Package org.globus.workspace.xen

Source Code of org.globus.workspace.xen.XenUtil

/*
* Copyright 1999-2008 University of Chicago
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package org.globus.workspace.xen;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.globus.workspace.Lager;
import org.globus.workspace.RepoFileSystemAdaptor;
import org.globus.workspace.ReturnException;
import org.globus.workspace.WorkspaceConstants;
import org.globus.workspace.WorkspaceException;
import org.globus.workspace.WorkspaceUtil;
import org.globus.workspace.cmdutils.SSHUtil;
import org.globus.workspace.service.binding.vm.VirtualMachine;
import org.globus.workspace.service.binding.vm.VirtualMachineDeployment;
import org.globus.workspace.service.binding.vm.VirtualMachinePartition;
import org.globus.workspace.service.binding.vm.FileCopyNeed;

import org.nimbustools.api.repr.vm.NIC;

import java.util.ArrayList;
import java.util.Iterator;

public class XenUtil implements WorkspaceConstants {

    public static final String XEN_NAME_PREFIX = "wrksp-";

    private static final Log logger =
        LogFactory.getLog(XenUtil.class.getName());

    private static final String NO_WRKSP =
            "worksp executable path (for compute node) is not configured";

    private static final String ERR_1 =
            "Problem with RM framework or finding executables";

    private static final String ERR_2 =
            "Problem with parameters to workspace driver, incorrectly " +
                    "supplied or validation of request failed";

    private static final String ERR_3 =
            "Problem with workspace driver, error executing request " +
                    "operation (but validation succeeded)";

    private static final String ERR_9 =
            "Problem with workspace driver, executing request succeed " +
                    "but something wrong with backend driver after success";

    private static final String ERR_OTHER= "Unexpected issue";

    // should be more private and encapsulated, see notes in Binding
    // should also be checks that none of the contents already contain
    // the markers
    public static final String WC_FIELD_SEPARATOR = ";";
    public static final String WC_GROUP_SEPARATOR = ";;";

    /* The path on the compute or local node to workspace_control */
    private static String worksp;
    private static RepoFileSystemAdaptor nsTrans;


    public static void setWorksp(String path) {
        if (worksp != null) {
            return;
        }
        worksp = path;
    }

    public static void setRepoAdaptor(RepoFileSystemAdaptor nsT) {
        if (nsTrans != null) {
            return;
        }
        nsTrans = nsT;
    }

    public static RepoFileSystemAdaptor getNsTrans() {
        return nsTrans;
    }

    public static ArrayList constructRemoveCommand(VirtualMachine vw,
                                                   boolean trash)
            throws WorkspaceException {

        if (vw == null) {
            final String err = "vw is null";
            logger.error(err);
            throw new IllegalArgumentException(err);
        }

        if (worksp == null) {
            logger.error(NO_WRKSP);
            throw new WorkspaceException(NO_WRKSP);
        }

        final ArrayList cmd = new ArrayList(8);

        /* The python program can have teardown tasks associated with it
           or those can be overriden here if they can't be predetermined
           or if it is not convenient to predetermine them. */

        cmd.add(worksp);
        cmd.add("--remove");

        if (trash) {
            cmd.add("--deleteall");
        }

        cmd.add("--name");
        cmd.add(xenName(vw));

        if (logger.isDebugEnabled()) {
            cmd.add("--loglevel");
            cmd.add("DEBUG");
        }

        return cmd;
    }

    public static ArrayList constructPropagateCommand(VirtualMachine vm,
                                                      String notificationInfo)
            throws WorkspaceException {

        if (vm == null) {
            final String err = "vm is null";
            logger.error(err);
            throw new IllegalArgumentException(err);
        }

        if (worksp == null) {
            logger.error(NO_WRKSP);
            throw new WorkspaceException(NO_WRKSP);
        }

        final ArrayList cmd = new ArrayList(16);

        cmd.add(worksp);
        cmd.add("--propagate");

        cmd.add("--name");
        cmd.add(xenName(vm));

        // For right now, only supporting propagate for one image, the rootdisk.
        // Waiting on generalization of disk and propagation (both in WSDL and
        // file movement tools)
        final VirtualMachinePartition[] partitions = vm.getPartitions();
        if (partitions != null) {
            String md5sum = null;
            cmd.add("--images");
            for (int i = 0; i < partitions.length; i++) {
                if (partitions[i].isRootdisk()) {
                    String img = partitions[i].getImage();
                    if(nsTrans != null) {
                        md5sum = nsTrans.getTranslatedChecksum(img);
                        img = nsTrans.translateExternaltoInternal(img, vm);                       
                    }
                    cmd.add("'"+img+"'");
                    break;
                }
            }
            if(partitions.length == 1 && md5sum != null)
            {
                cmd.add("--cachecksum");
                cmd.add(md5sum);
            }
        }    

        if (notificationInfo != null) {
            cmd.add("--notify");
            cmd.add(notificationInfo);
        }

        return cmd;
    }

    public static ArrayList constructUnpropagateCommand(VirtualMachine vm,
                                                       String notificationInfo)
            throws WorkspaceException {

        if (vm == null) {
            final String err = "vm is null";
            logger.error(err);
            throw new IllegalArgumentException(err);
        }
                                                            
        if (worksp == null) {
            logger.error(NO_WRKSP);
            throw new WorkspaceException(NO_WRKSP);
        }

        final ArrayList cmd = new ArrayList(16);

        cmd.add(worksp);
        cmd.add("--unpropagate");

        cmd.add("--name");
        cmd.add(xenName(vm));

        // source is the new target: for read-only images, use file://
        // and a local or local-shared filesystem (and therefore no
        // propagation) or also use the requested shutdown state of
        // Shutdown-Trash (which would propagate the image but when
        // you're done, trash any changes)

        // alternate propagation target may be supplied now
        String altTargets = null;

        // for right now, only supporting propagate for one image, the rootdisk
        final VirtualMachinePartition[] partitions = vm.getPartitions();
        if (partitions != null) {
            cmd.add("--images");
            for (int i = 0; i < partitions.length; i++) {
                if (partitions[i].isRootdisk()) {
                    String img = partitions[i].getImage();
                    if(nsTrans != null) {
                        img = nsTrans.translateExternaltoInternal(img, vm);
                    }
                    cmd.add("'"+img+"'");
                    altTargets = partitions[i].getAlternateUnpropTarget();
                    break;
                }
            }
        }

        if (altTargets != null) {
            cmd.add("--unproptargets");
            String img = altTargets;
            if(nsTrans != null) {
                img = nsTrans.translateExternaltoInternal(altTargets, vm);
            }
            cmd.add("'"+img+"'");
        }

        if (notificationInfo != null) {
            cmd.add("--notify");
            cmd.add(notificationInfo);
        }

        final String credentialName = vm.getCredentialName();
        if (credentialName != null) {

            cmd.add("--prop-extra-args");
            cmd.add("'credential=" + credentialName + "'");
        }

        return cmd;
    }

    public static ArrayList constructCreateCommand(VirtualMachine vw,
                                                   boolean startpaused)
            throws WorkspaceException {

        return constructCreateCommand(vw, startpaused, null);
    }


    private static String convertToAlreadyPropagated(String name, VirtualMachine vm)
            throws WorkspaceException {

        String img = name;
        if(nsTrans != null) {
            img = nsTrans.translateExternaltoInternal(img, vm);
        }
        int ndx = img.lastIndexOf('/');

        if(ndx > 0)
        {
            img = img.substring(ndx+1);
        }
        return "file://" + img;
    }

    public static ArrayList constructCreateCommand(VirtualMachine vm,
                                                   boolean startpaused,
                                                   String notificationInfo)
            throws WorkspaceException {

        if (vm == null) {
            final String err = "vm is null";
            logger.error(err);
            throw new IllegalArgumentException(err);
        }

        // not possible, Home initializes
        if (worksp == null) {
            logger.error(NO_WRKSP);
            throw new WorkspaceException(NO_WRKSP);
        }

        final ArrayList cmd = new ArrayList(16);

        cmd.add(worksp);
        cmd.add("--create");

        if (startpaused) {
            cmd.add("--startpaused");
        }

        cmd.add("--name");
        cmd.add(xenName(vm));

        if (vm.getDeployment() != null) {

            final VirtualMachineDeployment dep = vm.getDeployment();

            // the service does not currently support a default memory
            // config, but workspace_control does -- in the future,
            // decision to allow a default memory config will be policy
            // driven at service level
            if (dep.getIndividualPhysicalMemory() > 0) {
                cmd.add("--memory");
                cmd.add(Integer.toString(dep.getIndividualPhysicalMemory()));
            }

            if (dep.getIndividualCPUCount() > 0) {
                cmd.add("--vcpus");
                cmd.add(Integer.toString(dep.getIndividualCPUCount()));
            }
        }

        if (vm.getKernel() != null) {
            cmd.add("--kernel");
            cmd.add(vm.getKernel());
        }

        if (vm.getKernelParameters() != null) {
            cmd.add("--kernelargs");
            cmd.add(vm.getKernelParameters());
        }

        if (vm.getNetwork() != null) {
            cmd.add("--networking");
            final String net = "'" + hackStatic(vm.getNetwork()) + "'";
            cmd.add(net);
        }

        // sources:
        VirtualMachinePartition rootdisk = null;
        final ArrayList regularPartitions = new ArrayList();
        final ArrayList blankPartitions = new ArrayList();

        // results to send:
        final ArrayList images = new ArrayList();
        final ArrayList imagemounts = new ArrayList();

        final VirtualMachinePartition[] partitions = vm.getPartitions();

        if (partitions == null || partitions.length == 0) {
            final String err = "should be at least one partition, Binding " +
                    "should have caught at the outset";
            logger.error(err);
            throw new WorkspaceException(err);
        } else {
            for (int i = 0; i < partitions.length; i++) {
                if (partitions[i].isRootdisk()) {
                    rootdisk = partitions[i];
                } else if (partitions[i].getBlankspace() > 0) {
                    blankPartitions.add(partitions[i]);
                } else {
                    regularPartitions.add(partitions[i]);
                }
            }
        }


        // todo: generalize when propagating more than just rootdisk
        if (rootdisk != null) {
           
            String rootImageURI = rootdisk.getImage();

            // We know that if Propagate was required and notificationInfo
            // is null that this is a create command following a successful
            // Propagate-only command, so we let the backend know it can
            // find the file in its workspace-specific secureimage directory
            // by setting this file URL to a relative path -- relative paths
            // hitting the backend always cause the workspace-specific
            // secureimage directory to be consulted first

            if (vm.isPropagateRequired() && notificationInfo == null) {
                final String newURI = convertToAlreadyPropagated(rootImageURI, vm);

                logger.debug("turned '" + rootImageURI + "' into '" +
                            newURI + "' because file was already propagated");

                // not handling readonly root partition yet
                images.add(newURI);
            } else {
                // not handling readonly root partition yet
                images.add(rootImageURI);
            }
            imagemounts.add(rootdisk.getImagemount());
        }

        if (!blankPartitions.isEmpty()) {
            int blankNum = 0;
            final Iterator iter = blankPartitions.iterator();

            while (iter.hasNext()) {
                final VirtualMachinePartition blank =
                                (VirtualMachinePartition) iter.next();
                final int megs = blank.getBlankspace();
                //When unpropagate support is added for blank partitions,
                // this file will likely be unpropagated to the image node
                // with the originally supplied filename as target -- and
                // perhaps some schema change will allow the user to specify
                // whether or not it should be saved at all (when serializing
                // it would have to be)
                images.add("blankcreate://blankpartition" + blankNum
                                                            + "-size-" + megs);
                imagemounts.add(blank.getImagemount());
                blankNum += 1;

                // (assuming blank partition will always be readwrite)
            }
        }
       
        if (!regularPartitions.isEmpty()) {
            final Iterator iter = regularPartitions.iterator();
            while (iter.hasNext()) {
                final VirtualMachinePartition regular =
                                (VirtualMachinePartition) iter.next();
                String imgStr = regular.getImage();
                if (!regular.isReadwrite()) {
                    imgStr += WC_FIELD_SEPARATOR + "ro";
                }
                images.add(imgStr);
                imagemounts.add(regular.getImagemount());
            }
        }

        if (images.isEmpty()) {
            final String err = "should be at least one image here...";
            logger.error(err);
            throw new WorkspaceException(err);
        }
        Iterator iter = images.iterator();
        String imageString = "";

        imageString += (String) iter.next();

        while (iter.hasNext()) {
            imageString += WC_GROUP_SEPARATOR;
            imageString += (String) iter.next();
        }

        cmd.add("--images");
        cmd.add("'" + imageString + "'");


        if (imagemounts.isEmpty()) {
            final String err = "should be at least one image and hence at least " +
                    "one imagemount string here...";
            logger.error(err);
            throw new WorkspaceException(err);
        }
        iter = imagemounts.iterator();
        String imagemountString = "";

        imagemountString += (String) iter.next();

        while (iter.hasNext()) {
            imagemountString += WC_GROUP_SEPARATOR;
            imagemountString += (String) iter.next();
        }

        cmd.add("--imagemounts");
        cmd.add("'" + imagemountString + "'");

        if (notificationInfo != null) {
            cmd.add("--notify");                                          
            cmd.add(notificationInfo);
        }

        final FileCopyNeed[] needs = vm.getFileCopyNeeds();
        if (needs != null) {

            if (!vm.isFileCopyAllDone()) {
               
                boolean oneBeingSentToImage = false;
                final StringBuffer tasks = new StringBuffer("'");
                for (int i = 0; i < needs.length; i++) {

                    // Note that we don't copy needs with no destination path
                    // these are filecopies that are used at propagation time
                    if (!needs[i].onImage() && needs[i].destPath != null) {

                        if (oneBeingSentToImage) {
                            tasks.append(WC_GROUP_SEPARATOR);
                        }

                        oneBeingSentToImage = true;

                        tasks.append(needs[i].sourcePath)
                             .append(WC_FIELD_SEPARATOR)
                             .append(needs[i].destPath);

                        logger.debug(Lager.id(vm.getID()) +
                                    ": customization task '" +
                                    needs[i].sourcePath + "' --> '" +
                                    needs[i].destPath + "'");
                    }
                }

                tasks.append("'");

                if (oneBeingSentToImage) {
                    cmd.add("--mnttasks");
                    cmd.add(tasks.toString());
                }
            }
        }

        if (logger.isDebugEnabled()) {
            cmd.add("--loglevel");
            cmd.add("DEBUG");
        }
        return cmd;
    }

    public static ArrayList constructUnpauseCommand(VirtualMachine vw)
                                                 throws WorkspaceException {

        if (vw == null) {
            String err = "vw is null";
            logger.error(err);
            throw new IllegalArgumentException(err);
        }

        if (worksp == null) {
            logger.error(NO_WRKSP);
            throw new WorkspaceException(NO_WRKSP);
        }

        final ArrayList cmd = new ArrayList(8);

        cmd.add(worksp);
        cmd.add("--unpause");

        cmd.add("--name");
        cmd.add(xenName(vw));


        if (logger.isDebugEnabled()) {
            cmd.add("--loglevel");
            cmd.add("DEBUG");
        }

        return cmd;
    }


    public static ArrayList constructPauseCommand(VirtualMachine vw)
                                                 throws WorkspaceException {

        if (vw == null) {
            final String err = "vw is null";
            logger.error(err);
            throw new IllegalArgumentException(err);
        }

        // not possible, Home initializes
        if (worksp == null) {
            logger.error(NO_WRKSP);
            throw new WorkspaceException(NO_WRKSP);
        }

        final ArrayList cmd = new ArrayList(6);

        cmd.add(worksp);
        cmd.add("--pause");

        cmd.add("--name");
        cmd.add(xenName(vw));

        if (logger.isDebugEnabled()) {
            cmd.add("--loglevel");
            cmd.add("DEBUG");
        }

        return cmd;
    }

    public static ArrayList constructRebootCommand(VirtualMachine vw)
                                                 throws WorkspaceException {

        if (vw == null) {
            final String err = "vw is null";
            logger.error(err);
            throw new IllegalArgumentException(err);
        }

        // not possible, Home initializes
        if (worksp == null) {
            logger.error(NO_WRKSP);
            throw new WorkspaceException(NO_WRKSP);
        }

        final ArrayList cmd = new ArrayList(6);

        cmd.add(worksp);
        cmd.add("--reboot");

        cmd.add("--name");
        cmd.add(xenName(vw));

        if (logger.isDebugEnabled()) {
            cmd.add("--loglevel");
            cmd.add("DEBUG");
        }

        return cmd;
    }

    // TODO: in the future, make more things pluggable
    public static String xenName(VirtualMachine vw) {
        return XEN_NAME_PREFIX + vw.getID();
    }

    public static int xenNameToId(String name) {

        if (name == null) {
            return -1065;
        }

        final String cmp = name.trim();

        if (!cmp.startsWith(XEN_NAME_PREFIX)) {
            return -1066;
        }

        try {
            return Integer.parseInt(cmp.substring(XEN_NAME_PREFIX.length()));
        } catch (Throwable t) {
            return -1067;
        }
    }

    // sad
    public static String extractFirstIP(String net) {

        if (net == null) {
            return null;
        }

        logger.debug("received net = '" + net + "'");

        // bad code dup
       
        final String[] nicsStr = net.split(WC_GROUP_SEPARATOR);
        if (nicsStr.length == 0) {
            logger.debug("nicsStr.length == 0?");
            return null;
        }

        final String[] nicPropertiesStr = nicsStr[0].split(WC_FIELD_SEPARATOR);

        if (nicPropertiesStr.length < 6) {
            logger.fatal("nicPropertiesStr.length < 6?");
            return null;
        }

        return nicPropertiesStr[5];
    }


    public static WorkspaceException
                        translateReturnException(ReturnException e) {

        /* 1 is reserved for errors before reaching the workspace
           controller on the compute node.  Examples: if the srun/ssh
           program is not present, if it fails to talk to slurmctld,
           if slurmctld fails to talk to specified nodes, if slurmd
           cannot run worksp program, etc. */

        if (e.retval == 1) {
            return throwErr(ERR_1, e);
        }

        /* 2 is from workspace driver, wrong parameters or validation
           problem */

        if (e.retval == 2) {
            return throwErr(ERR_2, e);
        }

        /* 3 is from workspace driver, runtime problem.  Validation
           succeeded but something went wrong with execution of
           requested operation. */

        if (e.retval == 3) {
            return throwErr(ERR_3, e);
        }

        /* 9 is from workspace driver, problem with post-execution
           tasks, but too late to recover.  Client (us) must decide
           to invoke again to fix (for instance, if something post-create
           failed, it may be the policy to call destroy (this could be
           configurable)).  Just logging for now. */

        if (e.retval == 9) {
            // candidate for admin log/trigger of severe issues
            loge9Err(e);
            return null; // success still ...
        }

        /* anything else is uncategorized error */
        return throwErr(ERR_OTHER, e);
    }

    private static WorkspaceException
            throwErr(String baseErr, ReturnException e) {

        final String err;
        if (e.stderr != null) {
            err = baseErr + "\nSTDERR: " + e.stderr;
        } else {
            err = baseErr;
        }
        return new WorkspaceException(err, e.getCause());
    }

    private static void loge9Err(ReturnException e) {

        String err = ERR_9;
        if (e.stderr != null) {
            err += "\nSTDERR: " + e.stderr;
            if (e.stdout != null) {
                err += "\nSTDOUT: " + e.stdout;
            }
        } else if (e.stdout != null) {
            err += "\nSTDOUT: " + e.stdout;
        }
        logger.error(err);
    }

    // we'll be relieved of this nonsense when networking info
    // is handled better (which it now needs to be).  XenUtil should
    // take an object and convert it into necessary arguments.
    private static String hackStatic(String network) {
        String x = network.replaceAll(
                NIC.ACQUISITION_AllocateAndConfigure, "Static");
        x = x.replaceAll(NIC.ACQUISITION_AcceptAndConfigure, "Static");
        x = x.replaceAll(NIC.ACQUISITION_Advisory, "Independent");
        return x;
    }

    // todo: relieve need for loglevels
    public static void doFilePushLocalTarget(VirtualMachine vm,
                                             String localDirectory,
                                             String backendTargetDir,
                                             boolean fake,
                                             boolean eventLog,
                                             boolean traceLog) throws Exception {
        filePush(vm, localDirectory, backendTargetDir, fake, false, eventLog, traceLog);
    }

    // todo: relieve need for loglevels
    public static void doFilePushRemoteTarget(VirtualMachine vm,
                                              String localDirectory,
                                              String backendTargetDir,
                                              boolean fake,
                                              boolean eventLog,
                                              boolean traceLog) throws Exception {
        filePush(vm, localDirectory, backendTargetDir, fake, true, eventLog, traceLog);
    }

    private static void filePush(VirtualMachine vm,
                                 String localDirectory,
                                 String backendTargetDir,
                                 boolean fake,
                                 boolean remoteTarget,
                                 boolean eventLog,
                                 boolean traceLog) throws Exception {

        if (localDirectory == null) {
            throw new Exception("localDirectory needed but missing");
        }
        if (backendTargetDir == null) {
            throw new Exception("backendTargetDir needed but missing");
        }

        final FileCopyNeed[] needs = vm.getFileCopyNeeds();
        if (needs == null || needs.length == 0) {
            logger.warn("file push: nothing to do?");
            return;
        }

        final ArrayList cmd;
        if (remoteTarget) {
            cmd = SSHUtil.constructScpCommandPrefix();
        } else {
            cmd = new ArrayList(needs.length + 3);
            cmd.add("cp"); // hardcoded... TODO
            cmd.add("-p");
        }

        for (int i = 0; i < needs.length; i++) {
            // TODO: clean up
            final String path = localDirectory + "/" + needs[i].sourcePath;
            cmd.add(path);
        }

        if (remoteTarget) {
            cmd.addAll(SSHUtil.constructScpCommandSuffix(
                                            vm.getNode(), backendTargetDir));
        } else {
            cmd.add(backendTargetDir);
        }

        final String[] send = (String[]) cmd.toArray(new String[cmd.size()]);

        if (fake) {
            logger.debug("Would have run this for file push: " +
                    WorkspaceUtil.printCmd(send));
        } else {
            WorkspaceUtil.runCommand(send, eventLog, traceLog, vm.getID().intValue());
        }
    }
}
TOP

Related Classes of org.globus.workspace.xen.XenUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.