Repository: stratos Updated Branches: refs/heads/master 3bd20e5ee -> 24ba6982f
http://git-wip-us.apache.org/repos/asf/stratos/blob/24ba6982/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java new file mode 100644 index 0000000..056d991 --- /dev/null +++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java @@ -0,0 +1,144 @@ +/* + * 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.stratos.cloud.controller.services.impl; + +import com.google.common.net.InetAddresses; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.cloud.controller.context.CloudControllerContext; +import org.apache.stratos.cloud.controller.domain.ClusterContext; +import org.apache.stratos.cloud.controller.domain.IaasProvider; +import org.apache.stratos.cloud.controller.domain.MemberContext; +import org.apache.stratos.cloud.controller.domain.Volume; +import org.apache.stratos.cloud.controller.exception.CloudControllerException; +import org.apache.stratos.cloud.controller.exception.InvalidIaasProviderException; +import org.apache.stratos.cloud.controller.iaases.Iaas; +import org.apache.stratos.cloud.controller.messaging.publisher.CartridgeInstanceDataPublisher; +import org.apache.stratos.cloud.controller.messaging.topology.TopologyBuilder; +import org.apache.stratos.cloud.controller.util.CloudControllerUtil; +import org.apache.stratos.messaging.domain.topology.MemberStatus; +import org.jclouds.rest.ResourceNotFoundException; + +/** + * Cloud controller service utility methods. + */ +public class CloudControllerServiceUtil { + + private static final Log log = LogFactory.getLog(CloudControllerServiceUtil.class); + + /** + * A helper method to terminate an instance. + * + * @param iaasProvider + * @param ctxt + * @param nodeId + * @return will return the IaaSProvider + */ + public static IaasProvider terminate(IaasProvider iaasProvider, + String nodeId, MemberContext ctxt) { + Iaas iaas = iaasProvider.getIaas(); + if (iaas == null) { + + try { + iaas = CloudControllerUtil.getIaas(iaasProvider); + } catch (InvalidIaasProviderException e) { + String msg = + "Instance termination failed. " + ctxt.toString() + + ". Cause: Unable to build Iaas of this " + iaasProvider.toString(); + log.error(msg, e); + throw new CloudControllerException(msg, e); + } + + } + + //detach volumes if any + detachVolume(iaasProvider, ctxt); + + // destroy the node + iaasProvider.getComputeService().destroyNode(nodeId); + + // release allocated IP address + if (ctxt.getAllocatedIpAddress() != null) { + iaas.releaseAddress(ctxt.getAllocatedIpAddress()); + } + + if (log.isDebugEnabled()) { + log.debug("Member is terminated: " + ctxt.toString()); + } else if (log.isInfoEnabled()) { + log.info("Member with id " + ctxt.getMemberId() + " is terminated"); + } + return iaasProvider; + } + + private static void detachVolume(IaasProvider iaasProvider, MemberContext ctxt) { + String clusterId = ctxt.getClusterId(); + ClusterContext clusterCtxt = CloudControllerContext.getInstance().getClusterContext(clusterId); + if (clusterCtxt.getVolumes() != null) { + for (Volume volume : clusterCtxt.getVolumes()) { + try { + String volumeId = volume.getId(); + if (volumeId == null) { + return; + } + Iaas iaas = iaasProvider.getIaas(); + iaas.detachVolume(ctxt.getInstanceId(), volumeId); + } catch (ResourceNotFoundException ignore) { + if (log.isDebugEnabled()) { + log.debug(ignore); + } + } + } + } + } + + public static void logTermination(MemberContext memberContext) { + + if (memberContext == null) { + return; + } + + String partitionId = memberContext.getPartition() == null ? null : memberContext.getPartition().getId(); + + //updating the topology + TopologyBuilder.handleMemberTerminated(memberContext.getCartridgeType(), + memberContext.getClusterId(), memberContext.getNetworkPartitionId(), + partitionId, memberContext.getMemberId()); + + //publishing data + CartridgeInstanceDataPublisher.publish(memberContext.getMemberId(), + partitionId, + memberContext.getNetworkPartitionId(), + memberContext.getClusterId(), + memberContext.getCartridgeType(), + MemberStatus.Terminated.toString(), + null); + + // update data holders + CloudControllerContext.getInstance().removeMemberContext(memberContext.getMemberId(), memberContext.getClusterId()); + + // persist + CloudControllerContext.getInstance().persist(); + } + + public static boolean isValidIpAddress(String ip) { + boolean isValid = InetAddresses.isInetAddress(ip); + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/24ba6982/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceCreator.java ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceCreator.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceCreator.java new file mode 100644 index 0000000..033dc6f --- /dev/null +++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceCreator.java @@ -0,0 +1,289 @@ +/* + * 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.stratos.cloud.controller.services.impl; + +import com.google.common.collect.ImmutableSet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.cloud.controller.context.CloudControllerContext; +import org.apache.stratos.cloud.controller.domain.*; +import org.apache.stratos.cloud.controller.exception.CloudControllerException; +import org.apache.stratos.cloud.controller.iaases.Iaas; +import org.apache.stratos.cloud.controller.messaging.publisher.CartridgeInstanceDataPublisher; +import org.apache.stratos.cloud.controller.messaging.topology.TopologyBuilder; +import org.apache.stratos.cloud.controller.util.CloudControllerConstants; +import org.apache.stratos.messaging.domain.topology.MemberStatus; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadataBuilder; +import org.jclouds.compute.domain.Template; + +import java.util.Set; +import java.util.concurrent.locks.Lock; + +/** + * Instance creator runnable. + */ +public class InstanceCreator implements Runnable { + + private static final Log log = LogFactory.getLog(InstanceCreator.class); + + private MemberContext memberContext; + private IaasProvider iaasProvider; + private String cartridgeType; + + public InstanceCreator(MemberContext memberContext, IaasProvider iaasProvider, + String cartridgeType) { + this.memberContext = memberContext; + this.iaasProvider = iaasProvider; + this.cartridgeType = cartridgeType; + } + + @Override + public void run() { + Lock lock = null; + try { + lock = CloudControllerContext.getInstance().acquireMemberContextWriteLock(); + + String clusterId = memberContext.getClusterId(); + Partition partition = memberContext.getPartition(); + ClusterContext ctxt = CloudControllerContext.getInstance().getClusterContext(clusterId); + Iaas iaas = iaasProvider.getIaas(); + String publicIp = null; + + NodeMetadata node = null; + // generate the group id from domain name and sub domain name. + // Should have lower-case ASCII letters, numbers, or dashes. + // Should have a length between 3-15 + String str = clusterId.length() > 10 ? clusterId.substring(0, 10) : clusterId.substring(0, clusterId.length()); + String group = str.replaceAll("[^a-z0-9-]", ""); + + try { + ComputeService computeService = iaasProvider.getComputeService(); + Template template = iaasProvider.getTemplate(); + + if (log.isDebugEnabled()) { + log.debug("Cloud Controller is delegating request to start an instance for " + + memberContext + " to Jclouds layer."); + } + // create and start a node + Set<? extends NodeMetadata> nodes = computeService + .createNodesInGroup(group, 1, template); + node = nodes.iterator().next(); + if (log.isDebugEnabled()) { + log.debug("Cloud Controller received a response for the request to start " + + memberContext + " from Jclouds layer."); + } + + if (node == null) { + String msg = "Null response received for instance start-up request to Jclouds.\n" + + memberContext.toString(); + log.error(msg); + throw new IllegalStateException(msg); + } + + // node id + String nodeId = node.getId(); + if (nodeId == null) { + String msg = "Node id of the starting instance is null.\n" + + memberContext.toString(); + log.fatal(msg); + throw new IllegalStateException(msg); + } + + memberContext.setNodeId(nodeId); + if (log.isDebugEnabled()) { + log.debug("Node id was set. " + memberContext.toString()); + } + + // attach volumes + if (ctxt.isVolumeRequired()) { + // remove region prefix + String instanceId = nodeId.indexOf('/') != -1 ? nodeId + .substring(nodeId.indexOf('/') + 1, nodeId.length()) + : nodeId; + memberContext.setInstanceId(instanceId); + if (ctxt.getVolumes() != null) { + for (Volume volume : ctxt.getVolumes()) { + try { + iaas.attachVolume(instanceId, volume.getId(), + volume.getDevice()); + } catch (Exception e) { + // continue without throwing an exception, since + // there is an instance already running + log.error("Attaching Volume to Instance [ " + + instanceId + " ] failed!", e); + } + } + } + } + + } catch (Exception e) { + String msg = "Failed to start an instance. " + memberContext.toString() + " Cause: " + e.getMessage(); + log.error(msg, e); + throw new IllegalStateException(msg, e); + } + + try { + if (log.isDebugEnabled()) { + log.debug("IP allocation process started for " + memberContext); + } + String autoAssignIpProp = + iaasProvider.getProperty(CloudControllerConstants.AUTO_ASSIGN_IP_PROPERTY); + + String pre_defined_ip = + iaasProvider.getProperty(CloudControllerConstants.FLOATING_IP_PROPERTY); + + // reset ip + String ip = ""; + + // default behavior is autoIpAssign=false + if (autoAssignIpProp == null || + (autoAssignIpProp != null && autoAssignIpProp.equals("false"))) { + + // check if floating ip is well defined in cartridge definition + if (pre_defined_ip != null) { + if (CloudControllerServiceUtil.isValidIpAddress(pre_defined_ip)) { + if (log.isDebugEnabled()) { + log.debug("CloudControllerServiceImpl:IpAllocator:pre_defined_ip: invoking associatePredefinedAddress" + pre_defined_ip); + } + ip = iaas.associatePredefinedAddress(node, pre_defined_ip); + + if (ip == null || "".equals(ip) || !pre_defined_ip.equals(ip)) { + // throw exception and stop instance creation + String msg = "Error occurred while allocating predefined floating ip address: " + pre_defined_ip + + " / allocated ip:" + ip + + " - terminating node:" + memberContext.toString(); + log.error(msg); + // terminate instance + CloudControllerServiceUtil.terminate(iaasProvider, + node.getId(), memberContext); + throw new CloudControllerException(msg); + } + } else { + String msg = "Invalid floating ip address configured: " + pre_defined_ip + + " - terminating node:" + memberContext.toString(); + log.error(msg); + // terminate instance + CloudControllerServiceUtil.terminate(iaasProvider, + node.getId(), memberContext); + throw new CloudControllerException(msg); + } + + } else { + if (log.isDebugEnabled()) { + log.debug("CloudControllerServiceImpl:IpAllocator:no (valid) predefined floating ip configured, " + + "selecting available one from pool"); + } + // allocate an IP address - manual IP assigning mode + ip = iaas.associateAddress(node); + + if (ip != null) { + memberContext.setAllocatedIpAddress(ip); + if (log.isDebugEnabled()) { + log.debug("Allocated an ip address: " + + memberContext.toString()); + } else if (log.isInfoEnabled()) { + log.info("Allocated ip address [ " + memberContext.getAllocatedIpAddress() + + " ] to member with id: " + memberContext.getMemberId()); + } + } + } + + if (ip == null) { + String msg = "No IP address found. IP allocation failed for " + memberContext; + log.error(msg); + throw new CloudControllerException(msg); + } + + // build the node with the new ip + node = NodeMetadataBuilder.fromNodeMetadata(node) + .publicAddresses(ImmutableSet.of(ip)).build(); + } + + + // public ip + if (node.getPublicAddresses() != null && + node.getPublicAddresses().iterator().hasNext()) { + ip = node.getPublicAddresses().iterator().next(); + publicIp = ip; + memberContext.setPublicIpAddress(ip); + if (log.isDebugEnabled()) { + log.debug("Retrieving Public IP Address : " + memberContext.toString()); + } else if (log.isInfoEnabled()) { + log.info("Retrieving Public IP Address: " + memberContext.getPublicIpAddress() + + ", member id: " + memberContext.getMemberId()); + } + } + + // private IP + if (node.getPrivateAddresses() != null && + node.getPrivateAddresses().iterator().hasNext()) { + ip = node.getPrivateAddresses().iterator().next(); + memberContext.setPrivateIpAddress(ip); + if (log.isDebugEnabled()) { + log.debug("Retrieving Private IP Address. " + memberContext.toString()); + } else if (log.isInfoEnabled()) { + log.info("Retrieving Private IP Address: " + memberContext.getPrivateIpAddress() + + ", member id: " + memberContext.getMemberId()); + } + } + + CloudControllerContext.getInstance().addMemberContext(memberContext); + + // persist in registry + CloudControllerContext.getInstance().persist(); + + + // trigger topology + TopologyBuilder.handleMemberSpawned(cartridgeType, clusterId, + partition.getId(), ip, publicIp, memberContext); + + String memberID = memberContext.getMemberId(); + + // update the topology with the newly spawned member + // publish data + CartridgeInstanceDataPublisher.publish(memberID, + memberContext.getPartition().getId(), + memberContext.getNetworkPartitionId(), + memberContext.getClusterId(), + cartridgeType, + MemberStatus.Created.toString(), + node); + if (log.isDebugEnabled()) { + log.debug("Node details: " + node.toString()); + } + + if (log.isDebugEnabled()) { + log.debug("IP allocation process ended for " + memberContext); + } + + } catch (Exception e) { + String msg = "Error occurred while allocating an ip address. " + memberContext.toString(); + log.error(msg, e); + throw new CloudControllerException(msg, e); + } + } finally { + if(lock != null) { + CloudControllerContext.getInstance().releaseWriteLock(lock); + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/stratos/blob/24ba6982/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceTerminator.java ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceTerminator.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceTerminator.java new file mode 100644 index 0000000..374537d --- /dev/null +++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/InstanceTerminator.java @@ -0,0 +1,99 @@ +/* + * 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.stratos.cloud.controller.services.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.stratos.cloud.controller.context.CloudControllerContext; +import org.apache.stratos.cloud.controller.domain.Cartridge; +import org.apache.stratos.cloud.controller.domain.IaasProvider; +import org.apache.stratos.cloud.controller.domain.MemberContext; +import org.apache.stratos.cloud.controller.exception.CloudControllerException; +import org.apache.stratos.cloud.controller.exception.InvalidCartridgeTypeException; +import org.apache.stratos.cloud.controller.exception.InvalidMemberException; + +import java.util.concurrent.locks.Lock; + +/** + * Instance terminator runnable. + */ +public class InstanceTerminator implements Runnable { + + private static final Log log = LogFactory.getLog(InstanceTerminator.class); + + private MemberContext ctxt; + + public InstanceTerminator(MemberContext ctxt) { + this.ctxt = ctxt; + } + + @Override + public void run() { + String memberId = ctxt.getMemberId(); + String clusterId = ctxt.getClusterId(); + String partitionId = ctxt.getPartition().getId(); + String cartridgeType = ctxt.getCartridgeType(); + String nodeId = ctxt.getNodeId(); + + Lock lock = null; + try { + CloudControllerContext.getInstance().acquireMemberContextWriteLock(); + + Cartridge cartridge = CloudControllerContext.getInstance().getCartridge(cartridgeType); + log.info("Starting to terminate an instance with member id : " + memberId + + " in partition id: " + partitionId + " of cluster id: " + clusterId + + " and of cartridge type: " + cartridgeType); + + if (cartridge == null) { + String msg = "Termination of Member Id: " + memberId + " failed. " + + "Cannot find a matching Cartridge for type: " + + cartridgeType; + log.error(msg); + throw new InvalidCartridgeTypeException(msg); + } + + // if no matching node id can be found. + if (nodeId == null) { + String msg = "Termination failed. Cannot find a node id for Member Id: " + memberId; + + // log information + CloudControllerServiceUtil.logTermination(ctxt); + log.error(msg); + throw new InvalidMemberException(msg); + } + + IaasProvider iaasProvider = cartridge.getIaasProviderOfPartition(partitionId); + + // terminate it! + CloudControllerServiceUtil.terminate(iaasProvider, nodeId, ctxt); + + // log information + CloudControllerServiceUtil.logTermination(ctxt); + } catch (Exception e) { + String msg = "Instance termination failed. " + ctxt.toString(); + log.error(msg, e); + throw new CloudControllerException(msg, e); + } finally { + if(lock != null) { + CloudControllerContext.getInstance().releaseWriteLock(lock); + } + } + } +} \ No newline at end of file