Package org.globus.workspace.cloud.meta.client

Source Code of org.globus.workspace.cloud.meta.client.CloudMetaClient

/*
* 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.cloud.meta.client;

import org.globus.workspace.common.print.Print;
import org.globus.workspace.common.print.PrintOpts;
import org.globus.workspace.common.client.CLIUtils;
import org.globus.workspace.common.client.CommonPrint;
import org.globus.workspace.client_core.ParameterProblem;
import org.globus.workspace.client_core.ExecutionProblem;
import org.globus.workspace.client_core.ExitNow;
import org.globus.workspace.client_core.utils.StringUtils;
import org.globus.workspace.client_common.BaseClient;
import org.globus.workspace.cloud.client.cluster.ClusterUtil;
import org.globus.workspace.cloud.client.cluster.ClusterMember;
import org.globus.workspace.cloud.client.util.ExecuteUtil;
import org.globus.workspace.cloud.client.util.CloudClientUtil;
import org.globus.workspace.cloud.client.CloudClient;
import org.globus.workspace.cloud.client.Props;
import org.globus.wsrf.encoding.DeserializationException;
import org.nimbustools.ctxbroker.generated.gt4_0.description.Clouddeployment_Type;
import org.nimbustools.ctxbroker.generated.gt4_0.description.Clouddeploy_Type;
import org.nimbustools.ctxbroker.generated.gt4_0.description.Cloudcluster_Type;
import org.nimbustools.ctxbroker.generated.gt4_0.description.Cloudworkspace_Type;
import org.nimbustools.messaging.gt4_0.common.CommonUtil;

import java.io.IOException;
import java.io.PrintStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class CloudMetaClient {

    private AllArgs args;
    private HashMap<String, CloudDeployment> cloudMap;
    private Cloudcluster_Type cluster;
    private ArrayList<Cloudworkspace_Type> workspaceList;
    private boolean needsBroker = false;


    private CloudManager cloudManager;
    private ExecuteUtil executeUtil = new ExecuteUtil();


    private final Print print;

    public Print getPrint() {
        return this.print;
    }


    public CloudMetaClient(Print pr) {
        if (pr == null) {
            throw new IllegalArgumentException("print may not be null");
        }
        this.print = pr;
        this.workspaceList = new ArrayList<Cloudworkspace_Type>();
        this.cloudMap = new LinkedHashMap<String, CloudDeployment>();

    }

    public static void main(String[] argv) {

        // keeping it simple for now, but basically following the model of CloudClient

        // look for debug early, for diagnosing problems with parsing etc.
        PrintStream debug = null;
        if (CLIUtils.containsDebug(argv)) {
            debug = System.err;
        }

        PrintOpts prOpts = new PrintOpts(CloudClient.getOptInPrCodes());

        final Print print = new Print(prOpts, System.out, System.err, debug);
        CloudMetaClient client = new CloudMetaClient(print);

        ParameterProblem parameterProblem = null;
        ExitNow exitNow = null;
        Throwable anyError = null;
        try {
            mainImpl(client, argv);
        } catch (ParameterProblem e) {
            anyError = e;
            parameterProblem = e;
        } catch (ExecutionProblem e) {
            anyError = e;
        } catch (ExitNow e) {
            exitNow = e;
        } catch (Throwable e) {
            anyError = e;
        }

        int exitCode;

        if (exitNow != null) {
            print.debugln("[exiting via exitnow system]");
            exitCode = exitNow.exitCode;

        } else if (anyError == null) {
            exitCode = BaseClient.SUCCESS_EXIT_CODE;
        } else {
            exitCode = BaseClient.COMMAND_LINE_EXIT_CODE;

            final String message =
                CommonUtil.genericExceptionMessageWrapper(anyError);

            String err = "Problem: " + message;

            if (parameterProblem != null && !print.useLogging()) {
                err += "\nSee help (-h).";
            }

            print.errln(err);

            print.debugln("\n");

            final String sectionTitle = "STACKTRACE";
            CommonPrint.printDebugSection(print, sectionTitle);

            anyError.printStackTrace(print.getDebugProxy());

            CommonPrint.printDebugSectionEnd(print, sectionTitle);

            print.debugln("\n");

            print.debugln("Stacktrace was from: " + anyError.getMessage());
        }

        print.flush();
        print.close();
        System.exit(exitCode);
    }

    static void mainImpl(CloudMetaClient client, String[] argv)
        throws ParameterProblem, ExecutionProblem, ExitNow {

        // (for development only, to attach a remote debugger etc)
        if (CLIUtils.containsDebuggerHang(argv)) {
            try {
                CLIUtils.hangForInput(client.getPrint());
            } catch (IOException e) {
                throw new ExecutionProblem("", e);
            }
        }

        CommonPrint.logArgs(argv, client.getPrint());

        AllArgs args = AllArgs.create(argv, client.getPrint());

        client.run(args);

    }

    public void run(AllArgs args)
        throws ParameterProblem, ExecutionProblem, ExitNow {

        if (args == null)
            throw new IllegalArgumentException("args cannot be null");

        this.args = args;

        this.handleParameters();

        final Set<AllArgs.Action> actions = this.args.getActions();

        try {

            if (actions.contains(AllArgs.Action.HELP)) {
                printHelp();
                return;
            }

            if (actions.contains(AllArgs.Action.RUN)) {
                doDeploy();
            }

        } finally {
            if (this.executeUtil != null) {
                this.executeUtil.stopExecutorService();
            }
        }

    }

    void handleParameters() throws ParameterProblem {

        Set<AllArgs.Action> actions = this.args.getActions();

        if (actions.isEmpty()) {
            throw new ParameterProblem("At least one action must be specified.");
        }

        if (actions.contains(AllArgs.Action.HELP)) {
            return;
        }

        handleCommonParameters();

        if (actions.contains(AllArgs.Action.RUN)) {
            handleRunParameters();
        }

    }

    void handleCommonParameters() throws ParameterProblem {

        String clouddirPath = this.args.getCloudConfDir();

        if (clouddirPath == null) {
            throw new ParameterProblem("You must specify a cloud configuration" +
                " directory with --"+Opts.CLOUD_DIR_OPT_STRING);
        }
        this.cloudManager = new CloudManager(clouddirPath);

        String historyDirectory = this.args.getHistoryDirectory();
         if (historyDirectory == null) {
            throw new ParameterProblem("You must specify a cloud history dir "+
                                       " with --"+Opts.HISTORY_DIR_OPT_STRING);
        }

        CloudClientUtil.verifyHistoryDir(historyDirectory, true, true);


    }

    void handleRunParameters() throws ParameterProblem {

        String clusterPath = this.args.getClusterPath();
        String deployPath = this.args.getDeployPath();

        String sshFile = this.args.getSshfile();
        String brokerUrl = this.args.getBrokerURL();
        String brokerId = this.args.getBrokerID();
        int duration = this.args.getDurationMinutes();
        int pollMs = this.args.getPollMs();


        if (clusterPath == null) {
            throw new ParameterProblem("You must specify a cluster " +
                "document with --" + Opts.CLUSTER_OPT_STRING);
        }

        this.cluster = ClusterUtil.getCluster(clusterPath, this.print);

        Cloudworkspace_Type[] workspaces = this.cluster.getWorkspace();
        if (workspaces == null || workspaces.length == 0) {
            throw new ParameterProblem("The cluster document must contain "+
                "at least one workspace");
        }

        for (Cloudworkspace_Type ws : workspaces) {

            final Clouddeploy_Type[] deploys = ws.getDeploy();
            if (deploys != null && deploys.length > 0) {
                // we may want to enable this functionality in the future
                // but let's keep things simple for now
                throw new ParameterProblem("Your cluster document includes <deploy> " +
                    "elements, which are not allowed at this time.");
            }

            String name = ws.getName();
            if (name == null || name.trim().length() == 0) {
                throw new ParameterProblem("Every workspace must have a unique "+
                    "name");
            }
            name = name.trim();

            for (Cloudworkspace_Type existingWs : this.workspaceList) {
                String existingWsName = existingWs.getName().trim();

                if (existingWsName.equals(name)) {
                    throw new ParameterProblem("Every workspace must have a " +
                        "unique name");
                }
            }

            this.workspaceList.add(ws);
        }

        if (deployPath == null) {
            throw new ParameterProblem("You must specify a deployment document " +
                "using the --"+Opts.DEPLOY_OPT_STRING+" option");
        }

        final Map<String, Clouddeploy_Type[]> deployMap;

        try {
            final Clouddeployment_Type deployDoc =
                ClusterUtil.parseDeployDocument(deployPath);
            deployMap = ClusterUtil.parseDeployment(deployDoc);

        } catch (DeserializationException de) {
            throw new ParameterProblem("Failed to parse deployment " +
                "document: " + de.getMessage());
        } catch (IOException ie) {
            throw new ParameterProblem("Failed to read deployment "+
                "document: "+ ie.getMessage());
        }

        handleDeploymentMap(deployMap);

        if (this.needsBroker) {
            if (brokerUrl == null || brokerId == null) {
                throw new ParameterProblem("You must specify a valid Context " +
                    "Broker URL and identity string in your properties file ("+
                    this.args.getPropertiesPath()+") keys: "+
                    Props.KEY_BROKER_URL+" and " + Props.KEY_BROKER_IDENTITY
                );
            }
        }

        if (sshFile == null) {
            this.print.info("\nWarning: a SSH public key was not specified. " +
                "It will not be installed into cluster.");
        }

        if (duration <= 0) {
            throw new ParameterProblem("Please specify a valid duration (--"+
                Opts.HOURS_OPT_STRING+")");
        }

        if (pollMs <= 0) {
            throw new ParameterProblem("Please specify a valid polling " +
                "frequency in the properties file ("+
                this.args.getPropertiesPath()+")");
        }

    }

    void handleDeploymentMap(Map<String, Clouddeploy_Type[]> deployMap)
        throws ParameterProblem {

        for (Map.Entry<String,Clouddeploy_Type[]> entry : deployMap.entrySet()) {

            final String workspaceName = entry.getKey();
            int workspaceIndex = getWorkspaceIndex(workspaceName);
            if (workspaceIndex == -1) {
                throw new ParameterProblem("Deployment document contains "+
                    "a workspace: '"+ entry.getKey()+"' which is not present "+
                    "in the cluster definition");
            }

            final Cloudworkspace_Type workspace =
                this.cluster.getWorkspace(workspaceIndex);

            final short workspaceQuantity =
                workspace.getQuantity();

            short foundQuantity = 0;

            for (Clouddeploy_Type deploy : entry.getValue()) {

                String cloudName = deploy.getCloud();
                if (cloudName != null) {
                    cloudName = cloudName.trim();
                }
                if (cloudName == null || cloudName.length() == 0) {
                    throw new ParameterProblem("Invalid <cloud> name");
                }

                foundQuantity += deploy.getQuantity();

                CloudDeployment cloud = getDeploymentByName(cloudName);

                final String localNicPrefix =
                    cloud.getCloud().getBrokerLocalNicPrefix();

                final String publicNicPrefix =
                    cloud.getCloud().getBrokerPublicNicPrefix();

                ClusterMember member = ClusterUtil.parseRequest(this.cluster,
                    workspaceIndex, this.print, localNicPrefix, publicNicPrefix);

                if (member.getClusterForUserData() != null) {
                    needsBroker = true;
                }

                final MemberDeployment md = new MemberDeployment(member, deploy);
                cloud.addMember(md);
            }

            if (foundQuantity != workspaceQuantity) {
                throw new ParameterProblem("The workspace '"+workspaceName+
                    "' has a quantity of "+workspaceQuantity+" but the total "+
                    "quantity of all deployments of this workspace is "+
                    foundQuantity);
            }
        }

        // we already know that every deployment workspace is a valid
        // ClusterMember, so if the sizes match we can be sure that every
        // ClusterMember is accounted for
        if (deployMap.size() != this.workspaceList.size()) {
            throw new ParameterProblem("There must be a deployment entry "+
                "for each defined workspace.");
        }


    }

    private int getWorkspaceIndex(String key) {
        for (int i = 0; i < workspaceList.size(); i++) {
            Cloudworkspace_Type ws = workspaceList.get(i);
            if (ws.getName().trim().equals(key)) {
                return i;
            }
        }
        return -1;
    }

    private synchronized CloudDeployment getDeploymentByName(String name)
        throws ParameterProblem {
        CloudDeployment cloud = this.cloudMap.get(name);
        if (cloud == null) {
            cloud = new CloudDeployment(this.cloudManager.getCloudByName(name));
            this.cloudMap.put(name, cloud);
        }
        return cloud;
    }

    private void doDeploy() throws ExecutionProblem, ExitNow {

        printDeploymentInfo();

        executeUtil.startMultiCloudCluster(
            this.cloudMap.values(),
            this.args.getHistoryDirectory(),
            this.args.getPollMs(),
            this.print,
            this.args.getBrokerURL(),
            this.args.getBrokerID(),
            this.args.getSshfile(),
            this.args.getDurationMinutes()
        );

    }

    private void printDeploymentInfo() {
        if (this.cloudMap.size() == 1) {
            this.print.infoln("\nRequesting single cloud cluster:");
        } else {
            this.print.infoln("\nRequesting multi cloud cluster:");
        }

        for (CloudDeployment cloud : this.cloudMap.values()) {
            this.print.infoln("Cloud '"+cloud.getCloud().getName()+"'");

            for (MemberDeployment member : cloud.getMembers()) {
                String inststr = " instance";
                if (member.getInstanceCount() > 1) {
                    inststr += "s";
                }

                this.print.infoln("  - "+member.getMember().getPrintName()+
                    ": image '"+member.getImageName()+"', "+
                    member.getInstanceCount() +inststr);
            }
        }
    }


    private void printHelp() throws ExecutionProblem {


        String help = null;
        try {
            help = getHelpString();
        } catch (IOException e) {
            throw new ExecutionProblem("Failed to get help string", e);
        }

        this.print.infoln(help);

    }

    private String getHelpString() throws IOException {
        InputStream is = null;
        String help = "";
        try {
            is = this.getClass().getResourceAsStream("meta-cloud-help.txt");
            help = StringUtils.getTextFileViaInputStream(is);
        } finally {
            if (is != null) {
                is.close();
            }
        }
        return help;
    }


}
TOP

Related Classes of org.globus.workspace.cloud.meta.client.CloudMetaClient

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.