Package org.apache.ace.nodelauncher.amazon

Source Code of org.apache.ace.nodelauncher.amazon.AmazonNodeLauncher

/*
* 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.
*/
package org.apache.ace.nodelauncher.amazon;

import org.apache.ace.nodelauncher.NodeLauncher;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.ec2.reference.EC2Constants;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

import static org.jclouds.compute.predicates.NodePredicates.runningInGroup;

/**
* Simple NodeLauncher implementation that launches nodes based on a given AMI in Amazon EC2.
* We expect the AMI we launch to have a java on its path, at least after bootstrap.<br><br>
*
* This service is configured using Config Admin; see the constants in the class for more information
* about this.<br><br>
*
* After the node has been started up, this service will install a management agent on it. For this
* to work, there should be an ace-launcher in the OBR of the server the node should connect to.
*/
public class AmazonNodeLauncher implements NodeLauncher, ManagedService {
    public static final String PID = "org.apache.ace.nodelauncher.amazon";

    /**
     * Configuration key: The ACE server the newly started nodes should connect to.
     */
    public static final String SERVER = "server";

    /**
     * Configuration key: The ID of the AMI to use. Note that this AMI should be available
     * in the location ("availability zone") you configure.
     */
    public static final String AMI_ID = "amiId";

    /**
     * Configuration key: The location where the node should be started; this is an Amazon "availability zone",
     * something like "eu-west-1".
     */
    public static final String LOCATION = "location";

    /**
     * Configuration key: the Amazon access key ID.
     */
    public static final String ACCESS_KEY_ID = "accessKeyid";

    /**
     * Configuration key: The secret key that goes with your access key.
     */
    public static final String SECRET_ACCESS_KEY = "secretAccessKey";

    /**
     * Configuration key: A prefix to use for all nodes launched by this service. You can use this (a) allow
     * multiple nodes with the same ID, but launcher from different NodeLauncher services, or (b) to more
     * easily identify your nodes in the AWS management console.
     */
    public static final String TAG_PREFIX = "tagPrefix";

    /**
     * Configuration key: A piece of shell script that is run <em>before</em> the management agent is started.
     */
    public static final String NODE_BOOTSTRAP = "nodeBootstrap";

    /**
     * Configuration key: A set of VM options to pass to the JVM when starting the management agent, as a single string.
     */
    public static final String VM_OPTIONS = "vmOptions";

    /**
     * Configuration key: Any command line arguments you want to pass to the launcher; see the ace-launcher for
     * the possible options.
     */
    public static final String LAUNCHER_ARGUMENTS = "launcherArguments";
   
    /**
     * Configuration key: Extra ports to open on the nodes, besides the default ones (see DEFAULT_PORTS).
     */
    public static final String EXTRA_PORTS = "extraPorts";
   
    /**
     * Configuration key: Should we run the process as root?
     */
    public static final String RUN_AS_ROOT = "runAsRoot";

    /**
     * Default set of ports to open on a node.
     */
    public static final int[] DEFAULT_PORTS = new int[] {22, 80, 8080};
   
    private URL m_server;
    private String m_amiId;
    private String m_location;
    private String m_accessKeyId;
    private String m_secretAccessKey;
    private String m_tagPrefix;
    private String m_vmOptions;
    private String m_nodeBootstrap;
    private String m_launcherArguments;
    private String m_extraPorts;
    private boolean m_runAsRoot;

    private ComputeServiceContext m_computeServiceContext;
   
    public void start() {
        Properties props = new Properties();
        props.put(EC2Constants.PROPERTY_EC2_AMI_OWNERS, "");
        m_computeServiceContext = new ComputeServiceContextFactory().createContext("aws-ec2",
                m_accessKeyId, m_secretAccessKey, (List) Arrays.asList(new JschSshClientModule()), props);
    }

    public void start(String id) throws Exception {
        ComputeService computeService = m_computeServiceContext.getComputeService();
        Template template = computeService.templateBuilder()
                .imageId(m_location + "/" + m_amiId)
                .hardwareId(InstanceType.C1_MEDIUM)
                .locationId(m_location)
                .build();
       
        int[] extraPorts = parseExtraPorts(m_extraPorts);
        int[] inboundPorts = mergePorts(DEFAULT_PORTS, extraPorts);
        template.getOptions().as(EC2TemplateOptions.class).inboundPorts(inboundPorts);
        template.getOptions().blockOnComplete(false);
        template.getOptions().runAsRoot(m_runAsRoot);

        Set<? extends NodeMetadata> tag = computeService.createNodesInGroup(m_tagPrefix + id, 1, template);
        System.out.println("In case you need it, this is the key to ssh to " + id + ":\n"
                + tag.iterator().next().getCredentials().credential);
        computeService.runScriptOnNodesMatching(runningInGroup(m_tagPrefix + id),
                Statements.exec(buildStartupScript(id)),
                RunScriptOptions.Builder.blockOnComplete(false));
    }
   
    int[] mergePorts(int[] first, int[] last) {
        int[] result = new int[first.length + last.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = (i < first.length) ? first[i] : last[i - first.length];
        }
        return result;
    }
   
    int[] parseExtraPorts(String extraPorts) {
        extraPorts = extraPorts.trim();
        if (extraPorts.isEmpty()) {
            return new int[] {};
        }
        String[] ports = extraPorts.split(",");
        int[] result = new int[ports.length];
        for (int i = 0; i < ports.length; i++) {
            result[i] = Integer.parseInt(ports[i].trim());
        }
        return result;
    }

    private String buildStartupScript(String id) throws MalformedURLException {
        StringBuilder script = new StringBuilder();
        if (m_nodeBootstrap != null) {
            script.append(m_nodeBootstrap).append(" ; ");
        }
        script.append("wget ").append(new URL(m_server, "/obr/ace-launcher.jar")).append(" ;");

        script.append("nohup java -jar ace-launcher.jar ");
        script.append("discovery=").append(m_server.toExternalForm()).append(" ");
        script.append("identification=").append(id).append(" ");
        script.append(m_vmOptions).append(" ");
        script.append(m_launcherArguments);
        return script.toString();
    }

    public void stop(String id) {
        m_computeServiceContext.getComputeService().destroyNodesMatching(runningInGroup(m_tagPrefix + id));
    }
   
    public Properties getProperties(String id) throws Exception {
        Properties result = new Properties();
       
        NodeMetadata nodeMetadata = getNodeMetadataForRunningNodeWithTag(m_tagPrefix + id);
        if (nodeMetadata == null) {
            return null;
        }
        result.put("id", id);
        result.put("node-id", nodeMetadata.getId());
        result.put("ip", nodeMetadata.getPublicAddresses().iterator().next());
       
        return result;
    }

    private NodeMetadata getNodeMetadataForRunningNodeWithTag(String tag) {
        for (ComputeMetadata node : m_computeServiceContext.getComputeService().listNodes()) {
            NodeMetadata candidate = m_computeServiceContext.getComputeService().getNodeMetadata(node.getId());
            if (tag.equals(candidate.getGroup()) && candidate.getState().equals(NodeState.RUNNING)) {
                return candidate;
            }
        }
        return null;
    }

    public void updated(@SuppressWarnings("rawtypes") Dictionary properties) throws ConfigurationException {
        if (properties != null) {
            URL server;
            try {
                server = new URL(getConfigProperty(properties, SERVER));
            }
            catch (MalformedURLException e) {
                throw new ConfigurationException(SERVER, getConfigProperty(properties, SERVER) + " is not a valid URL.", e);
            }
            String amiId = getConfigProperty(properties, AMI_ID);
            String location = getConfigProperty(properties, LOCATION);
            String accessKeyId = getConfigProperty(properties, ACCESS_KEY_ID);
            String secretAccessKey = getConfigProperty(properties, SECRET_ACCESS_KEY);

            String vmOptions = getConfigProperty(properties, VM_OPTIONS, "");
            String nodeBootstrap = getConfigProperty(properties, NODE_BOOTSTRAP, "");
            String tagPrefix = getConfigProperty(properties, TAG_PREFIX, "");
            String launcherArguments = getConfigProperty(properties, LAUNCHER_ARGUMENTS, "");
            String extraPorts = getConfigProperty(properties, EXTRA_PORTS, "");
            String runAsRoot = getConfigProperty(properties, RUN_AS_ROOT, "false");

            m_server = server;
            m_amiId = amiId;
            m_location = location;
            m_accessKeyId = accessKeyId;
            m_secretAccessKey = secretAccessKey;
            m_tagPrefix = tagPrefix;
            m_vmOptions = vmOptions;
            m_nodeBootstrap = nodeBootstrap;
            m_launcherArguments = launcherArguments;
            m_extraPorts = extraPorts;
            m_runAsRoot = "true".equals(runAsRoot);
        }
    }

    private String getConfigProperty(@SuppressWarnings("rawtypes") Dictionary settings, String id)
            throws ConfigurationException {
        return getConfigProperty(settings, id, null);
    }

    private String getConfigProperty(@SuppressWarnings("rawtypes") Dictionary settings, String id, String defaultValue)
            throws ConfigurationException {
        String result = (String) settings.get(id);
        if (result == null) {
            if (defaultValue == null) {
            throw new ConfigurationException(id, "key missing");
            }
            else {
                return defaultValue;
            }
        }
        return result;
    }
}
TOP

Related Classes of org.apache.ace.nodelauncher.amazon.AmazonNodeLauncher

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.