com.tasktop.c2c.server.internal.cloud.hp.HPCloudService.java Source code

Java tutorial

Introduction

Here is the source code for com.tasktop.c2c.server.internal.cloud.hp.HPCloudService.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2014 Tasktop Technologies
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Tasktop Technologies - initial API and implementation
 ******************************************************************************/
package com.tasktop.c2c.server.internal.cloud.hp;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.jclouds.Constants;
import org.jclouds.ContextBuilder;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.domain.Address;
import org.jclouds.openstack.nova.v2_0.domain.Server;
import org.jclouds.openstack.nova.v2_0.domain.ServerCreated;
import org.jclouds.openstack.nova.v2_0.features.ServerApi;
import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.inject.Module;
import com.tasktop.c2c.server.cloud.domain.Node;
import com.tasktop.c2c.server.cloud.domain.Node.Status;
import com.tasktop.c2c.server.cloud.domain.Task;
import com.tasktop.c2c.server.cloud.service.CloudService;
import com.tasktop.c2c.server.cloud.service.Template;

/**
 * An implementation of CloudService using the JClouds library for use with the HP Cloud Service.
 * 
 * @author michaelnelson (Tasktop Technologies Inc.)
 * 
 */
public class HPCloudService implements CloudService {

    protected static final String OP_CREATE_SERVER = "create server";

    private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(HPCloudService.class);

    @Value("${alm.https.proxy.host}")
    private String proxyHost;

    @Value("${alm.https.proxy.port}")
    private String proxyPort;

    private HPCloudServicesConfiguration configuration;

    @Autowired
    private ContextBuilder contextBuilder;

    private interface ContextOperation<T> {
        public T perform(ComputeServiceContext context);
    }

    private abstract class JCloudGenericOperation<T> implements ContextOperation<T> {
        @Override
        public T perform(ComputeServiceContext context) {
            ComputeService computeService = context.getComputeService();
            return perform(computeService);
        }

        protected abstract T perform(ComputeService computeService);
    }

    private abstract class HPCloudSpecificOperation<T> implements ContextOperation<T> {
        @Override
        public T perform(ComputeServiceContext ctx) {
            NovaApi novaApi = contextBuilder.buildApi(NovaApi.class);
            return perform(novaApi);
        }

        protected abstract T perform(NovaApi novaApi);
    }

    /**
     * Wrap the performing of an operation with the building of a ComputeServiceContext, and close it afterwards.
     * 
     * @param operation
     * @return
     */
    private <T> T perform(ContextOperation<T> operation) {
        boolean proxyIsSet = (proxyHost != null && !proxyHost.isEmpty() && proxyPort != null
                && !proxyPort.isEmpty());
        if (proxyIsSet) {
            Properties overrides = new Properties();
            overrides.setProperty(Constants.PROPERTY_PROXY_HOST, proxyHost);
            overrides.setProperty(Constants.PROPERTY_PROXY_PORT, proxyPort);
            contextBuilder = contextBuilder.overrides(overrides);
        }

        ComputeServiceContext context = contextBuilder
                .credentials(configuration.getTenantName() + ":" + configuration.getUsername(),
                        configuration.getPassword())
                .modules(ImmutableSet.<Module>of(new SshjSshClientModule())).buildView(ComputeServiceContext.class);
        try {
            return operation.perform(context);
        } finally {
            context.close();
        }
    }

    @Override
    public List<Template> listTemplates() {
        return perform(new JCloudGenericOperation<List<Template>>() {

            @Override
            public List<Template> perform(ComputeService cs) {
                LOGGER.debug("Making call to list templates ...");
                Set<? extends Image> images = cs.listImages();
                ArrayList<Template> retList = new ArrayList<Template>();
                for (Image image : images) {
                    retList.add(convertImageToTemplate(image));
                }
                LOGGER.debug("Got templates: " + retList.size());
                return retList;
            }
        });
    }

    @Override
    public Task createNode(final Template template, final String newName) {
        return perform(new HPCloudSpecificOperation<Task>() {

            @Override
            public Task perform(NovaApi novaApi) {
                LOGGER.debug("Making call to create node ...");
                ServerApi serverApi = novaApi.getServerApiForZone(configuration.getZone());
                CreateServerOptions createServerOptions = CreateServerOptions.Builder
                        .keyPairName(configuration.getKeyPairName())
                        .securityGroupNames(configuration.getSecurityGroupNames());
                ServerCreated serverCreated = serverApi.create(newName, template.getIdentity(),
                        configuration.getFlavorId(), createServerOptions);
                LOGGER.debug("Created a new server: " + serverCreated.toString());
                Task task = new Task();
                task.setName(serverCreated.getId());
                task.setOperation(OP_CREATE_SERVER);
                task.setStatus(Task.Status.QUEUED);
                return task;
            }
        });
    }

    @Override
    public Task allocateDisk(Node node, int sizeInKillobytes) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Node retrieveNode(final String nodeIdentity) {
        return perform(new HPCloudSpecificOperation<Node>() {

            @Override
            protected Node perform(NovaApi novaApi) {
                LOGGER.debug("Making call to retrieve node ...");
                ServerApi serverApi = novaApi.getServerApiForZone(configuration.getZone());
                Server server = serverApi.get(nodeIdentity);
                if (server == null) {
                    throw new RuntimeException(String.format("No server was found for ID '%s'", nodeIdentity));
                }
                LOGGER.debug("Found node: " + server.toString());
                return convertServerToNode(server);
            }
        });
    }

    @Override
    public Task retrieveTask(Task task) {
        if (OP_CREATE_SERVER.equals(task.getOperation())) {
            final String serverId = task.getName();
            Server foundServer = perform(new HPCloudSpecificOperation<Server>() {

                @Override
                protected Server perform(NovaApi novaApi) {
                    LOGGER.debug("Making call to retrieve server from Task...");
                    ServerApi serverApi = novaApi.getServerApiForZone(configuration.getZone());
                    Server server = serverApi.get(serverId);
                    if (server == null) {
                        throw new RuntimeException(String.format("No server was found for ID '%s'", serverId));
                    }
                    LOGGER.debug("Found server: " + server.toString());
                    return server;
                }
            });
            Task.Status status = Task.Status.UNKNOWN;
            if (foundServer.getStatus() != null) {
                switch (foundServer.getStatus()) {
                case ACTIVE:
                    status = Task.Status.COMPLETE;
                    break;
                case PAUSED:
                case SUSPENDED:
                    status = Task.Status.CANCELLED;
                    break;
                case BUILD:
                case HARD_REBOOT:
                case PASSWORD:
                case REBOOT:
                case REBUILD:
                case RESIZE:
                case VERIFY_RESIZE:
                case REVERT_RESIZE:
                    status = Task.Status.QUEUED;
                    break;
                case DELETED:
                case ERROR:
                case UNRECOGNIZED:
                case UNKNOWN:
                default:
                    status = Task.Status.UNKNOWN;
                }
            }
            task.setStatus(status);
        }
        return task;
    }

    @Override
    public Node retrieveNodeByName(final String nodeName) {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<Node> listNodes() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Task startNode(final Node node) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Task stopNode(Node node) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void deleteNode(final Node node) {
        perform(new HPCloudSpecificOperation<Object>() {

            @Override
            protected Object perform(NovaApi novaApi) {
                LOGGER.debug("Making call to delete node...");
                ServerApi serverApi = novaApi.getServerApiForZone(configuration.getZone());
                String zoneIdentity = node.getIdentity();
                // trim away the zone prefix and slash (example node identity: "az-1.region-a.geo-1/1234567")
                if (zoneIdentity.startsWith(configuration.getZone())) {
                    zoneIdentity = zoneIdentity.substring(configuration.getZone().length() + 1);
                }
                boolean deleted = serverApi.delete(zoneIdentity);
                if (deleted) {
                    LOGGER.debug("Deleted server with ID: " + node.getIdentity());
                } else {
                    LOGGER.error("Deletion failed for server with ID: " + node.getIdentity());
                }
                return null;
            }
        });
    }

    @Override
    public Node findNodeForIp(final String ip) {
        return perform(new JCloudGenericOperation<Node>() {

            @Override
            public Node perform(ComputeService cs) {
                LOGGER.debug("Making call to list nodes...");
                Set<? extends ComputeMetadata> nodes = cs.listNodes();
                Node retNode = null;
                for (ComputeMetadata cm : nodes) {
                    if (cm instanceof NodeMetadata) {
                        NodeMetadata nm = (NodeMetadata) cm;
                        // ignoring private addresses as we won't be using them
                        Set<String> addresses = nm.getPublicAddresses();
                        for (String address : addresses) {
                            if (ip.equals(address)) {
                                retNode = convertComputeMetadataToNode(cm);
                                break;
                            }
                        }
                    }
                }
                LOGGER.debug("Found match: " + retNode.toString());
                return retNode;
            }
        });
    }

    public HPCloudServicesConfiguration getConfiguration() {
        return configuration;
    }

    public void setConfiguration(HPCloudServicesConfiguration configuration) {
        this.configuration = configuration;
    }

    public ContextBuilder getContextBuilder() {
        return contextBuilder;
    }

    public void setContextBuilder(ContextBuilder contextBuilder) {
        this.contextBuilder = contextBuilder;
    }

    private static Template convertImageToTemplate(Image image) {
        Template template = new Template();
        template.setIdentity(image.getId());
        template.setName(image.getName());
        template.setUri(image.getUri());
        return template;
    }

    private static Node convertComputeMetadataToNode(ComputeMetadata cm) {
        Node node = new Node();
        node.setIdentity(cm.getId());
        node.setName(cm.getName());
        node.setUri(cm.getUri());
        if (cm instanceof NodeMetadata) {
            NodeMetadata nm = (NodeMetadata) cm;
            Set<String> addresses = nm.getPublicAddresses();
            if (!addresses.isEmpty()) {
                node.setIpAddress(addresses.iterator().next());
            }
            node.setStatus(convertNodeMetadataStatusToStatus(nm.getStatus()));
        }
        return node;
    }

    protected static Node convertServerToNode(Server server) {
        Node node = new Node();
        node.setIdentity(String.valueOf(server.getId()));
        Multimap<String, Address> addressMap = server.getAddresses();
        // There may be a bug in the JClouds code: both public and private IPs appear
        // for the same "private" key in the map; the private IP is first, the public IP is second
        if (addressMap != null) {
            for (String key : addressMap.keySet()) {
                Collection<Address> addresses = addressMap.get(key);
                if (addresses != null && addresses.size() > 1) {
                    for (Address address : addresses) {
                        try {
                            if (!InetAddress.getByName(address.getAddr()).isSiteLocalAddress()) {
                                node.setIpAddress(address.getAddr());
                                break;
                            }
                        } catch (UnknownHostException e) {
                            LOGGER.debug("Caught Exception examining IP: " + address.getAddr(), e);
                        }
                    }
                }
            }
        }
        node.setName(server.getName());
        node.setStatus(convertServerStatusToNodeStatus(server.getStatus()));
        // URI is left null but it is not yet needed
        return node;
    }

    private static Node.Status convertNodeMetadataStatusToStatus(NodeMetadata.Status status) {
        if (status != null) {
            switch (status) {
            case PENDING:
                return Status.TRANSITION;
            case RUNNING:
                return Status.RUNNING;
            case SUSPENDED:
                return Status.STOPPED;
            case TERMINATED:
                return Status.DELETED;
            case UNRECOGNIZED:
                return Status.UNKNOWN;
            case ERROR:
                return Status.ERROR;
            }
        }
        return Status.UNKNOWN;
    }

    private static Node.Status convertServerStatusToNodeStatus(
            org.jclouds.openstack.nova.v2_0.domain.Server.Status status) {
        if (status != null) {
            switch (status) {
            case ACTIVE:
                return Node.Status.RUNNING;
            case PAUSED:
            case SUSPENDED:
                return Node.Status.STOPPED;
            case DELETED:
                return Node.Status.DELETED;
            case BUILD:
            case HARD_REBOOT:
            case PASSWORD:
            case REBOOT:
            case REBUILD:
            case RESIZE:
            case VERIFY_RESIZE:
            case REVERT_RESIZE:
                return Node.Status.TRANSITION;
            case ERROR:
            case UNRECOGNIZED:
            case UNKNOWN:
            default:
                return Node.Status.UNKNOWN;
            }
        }
        return Node.Status.UNKNOWN;
    }
}