MainApp.java Source code

Java tutorial

Introduction

Here is the source code for MainApp.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.contains;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_AMI_QUERY;
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_SCRIPT_COMPLETE;
import static org.jclouds.compute.options.TemplateOptions.Builder.overrideLoginCredentials;
import static org.jclouds.compute.options.TemplateOptions.Builder.overrideLoginUser;
import static org.jclouds.compute.options.TemplateOptions.Builder.runScript;
import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
import static org.jclouds.compute.predicates.NodePredicates.inGroup;
import static org.jclouds.scriptbuilder.domain.Statements.exec;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.jclouds.ContextBuilder;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.apis.Apis;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.RunScriptOnNodesException;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.enterprise.config.EnterpriseConfigurationModule;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.providers.Providers;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
import org.jclouds.sshj.config.SshjSshClientModule;

import com.google.common.base.Charsets;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.inject.Module;

import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.OsFamily;

import org.jclouds.vsphere.compute.options.VSphereTemplateOptions;
import org.jclouds.compute.options.TemplateOptions;

// for vsphere overloads
import java.util.Properties;
import static org.jclouds.vsphere.config.VSphereConstants.JCLOUDS_VSPHERE_VM_PASSWORD;

/**
 * Demonstrates the use of {@link ComputeService}.
 * <p/>
 * Usage is:
 * {@code java MainApp provider identity credential groupName (add|exec|run|destroy)}
 * if {@code exec} is used, the following parameter is a command, which should
 * be passed in quotes
 * if {@code run} is used, the following parameter is a file to execute.
 */
public class MainApp {

    public static enum Action {
        ADD, RUN, EXEC, DESTROY, LISTIMAGES, LISTNODES;
    }

    public static final Map<String, ApiMetadata> allApis = Maps
            .uniqueIndex(Apis.viewableAs(ComputeServiceContext.class), Apis.idFunction());

    public static final Map<String, ProviderMetadata> appProviders = Maps
            .uniqueIndex(Providers.viewableAs(ComputeServiceContext.class), Providers.idFunction());

    public static final Set<String> allKeys = ImmutableSet
            .copyOf(Iterables.concat(appProviders.keySet(), allApis.keySet()));

    public static int PARAMETERS = 5;
    public static String INVALID_SYNTAX = "Invalid number of parameters. Syntax is: provider identity credential groupName (add|exec|run|destroy)";

    public static void main(String[] args) {
        if (args.length < PARAMETERS)
            throw new IllegalArgumentException(INVALID_SYNTAX);

        String provider = args[0];
        String identity = args[1];
        String credential = args[2];
        String groupName = args[3];
        Action action = Action.valueOf(args[4].toUpperCase());
        boolean providerIsGCE = provider.equalsIgnoreCase("google-compute-engine");
        boolean providerIsVsphere = provider.equalsIgnoreCase("vsphere");

        if (action == Action.EXEC && args.length < PARAMETERS + 1)
            throw new IllegalArgumentException("please quote the command to exec as the last parameter");
        String command = (action == Action.EXEC) ? args[5] : "echo hello";

        // For GCE, the credential parameter is the path to the private key file
        if (providerIsGCE)
            credential = getPrivateKeyFromFile(credential);

        if (action == Action.RUN && args.length < PARAMETERS + 1)
            throw new IllegalArgumentException("please pass the local file to run as the last parameter");
        File file = null;
        if (action == Action.RUN) {
            file = new File(args[5]);
            if (!file.exists())
                throw new IllegalArgumentException("file must exist! " + file);
        }

        String minRam = System.getProperty("minRam");
        String loginUser = System.getProperty("loginUser", "toor");

        // note that you can check if a provider is present ahead of time
        checkArgument(contains(allKeys, provider), "provider %s not in supported list: %s", provider, allKeys);

        LoginCredentials login = (action != Action.DESTROY) ? getLoginForCommandExecution(action) : null;

        ComputeService compute = initComputeService(provider, identity, credential);

        try {
            switch (action) {
            case ADD:
                System.out.printf(">> adding node to group %s%n", groupName);

                // Default template chooses the smallest size on an operating system
                // that tested to work with java, which tends to be Ubuntu or CentOS
                TemplateBuilder templateBuilder = compute.templateBuilder();

                if (providerIsGCE)
                    templateBuilder.osFamily(OsFamily.CENTOS);

                // If you want to up the ram and leave everything default, you can 
                // just tweak minRam
                if (minRam != null)
                    templateBuilder.minRam(Integer.parseInt(minRam));

                // note this will create a user with the same name as you on the
                // node. ex. you can connect via ssh publicip
                Statement bootInstructions = AdminAccess.standard();

                // to run commands as root, we use the runScript option in the template.
                if (provider.equalsIgnoreCase("virtualbox"))
                    templateBuilder.options(overrideLoginUser(loginUser).runScript(bootInstructions));
                else
                    templateBuilder.options(runScript(bootInstructions));

                if (providerIsVsphere) {
                    TemplateOptions o = compute.templateOptions();
                    ((VSphereTemplateOptions) o).isoFileName("ISO/UCSInstall_UCOS_3.1.0.0-9914.iso");
                    ((VSphereTemplateOptions) o).flpFileName("ISO/image.flp");
                    ((VSphereTemplateOptions) o).postConfiguration(false);
                    o.tags(ImmutableSet.of("from UnitTest")).nodeNames(ImmutableSet.of("my-clone1"))
                            .runScript("cd /tmp; touch test.txt").networks("Dev Admin Network");
                    templateBuilder.imageId("first-vm12-from-template").locationId("default").minRam(6000)
                            .options(o);
                    System.out.printf("After ProviderIsVsphere option setting\n");
                }

                NodeMetadata node = getOnlyElement(
                        compute.createNodesInGroup(groupName, 1, templateBuilder.build()));
                System.out.printf("<< node %s: %s%n", node.getId(),
                        concat(node.getPrivateAddresses(), node.getPublicAddresses()));

            case EXEC:
                System.out.printf(">> running [%s] on group %s as %s%n", command, groupName, login.identity);

                // when you run commands, you can pass options to decide whether to
                // run it as root, supply or own credentials vs from cache, and wrap
                // in an init script vs directly invoke
                Map<? extends NodeMetadata, ExecResponse> responses = compute.runScriptOnNodesMatching(//
                        inGroup(groupName), // predicate used to select nodes
                        exec(command), // what you actually intend to run
                        overrideLoginCredentials(login) // use my local user &
                                // ssh key
                                .runAsRoot(false) // don't attempt to run as root (sudo)
                                .wrapInInitScript(false));// run command directly

                for (Entry<? extends NodeMetadata, ExecResponse> response : responses.entrySet()) {
                    System.out.printf("<< node %s: %s%n", response.getKey().getId(), concat(
                            response.getKey().getPrivateAddresses(), response.getKey().getPublicAddresses()));
                    System.out.printf("<<     %s%n", response.getValue());
                }
                break;
            case RUN:
                System.out.printf(">> running [%s] on group %s as %s%n", file, groupName, login.identity);

                // when running a sequence of commands, you probably want to have jclouds use the default behavior, 
                // which is to fork a background process.
                responses = compute.runScriptOnNodesMatching(//
                        inGroup(groupName), Files.toString(file, Charsets.UTF_8), // passing in a string with the contents of the file
                        overrideLoginCredentials(login).runAsRoot(false)
                                .nameTask("_" + file.getName().replaceAll("\\..*", ""))); // ensuring task name isn't
                // the same as the file so status checking works properly

                for (Entry<? extends NodeMetadata, ExecResponse> response : responses.entrySet()) {
                    System.out.printf("<< node %s: %s%n", response.getKey().getId(), concat(
                            response.getKey().getPrivateAddresses(), response.getKey().getPublicAddresses()));
                    System.out.printf("<<     %s%n", response.getValue());
                }
                break;
            case DESTROY:
                System.out.printf(">> destroying nodes in group %s%n", groupName);
                // you can use predicates to select which nodes you wish to destroy.
                Set<? extends NodeMetadata> destroyed = compute.destroyNodesMatching(//
                        Predicates.<NodeMetadata>and(not(TERMINATED), inGroup(groupName)));
                System.out.printf("<< destroyed nodes %s%n", destroyed);
                break;
            case LISTIMAGES:
                Set<? extends Image> images = compute.listImages();
                System.out.printf(">> No of images %d%n", images.size());
                for (Image img : images) {
                    System.out.println(">>>>  " + img);
                }
                break;
            case LISTNODES:
                Set<? extends ComputeMetadata> nodes = compute.listNodes();
                System.out.printf(">> No of nodes/instances %d%n", nodes.size());
                for (ComputeMetadata nodeData : nodes) {
                    System.out.println(">>>>  " + nodeData);
                }
                break;
            }
        } catch (RunNodesException e) {
            System.err.println("error adding node to group " + groupName + ": " + e.getMessage());
            error = 1;
        } catch (RunScriptOnNodesException e) {
            System.err.println("error executing " + command + " on group " + groupName + ": " + e.getMessage());
            error = 1;
        } catch (Exception e) {
            System.err.println("error: " + e.getMessage());
            error = 1;
        } finally {
            compute.getContext().close();
            System.exit(error);
        }
    }

    private static String getPrivateKeyFromFile(String filename) {
        try {
            return Files.toString(new File(filename), Charsets.UTF_8);
        } catch (IOException e) {
            System.err.println("Exception reading private key from '%s': " + filename);
            e.printStackTrace();
            System.exit(1);
            return null;
        }
    }

    static int error = 0;

    private static ComputeService initComputeService(String provider, String identity, String credential) {

        // example of specific properties, in this case optimizing image list to
        // only amazon supplied
        Properties properties = new Properties();
        properties.setProperty(PROPERTY_EC2_AMI_QUERY, "owner-id=137112412989;state=available;image-type=machine");
        properties.setProperty(PROPERTY_EC2_CC_AMI_QUERY, "");
        long scriptTimeout = TimeUnit.MILLISECONDS.convert(20, TimeUnit.MINUTES);
        properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, scriptTimeout + "");

        /*
              ComputeServiceContext context = ContextBuilder.newBuilder("vsphere")
          .credentials("root", "vmware")
          .endpoint("https://172.31.11.14/sdk")
          .modules(modules)
          .overrides(overrides)
          .buildView(ComputeServiceContext.class);
        */

        // example of injecting a ssh implementation
        Iterable<Module> modules = ImmutableSet.<Module>of(new SshjSshClientModule(), new SLF4JLoggingModule(),
                new EnterpriseConfigurationModule());

        ContextBuilder builder;
        if (provider.equalsIgnoreCase("vsphere")) {
            properties.setProperty(JCLOUDS_VSPHERE_VM_PASSWORD, "default"); // set vsphere vm root password

            builder = ContextBuilder.newBuilder(provider).credentials(identity, credential)
                    .endpoint("https://172.31.11.14/sdk").modules(modules).overrides(properties);
        } else {
            builder = ContextBuilder.newBuilder(provider).credentials(identity, credential).modules(modules)
                    .overrides(properties);
        }
        System.out.printf(">> initializing %s%n", builder.getApiMetadata());

        return builder.buildView(ComputeServiceContext.class).getComputeService();
    }

    private static LoginCredentials getLoginForCommandExecution(Action action) {
        try {
            String user = System.getProperty("user.name");
            String privateKey = Files.toString(new File(System.getProperty("user.home") + "/.ssh/id_rsa"), UTF_8);
            return LoginCredentials.builder().user(user).privateKey(privateKey).build();
        } catch (Exception e) {
            System.err.println("error reading ssh key " + e.getMessage());
            System.exit(1);
            return null;
        }
    }

}