Java tutorial
/******************************************************************************* * 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; } }