You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by is...@apache.org on 2013/07/10 13:12:18 UTC
[03/14] versions of components are set to 3.0.0-SNAPSHOT
http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/e8c32dac/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/impl/CloudControllerServiceImpl.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/impl/CloudControllerServiceImpl.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/impl/CloudControllerServiceImpl.java
new file mode 100644
index 0000000..b33d7b6
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/impl/CloudControllerServiceImpl.java
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. 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.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.stratos.cloud.controller.consumers.TopologyBuilder;
+import org.apache.stratos.cloud.controller.exception.CloudControllerException;
+import org.apache.stratos.cloud.controller.exception.UnregisteredServiceException;
+import org.apache.stratos.cloud.controller.publisher.CartridgeInstanceDataPublisherTask;
+import org.apache.stratos.cloud.controller.runtime.FasterLookUpDataHolder;
+import org.apache.stratos.cloud.controller.util.Cartridge;
+import org.apache.stratos.cloud.controller.util.CartridgeInfo;
+import org.apache.stratos.cloud.controller.util.Properties;
+import org.apache.stratos.cloud.controller.util.Property;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.ComputeMetadata;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.internal.NodeMetadataImpl;
+import org.apache.stratos.lb.common.conf.util.Constants;
+import org.wso2.carbon.ntask.common.TaskException;
+import org.wso2.carbon.ntask.core.TaskInfo;
+import org.wso2.carbon.ntask.core.TaskInfo.TriggerInfo;
+import org.wso2.carbon.ntask.core.TaskManager;
+import org.wso2.carbon.ntask.core.service.TaskService;
+import org.wso2.carbon.registry.core.exceptions.RegistryException;
+import org.apache.stratos.cloud.controller.exception.UnregisteredCartridgeException;
+import org.apache.stratos.cloud.controller.interfaces.CloudControllerService;
+import org.apache.stratos.cloud.controller.jcloud.ComputeServiceBuilderUtil;
+import org.apache.stratos.cloud.controller.persist.Deserializer;
+import org.apache.stratos.cloud.controller.registry.RegistryManager;
+import org.apache.stratos.cloud.controller.topic.TopologySynchronizerTask;
+import org.apache.stratos.cloud.controller.util.CloudControllerConstants;
+import org.apache.stratos.cloud.controller.util.DeclarativeServiceReferenceHolder;
+import org.apache.stratos.cloud.controller.util.CloudControllerUtil;
+import org.apache.stratos.cloud.controller.util.IaasContext;
+import org.apache.stratos.cloud.controller.util.IaasProvider;
+import org.apache.stratos.cloud.controller.util.ServiceContext;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Cloud Controller Service is responsible for starting up new server instances,
+ * terminating already started instances, providing pending instance count etc.
+ *
+ */
+public class CloudControllerServiceImpl implements CloudControllerService {
+
+ private static final Log log = LogFactory.getLog(CloudControllerServiceImpl.class);
+ private FasterLookUpDataHolder dataHolder = FasterLookUpDataHolder.getInstance();
+
+ public CloudControllerServiceImpl() {
+
+ // acquire serialized data from registry
+ acquireData();
+
+ // gets the task service
+ TaskService taskService =
+ DeclarativeServiceReferenceHolder.getInstance()
+ .getTaskService();
+
+ if (dataHolder.getEnableBAMDataPublisher()) {
+
+ // register and schedule, BAM data publisher task
+ registerAndScheduleDataPublisherTask(taskService);
+ }
+
+ if (dataHolder.getEnableTopologySync()) {
+
+ // start the topology builder thread
+ startTopologyBuilder();
+
+ // register and schedule, topology synchronizer task
+ registerAndScheduleTopologySyncerTask(taskService);
+ }
+ }
+
+ private void registerAndScheduleTopologySyncerTask(TaskService taskService) {
+ TaskInfo taskInfo;
+ TaskManager tm = null;
+ try {
+
+ if (!taskService.getRegisteredTaskTypes()
+ .contains(CloudControllerConstants.TOPOLOGY_SYNC_TASK_TYPE)) {
+
+ // topology sync
+ taskService.registerTaskType(CloudControllerConstants.TOPOLOGY_SYNC_TASK_TYPE);
+
+ tm =
+ taskService.getTaskManager(CloudControllerConstants.TOPOLOGY_SYNC_TASK_TYPE);
+
+ TriggerInfo triggerInfo =
+ new TriggerInfo(
+ dataHolder.getTopologySynchronizerCron());
+ taskInfo =
+ new TaskInfo(CloudControllerConstants.TOPOLOGY_SYNC_TASK_NAME,
+ TopologySynchronizerTask.class.getName(),
+ new HashMap<String, String>(), triggerInfo);
+ tm.registerTask(taskInfo);
+ }
+
+ } catch (Exception e) {
+ String msg =
+ "Error scheduling task: " +
+ CloudControllerConstants.TOPOLOGY_SYNC_TASK_NAME;
+ log.error(msg, e);
+ if (tm != null) {
+ try {
+ tm.deleteTask(CloudControllerConstants.TOPOLOGY_SYNC_TASK_NAME);
+ } catch (TaskException e1) {
+ log.error(e1);
+ }
+ }
+ throw new CloudControllerException(msg, e);
+ }
+ }
+
+ private void startTopologyBuilder() {
+ // initialize TopologyBuilder Consumer
+ Thread topologyBuilder =
+ new Thread(
+ new TopologyBuilder(
+ dataHolder.getSharedTopologyDiffQueue()));
+ // start consumer
+ topologyBuilder.start();
+ }
+
+ private TaskManager registerAndScheduleDataPublisherTask(TaskService taskService) {
+ TaskInfo taskInfo;
+ TaskManager tm = null;
+ // initialize and schedule the data publisher task
+ try {
+
+ if (!taskService.getRegisteredTaskTypes()
+ .contains(CloudControllerConstants.DATA_PUB_TASK_TYPE)) {
+
+ taskService.registerTaskType(CloudControllerConstants.DATA_PUB_TASK_TYPE);
+
+ tm = taskService.getTaskManager(CloudControllerConstants.DATA_PUB_TASK_TYPE);
+
+ if (!tm.isTaskScheduled(CloudControllerConstants.DATA_PUB_TASK_NAME)) {
+
+ TriggerInfo triggerInfo =
+ new TriggerInfo(
+ FasterLookUpDataHolder.getInstance()
+ .getDataPublisherCron());
+ taskInfo =
+ new TaskInfo(CloudControllerConstants.DATA_PUB_TASK_NAME,
+ CartridgeInstanceDataPublisherTask.class.getName(),
+ new HashMap<String, String>(), triggerInfo);
+ tm.registerTask(taskInfo);
+
+ // Following code is currently not required, due to an issue in TS API.
+ // tm.scheduleTask(taskInfo.getName());
+ }
+ }
+
+ } catch (Exception e) {
+ String msg =
+ "Error scheduling task: " +
+ CloudControllerConstants.DATA_PUB_TASK_NAME;
+ log.error(msg, e);
+ if (tm != null) {
+ try {
+ tm.deleteTask(CloudControllerConstants.DATA_PUB_TASK_NAME);
+ } catch (TaskException e1) {
+ log.error(e1);
+ }
+ }
+ throw new CloudControllerException(msg, e);
+ }
+ return tm;
+ }
+
+ private void acquireData() {
+
+ Object obj = RegistryManager.getInstance().retrieve();
+ if (obj != null) {
+ try {
+ Object dataObj = Deserializer.deserializeFromByteArray((byte[]) obj);
+ if (dataObj instanceof FasterLookUpDataHolder) {
+ FasterLookUpDataHolder serializedObj = (FasterLookUpDataHolder) dataObj;
+ FasterLookUpDataHolder currentData = FasterLookUpDataHolder.getInstance();
+
+ // assign necessary data
+ currentData.setNodeIdToServiceContextMap(serializedObj.getNodeIdToServiceContextMap());
+
+ // traverse through current Service Contexts
+ for (ServiceContext ctxt : currentData.getServiceCtxtList()) {
+ // traverse through serialized Service Contexts
+ for (ServiceContext serializedCtxt : serializedObj.getServiceCtxtList()) {
+ // if a matching Service Context found
+ if(ctxt.equals(serializedCtxt)){
+ // persisted node ids of this Service Context
+ List<Object> nodeIds = serializedObj.getNodeIdsOfServiceCtxt(serializedCtxt);
+ for (Object nodeIdObj : nodeIds) {
+ String nodeId = (String) nodeIdObj;
+
+ // assign persisted data
+ currentData.addNodeId(nodeId, ctxt);
+
+ }
+
+ ctxt.setIaasContextMap(serializedCtxt.getIaasCtxts());
+ appendToPublicIpProperty(serializedCtxt.getProperty(CloudControllerConstants.PUBLIC_IP_PROPERTY), ctxt);
+
+ // assign lastly used IaaS
+ if(serializedCtxt.getCartridge() != null && serializedCtxt.getCartridge().getLastlyUsedIaas() != null){
+
+ if(ctxt.getCartridge() == null){
+ // load Cartridge
+ ctxt.setCartridge(loadCartridge(ctxt.getCartridgeType(), ctxt.getPayload(), serializedObj.getCartridges()));
+ }
+
+ IaasProvider serializedIaas = serializedCtxt.getCartridge().getLastlyUsedIaas();
+ ctxt.getCartridge().setLastlyUsedIaas(serializedIaas);
+
+ }
+ }
+ }
+ }
+
+ log.debug("Data is retrieved from registry.");
+ } else {
+ log.debug("No data is persisted in registry.");
+ }
+ } catch (Exception e) {
+
+ String msg =
+ "Unable to acquire data from Registry. Hence, any historical data will not get reflected.";
+ log.warn(msg, e);
+ }
+
+ }
+ }
+
+ @Override
+ public String startInstance(String domainName, String subDomainName) {
+
+ ComputeService computeService;
+ Template template;
+ String ip = "";
+ final Lock lock = new ReentrantLock();
+
+ // check for sub domain
+ subDomainName = checkSubDomain(subDomainName);
+
+ log.info("Starting new instance of domain : " + domainName + " and sub domain : " +
+ subDomainName);
+
+ // get the subjected ServiceContext
+ ServiceContext serviceCtxt =
+ FasterLookUpDataHolder.getInstance()
+ .getServiceContext(domainName,
+ subDomainName);
+
+ if (serviceCtxt == null) {
+ String msg =
+ "Not a registered service: domain - " + domainName + ", sub domain - " +
+ subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // load Cartridge
+ serviceCtxt.setCartridge(loadCartridge(serviceCtxt.getCartridgeType(),
+ serviceCtxt.getPayload(),
+ FasterLookUpDataHolder.getInstance().getCartridges()));
+
+ if (serviceCtxt.getCartridge() == null) {
+ String msg =
+ "There's no registered Cartridge found. Domain - " + domainName +
+ ", sub domain - " + subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ if (serviceCtxt.getCartridge().getIaases().isEmpty()) {
+ String msg =
+ "There's no registered IaaSes found for Cartridge type: " +
+ serviceCtxt.getCartridge().getType();
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // sort the IaasProviders according to scale up order
+ Collections.sort(serviceCtxt.getCartridge().getIaases(),
+ IaasProviderComparator.ascending(IaasProviderComparator.getComparator(IaasProviderComparator.SCALE_UP_SORT)));
+
+ for (IaasProvider iaas : serviceCtxt.getCartridge().getIaases()) {
+
+ IaasContext ctxt = null;
+ if ((ctxt = serviceCtxt.getIaasContext(iaas.getType())) == null) {
+ ctxt = serviceCtxt.addIaasContext(iaas.getType());
+ }
+
+ if (iaas.getMaxInstanceLimit() > ctxt.getCurrentInstanceCount()) {
+ try {
+
+ iaas.getIaas().setDynamicPayload(iaas);
+
+ // get the ComputeService
+ computeService = iaas.getComputeService();
+
+ // corresponding Template
+ template = iaas.getTemplate();
+
+ if (template == null) {
+ String msg =
+ "Failed to start an instance in " +
+ iaas.getType() +
+ ". Reason : Template is null. You have not specify a matching service " +
+ "element in the configuration file of Autoscaler.\n Hence, will try to " +
+ "start in another IaaS if available.";
+ log.error(msg);
+ continue;
+ }
+
+ // set instance name as the host name
+ // template.getOptions().userMetadata("Name",
+ // serviceCtxt.getHostName());
+ // template.getOptions().as(TemplateOptions.class).userMetadata("Name",
+ // serviceCtxt.getHostName());
+
+ // 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 = domainName.concat("-" + subDomainName).substring(0, 10);
+ String group = str.replaceAll("[^a-z0-9-]", "");
+
+ NodeMetadata node;
+
+ // create and start a node
+ Set<? extends NodeMetadata> nodes =
+ computeService.createNodesInGroup(group, 1,
+ template);
+
+ node = nodes.iterator().next();
+
+ String autoAssignIpProp =
+ iaas.getProperty(CloudControllerConstants.AUTO_ASSIGN_IP_PROPERTY);
+
+ // acquire the lock
+ lock.tryLock();
+
+ try {
+ // reset ip
+ ip = "";
+ // default behavior is autoIpAssign=false
+ if (autoAssignIpProp == null ||
+ (autoAssignIpProp != null && autoAssignIpProp.equals("false"))) {
+ // allocate an IP address - manual IP assigning mode
+ ip = iaas.getIaas().associateAddress(iaas, node);
+ }
+
+ if (ip.isEmpty() && node.getPublicAddresses() != null &&
+ node.getPublicAddresses().iterator().hasNext()) {
+ ip = node.getPublicAddresses().iterator().next();
+ }
+
+ // if not public IP is assigned, we're using private IP
+ if (ip.isEmpty() && node.getPrivateAddresses() != null &&
+ node.getPrivateAddresses().iterator().hasNext()) {
+ ip = node.getPrivateAddresses().iterator().next();
+ }
+
+ if (node.getId() == null) {
+ String msg =
+ "Node id of the starting instance is null.\n" +
+ node.toString();
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // add node ID
+ ctxt.addNodeId(node.getId());
+ ctxt.addNodeToPublicIp(node.getId(), ip);
+
+ // to faster look up
+ FasterLookUpDataHolder.getInstance().addNodeId(node.getId(), serviceCtxt);
+
+ serviceCtxt.getCartridge().setLastlyUsedIaas(iaas);
+
+ // add this ip to the topology
+ appendToPublicIpProperty(ip, serviceCtxt);
+
+ ctxt.incrementCurrentInstanceCountByOne();
+
+ // persist in registry
+ persist();
+
+ // trigger topology consumers
+ List<ServiceContext> list = new ArrayList<ServiceContext>();
+ list.add(serviceCtxt);
+ try {
+ dataHolder.getSharedTopologyDiffQueue().put(list);
+
+ // publish data
+ CartridgeInstanceDataPublisherTask.publish();
+ } catch (InterruptedException ignore) {
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Node details: \n" + node.toString() + "\n***************\n");
+ }
+
+ log.info("Instance is successfully starting up in IaaS " + iaas.getType() +
+ ".\tIP Address(public/private): " + ip + "\tNode Id: " +
+ node.getId());
+
+ return ip;
+
+ } finally {
+ // release the lock
+ lock.unlock();
+ }
+
+ } catch (Exception e) {
+ log.warn("Failed to start an instance in " + iaas.getType() +
+ ". Hence, will try to start in another IaaS if available.", e);
+ continue;
+ }
+ } else {
+ log.warn("Max instance limit is reached in the IaaS " + iaas.getType() +
+ " : Max instance limit: " + iaas.getMaxInstanceLimit());
+ }
+
+ }
+
+ log.error("Failed to start an instance, in any available IaaS: " + domainName +
+ " and sub domain : " + subDomainName);
+
+ return null;
+
+ }
+
+ /**
+ * Appends this ip to the Service Context's {@link CloudControllerConstants#PUBLIC_IP_PROPERTY}
+ * @param ip
+ * @param serviceCtxt
+ */
+ private void appendToPublicIpProperty(String ip, ServiceContext serviceCtxt) {
+ String ipStr = serviceCtxt.getProperty(CloudControllerConstants.PUBLIC_IP_PROPERTY);
+ if (ip != null && !"".equals(ip)) {
+ serviceCtxt.setProperty(CloudControllerConstants.PUBLIC_IP_PROPERTY,
+ ("".equals(ipStr) ? ""
+ : ipStr +
+ CloudControllerConstants.ENTRY_SEPARATOR) +
+ ip);
+ }
+ }
+
+ /**
+ * Persist data in registry.
+ */
+ private void persist() {
+ try {
+ RegistryManager.getInstance().persist(FasterLookUpDataHolder.getInstance());
+ } catch (RegistryException e) {
+
+ String msg = "Failed to persist the Cloud Controller data in registry. Further, transaction roll back also failed.";
+ log.fatal(msg);
+ throw new CloudControllerException(msg, e);
+ }
+ }
+
+ private Cartridge loadCartridge(String cartridgeType, byte[] payload, List<Cartridge> cartridges) {
+
+ for (Cartridge cartridge : cartridges) {
+ if (cartridge.getType().equals(cartridgeType)) {
+ for (IaasProvider iaas : cartridge.getIaases()) {
+ iaas.setPayload(payload);
+ }
+ return cartridge;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean terminateInstance(String domainName, String subDomainName) {
+
+ subDomainName = checkSubDomain(subDomainName);
+
+ log.info("Starting to terminate an instance of domain : " + domainName +
+ " and sub domain : " + subDomainName);
+
+ ServiceContext serviceCtxt =
+ FasterLookUpDataHolder.getInstance()
+ .getServiceContext(domainName,
+ subDomainName);
+
+ if (serviceCtxt == null) {
+ String msg =
+ "Not a registered service: domain - " + domainName + ", sub domain - " +
+ subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // load Cartridge, if null
+ if (serviceCtxt.getCartridge() == null) {
+ serviceCtxt.setCartridge(loadCartridge(serviceCtxt.getCartridgeType(),
+ serviceCtxt.getPayload(),
+ FasterLookUpDataHolder.getInstance()
+ .getCartridges()));
+ }
+
+ // if still, Cartridge is null
+ if (serviceCtxt.getCartridge() == null) {
+ String msg =
+ "There's no registered Cartridge found. Domain - " + domainName +
+ ", sub domain - " + subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // sort the IaasProviders according to scale down order
+ Collections.sort(serviceCtxt.getCartridge().getIaases(),
+ IaasProviderComparator.ascending(IaasProviderComparator.getComparator(IaasProviderComparator.SCALE_DOWN_SORT)));
+
+ // traverse in scale down order
+ for (IaasProvider iaas : serviceCtxt.getCartridge().getIaases()) {
+
+ String msg =
+ "Failed to terminate an instance in " + iaas.getType() +
+ ". Hence, will try to terminate an instance in another IaaS if possible.";
+
+ String nodeId = null;
+
+ IaasContext ctxt = serviceCtxt.getIaasContext(iaas.getType());
+
+ // terminate the last instance first
+ for (String id : Lists.reverse(ctxt.getNodeIds())) {
+ if (id != null) {
+ nodeId = id;
+ break;
+ }
+ }
+
+ // if no matching node id can be found.
+ if (nodeId == null) {
+
+ log.warn(msg + " : Reason- No matching instance found for domain: " + domainName +
+ " and sub domain: " + subDomainName + ".");
+ continue;
+ }
+
+ // terminate it!
+ terminate(iaas, ctxt, nodeId);
+
+ // log information
+ logTermination(nodeId, ctxt, serviceCtxt);
+
+ return true;
+
+ }
+
+ log.info("Termination of an instance which is belong to domain '" + domainName +
+ "' and sub domain '" + subDomainName + "' , failed! Reason: No matching " +
+ "running instance found in any available IaaS.");
+
+ return false;
+
+ }
+
+ @Override
+ public boolean terminateLastlySpawnedInstance(String domainName, String subDomainName) {
+
+ subDomainName = checkSubDomain(subDomainName);
+
+ log.info("Starting to terminate the last instance spawned, of domain : " + domainName +
+ " and sub domain : " + subDomainName);
+
+ ServiceContext serviceCtxt =
+ FasterLookUpDataHolder.getInstance()
+ .getServiceContext(domainName,
+ subDomainName);
+
+ if (serviceCtxt == null) {
+ String msg =
+ "Not a registered service: domain - " + domainName + ", sub domain - " +
+ subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // load Cartridge, if null
+ if (serviceCtxt.getCartridge() == null) {
+ serviceCtxt.setCartridge(loadCartridge(serviceCtxt.getCartridgeType(),
+ serviceCtxt.getPayload(),
+ FasterLookUpDataHolder.getInstance()
+ .getCartridges()));
+ }
+
+ if (serviceCtxt.getCartridge() == null) {
+ String msg =
+ "There's no registered Cartridge found. Domain - " + domainName +
+ ", sub domain - " + subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ IaasProvider iaas = serviceCtxt.getCartridge().getLastlyUsedIaas();
+ // this is required since, we need to find the correct reference.
+ // caz if the lastly used iaas retrieved from registry, it is not a reference.
+ iaas = serviceCtxt.getCartridge().getIaasProvider(iaas.getType());
+
+ if (iaas != null) {
+
+ String nodeId = null;
+ IaasContext ctxt = serviceCtxt.getIaasContext(iaas.getType());
+
+ int i=0;
+ for (i = ctxt.getNodeIds().size()-1; i >= 0 ; i--) {
+ String id = ctxt.getNodeIds().get(i);
+ if (id != null) {
+ nodeId = id;
+ break;
+ }
+ }
+
+ if (nodeId != null) {
+
+ // terminate it!
+ iaas = terminate(iaas, ctxt, nodeId);
+
+ // log information
+ logTermination(nodeId, ctxt, serviceCtxt);
+
+ return true;
+ }
+
+ }
+
+ log.info("Termination of an instance which is belong to domain '" + domainName +
+ "' and sub domain '" + subDomainName + "' , failed! Reason: No matching " +
+ "running instance found in lastly used IaaS.");
+
+ return false;
+
+ }
+
+ @Override
+ public boolean terminateAllInstances(String domainName, String subDomainName) {
+
+ boolean isAtLeastOneTerminated = false;
+
+ subDomainName = checkSubDomain(subDomainName);
+
+ log.info("Starting to terminate all instances of domain : " + domainName +
+ " and sub domain : " + subDomainName);
+
+ ServiceContext serviceCtxt =
+ FasterLookUpDataHolder.getInstance()
+ .getServiceContext(domainName,
+ subDomainName);
+
+ if (serviceCtxt == null) {
+ String msg =
+ "Not a registered service: domain - " + domainName + ", sub domain - " +
+ subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // load Cartridge, if null
+ if (serviceCtxt.getCartridge() == null) {
+ serviceCtxt.setCartridge(loadCartridge(serviceCtxt.getCartridgeType(),
+ serviceCtxt.getPayload(),
+ FasterLookUpDataHolder.getInstance()
+ .getCartridges()));
+ }
+
+ if (serviceCtxt.getCartridge() == null) {
+ String msg =
+ "There's no registered Cartridge found. Domain - " + domainName +
+ ", sub domain - " + subDomainName;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // sort the IaasProviders according to scale down order
+ Collections.sort(serviceCtxt.getCartridge().getIaases(),
+ IaasProviderComparator.ascending(IaasProviderComparator.getComparator(IaasProviderComparator.SCALE_DOWN_SORT)));
+
+ // traverse in scale down order
+ for (IaasProvider iaas : serviceCtxt.getCartridge().getIaases()) {
+
+ IaasContext ctxt = serviceCtxt.getIaasContext(iaas.getType());
+
+ if (ctxt == null) {
+ log.error("Iaas Context for " + iaas.getType() + " not found. Cannot terminate instances");
+ continue;
+ }
+
+ ArrayList<String> temp = new ArrayList<String>(ctxt.getNodeIds());
+ for (String id : temp) {
+ if (id != null) {
+ // terminate it!
+ terminate(iaas, ctxt, id);
+
+ // log information
+ logTermination(id, ctxt, serviceCtxt);
+
+ isAtLeastOneTerminated = true;
+ }
+ }
+ }
+
+ if(isAtLeastOneTerminated){
+ return true;
+ }
+
+ log.info("Termination of an instance which is belong to domain '" + domainName +
+ "' and sub domain '" + subDomainName + "' , failed! Reason: No matching " +
+ "running instance found in lastly used IaaS.");
+
+ return false;
+
+ }
+
+ public int getPendingInstanceCount(String domainName, String subDomainName) {
+
+ subDomainName = checkSubDomain(subDomainName);
+
+ int pendingInstanceCount = 0;
+
+ ServiceContext subjectedSerCtxt =
+ FasterLookUpDataHolder.getInstance()
+ .getServiceContext(domainName,
+ subDomainName);
+
+ if (subjectedSerCtxt != null && subjectedSerCtxt.getCartridgeType() != null) {
+
+ // load cartridge
+ subjectedSerCtxt.setCartridge(loadCartridge(subjectedSerCtxt.getCartridgeType(),
+ subjectedSerCtxt.getPayload(),
+ FasterLookUpDataHolder.getInstance()
+ .getCartridges()));
+
+ if(subjectedSerCtxt.getCartridge() == null){
+ return pendingInstanceCount;
+ }
+
+ List<IaasProvider> iaases = subjectedSerCtxt.getCartridge().getIaases();
+
+ for (IaasProvider iaas : iaases) {
+
+ ComputeService computeService = iaas.getComputeService();
+
+ IaasContext ctxt = null;
+ if ((ctxt = subjectedSerCtxt.getIaasContext(iaas.getType())) == null) {
+ ctxt = subjectedSerCtxt.addIaasContext(iaas.getType());
+ }
+
+ // get list of node Ids which are belong to this domain- sub
+ // domain
+ List<String> nodeIds = ctxt.getNodeIds();
+
+ if (nodeIds.isEmpty()) {
+ log.debug("Zero nodes spawned in the IaaS " + iaas.getType() + " of domain: " +
+ domainName + " and sub domain: " + subDomainName);
+ continue;
+ }
+
+ // get all the nodes spawned by this IaasContext
+ Set<? extends ComputeMetadata> set = computeService.listNodes();
+
+ Iterator<? extends ComputeMetadata> iterator = set.iterator();
+
+ // traverse through all nodes of this ComputeService object
+ while (iterator.hasNext()) {
+ NodeMetadataImpl nodeMetadata = (NodeMetadataImpl) iterator.next();
+
+ // if this node belongs to the requested domain
+ if (nodeIds.contains(nodeMetadata.getId())) {
+
+ // get the status of the node
+ Status nodeStatus = nodeMetadata.getStatus();
+
+ // count nodes that are in pending state
+ if (nodeStatus.equals(Status.PENDING)) {
+ pendingInstanceCount++;
+ }
+ }
+
+ }
+ }
+ }
+
+ log.debug("Pending instance count of domain '" + domainName + "' and sub domain '" +
+ subDomainName + "' is " + pendingInstanceCount);
+
+ return pendingInstanceCount;
+
+ }
+
+
+ /**
+ * A helper method to terminate an instance.
+ */
+ private IaasProvider terminate(IaasProvider iaasTemp, IaasContext ctxt, String nodeId) {
+
+ // this is just to be safe
+ if (iaasTemp.getComputeService() == null) {
+ String msg = "Unexpeced error occured! IaasContext's ComputeService is null!";
+ log.error(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ // destroy the node
+ iaasTemp.getComputeService().destroyNode(nodeId);
+
+
+ String autoAssignIpProp =
+ iaasTemp.getProperty(CloudControllerConstants.AUTO_ASSIGN_IP_PROPERTY);
+
+ // release allocated IP address
+ if (autoAssignIpProp == null ||
+ (autoAssignIpProp != null && autoAssignIpProp.equals("false"))) {
+ // allocate an IP address - manual IP assigning mode
+ iaasTemp.getIaas().releaseAddress(iaasTemp, ctxt.getPublicIp(nodeId));
+ }
+
+ // remove the node id
+ ctxt.removeNodeId(nodeId);
+
+ ctxt.decrementCurrentInstanceCountByOne();
+
+ // publish data to BAM
+ CartridgeInstanceDataPublisherTask.publish();
+
+ log.info("Node with Id: '" + nodeId + "' is terminated!");
+ return iaasTemp;
+ }
+
+ private void logTermination(String nodeId, IaasContext ctxt, ServiceContext serviceCtxt) {
+
+ // get the ip of the terminated node
+ String ip = ctxt.getPublicIp(nodeId);
+ String ipProp = CloudControllerConstants.PUBLIC_IP_PROPERTY;
+ String ipStr = serviceCtxt.getProperty(ipProp);
+ StringBuilder newIpStr = new StringBuilder("");
+
+ for (String str : ipStr.split(CloudControllerConstants.ENTRY_SEPARATOR)) {
+ if (!str.equals(ip)) {
+ newIpStr.append(str + CloudControllerConstants.ENTRY_SEPARATOR);
+ }
+ }
+
+ // add this ip to the topology
+ serviceCtxt.setProperty(ipProp,
+ newIpStr.length() == 0
+ ? ""
+ : newIpStr.substring(0, newIpStr.length() - 1)
+ .toString());
+
+ // remove the reference
+ ctxt.removeNodeIdToPublicIp(nodeId);
+
+ // persist
+ persist();
+
+ // trigger topology consumers
+ List<ServiceContext> list = new ArrayList<ServiceContext>();
+ list.add(serviceCtxt);
+ try {
+ dataHolder.getSharedTopologyDiffQueue().put(list);
+ } catch (InterruptedException ignore) {
+ }
+
+ }
+
+ /**
+ * Comparator to compare {@link IaasProvider} on different attributes.
+ */
+ public enum IaasProviderComparator implements Comparator<IaasProvider> {
+ SCALE_UP_SORT {
+ public int compare(IaasProvider o1, IaasProvider o2) {
+ return Integer.valueOf(o1.getScaleUpOrder()).compareTo(o2.getScaleUpOrder());
+ }
+ },
+ SCALE_DOWN_SORT {
+ public int compare(IaasProvider o1, IaasProvider o2) {
+ return Integer.valueOf(o1.getScaleDownOrder()).compareTo(o2.getScaleDownOrder());
+ }
+ };
+
+ public static Comparator<IaasProvider> ascending(final Comparator<IaasProvider> other) {
+ return new Comparator<IaasProvider>() {
+ public int compare(IaasProvider o1, IaasProvider o2) {
+ return other.compare(o1, o2);
+ }
+ };
+ }
+
+ public static Comparator<IaasProvider> getComparator(final IaasProviderComparator... multipleOptions) {
+ return new Comparator<IaasProvider>() {
+ public int compare(IaasProvider o1, IaasProvider o2) {
+ for (IaasProviderComparator option : multipleOptions) {
+ int result = option.compare(o1, o2);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return 0;
+ }
+ };
+ }
+ }
+
+ @Override
+ public boolean registerService(String domain, String subDomain, String tenantRange,
+ String cartridgeType, String hostName, Properties properties, byte[] payload)
+ throws UnregisteredCartridgeException {
+
+ // create a ServiceContext dynamically
+ ServiceContext newServiceCtxt = new ServiceContext();
+ newServiceCtxt.setDomainName(domain);
+ newServiceCtxt.setSubDomainName(subDomain);
+ newServiceCtxt.setTenantRange(tenantRange);
+ newServiceCtxt.setHostName(hostName);
+
+ if (properties != null && properties.getProperties() != null ) {
+ // add properties
+ for (Property property : properties.getProperties()) {
+ if (property != null && property.getName() != null) {
+ newServiceCtxt.setProperty(property.getName(), property.getValue());
+ }
+ }
+ }
+
+ newServiceCtxt.setCartridgeType(cartridgeType);
+
+ for (Cartridge cartridge : FasterLookUpDataHolder.getInstance().getCartridges()) {
+ if (cartridge.getType().equals(cartridgeType)) {
+ newServiceCtxt.setCartridge(cartridge);
+ break;
+ }
+ }
+
+ if (newServiceCtxt.getCartridge() == null) {
+ String msg = "Registration failed - Unregistered Cartridge type: " + cartridgeType;
+ log.error(msg);
+ throw new UnregisteredCartridgeException(msg);
+ }
+
+ if (payload != null && payload.length != 0) {
+
+ // write payload file
+ try {
+ String uniqueName = domain + "-" + subDomain + ".txt";
+ FileUtils.forceMkdir(new File(CloudControllerConstants.PAYLOAD_DIR));
+ File payloadFile = new File(CloudControllerConstants.PAYLOAD_DIR + uniqueName);
+ FileUtils.writeByteArrayToFile(payloadFile, payload);
+ newServiceCtxt.setPayloadFile(payloadFile.getPath());
+
+ } catch (IOException e) {
+ String msg =
+ "Failed while persisting the payload of domain : " + domain +
+ ", sub domain : " + subDomain;
+ log.error(msg, e);
+ throw new CloudControllerException(msg, e);
+ }
+
+ } else {
+ log.debug("Payload is null or empty for :\n "+newServiceCtxt.toNode().toString());
+ }
+
+ // persist
+ try {
+ String uniqueName = domain + "-" + subDomain + "-" + UUID.randomUUID() + ".xml";
+ FileUtils.writeStringToFile(new File(CloudControllerConstants.SERVICES_DIR + uniqueName),
+ newServiceCtxt.toXml());
+ } catch (IOException e) {
+ String msg =
+ "Failed while persisting the service configuration - domain : " + domain +
+ ", sub domain : " + subDomain + ", tenant range: " + tenantRange +
+ ", cartridge type: " + cartridgeType;
+ log.error(msg, e);
+ throw new CloudControllerException(msg, e);
+ }
+
+ log.info("Service successfully registered! Domain - " + domain + ", Sub domain - " +
+ newServiceCtxt.getSubDomainName() + ", Cartridge type - " + cartridgeType);
+
+ return true;
+ }
+
+ @Override
+ public String[] getRegisteredCartridges() {
+ // get the list of cartridges registered
+ List<Cartridge> cartridges = FasterLookUpDataHolder.getInstance().getCartridges();
+
+ if (cartridges == null) {
+ return new String[0];
+ }
+
+ String[] cartridgeTypes = new String[cartridges.size()];
+ int i = 0;
+
+ for (Cartridge cartridge : cartridges) {
+ cartridgeTypes[i] = cartridge.getType();
+ i++;
+ }
+
+ return cartridgeTypes;
+ }
+
+ @Override
+ public boolean createKeyPairFromPublicKey(String cartridgeType, String keyPairName,
+ String publicKey) {
+
+ Cartridge cartridge = FasterLookUpDataHolder.getInstance().getCartridge(cartridgeType);
+
+ if (cartridge == null) {
+ String msg = "Invalid Cartridge type specified : " + cartridgeType;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ for (IaasProvider iaas : cartridge.getIaases()) {
+ String region = ComputeServiceBuilderUtil.extractRegion(iaas);
+
+ if (region == null) {
+ String msg =
+ "Cannot find a region to create the key pair. Please add a property called 'region' under IaaS '" +
+ iaas.getType() + "' of Cartridge - " + cartridgeType;
+ log.fatal(msg);
+ throw new CloudControllerException(msg);
+ }
+
+ return iaas.getIaas().createKeyPairFromPublicKey(iaas, region, keyPairName, publicKey);
+ }
+
+ return false;
+ }
+
+ private String checkSubDomain(String subDomainName) {
+ // if sub domain is null, we assume it as default one.
+ if (subDomainName == null || "null".equalsIgnoreCase(subDomainName)) {
+ subDomainName = Constants.DEFAULT_SUB_DOMAIN;
+ log.debug("Sub domain is null, hence using the default value : " + subDomainName);
+ }
+
+ return subDomainName;
+ }
+
+ @Override
+ public CartridgeInfo getCartridgeInfo(String cartridgeType)
+ throws UnregisteredCartridgeException {
+ Cartridge cartridge = FasterLookUpDataHolder.getInstance().getCartridge(cartridgeType);
+
+ if (cartridge != null) {
+
+ return CloudControllerUtil.toCartridgeInfo(cartridge);
+
+ }
+
+ String msg =
+ "Cannot find a Cartridge having a type of " + cartridgeType +
+ ". Hence unable to find information.";
+ log.error(msg);
+ throw new UnregisteredCartridgeException(msg);
+ }
+
+ @Override
+ public boolean unregisterService(String domain, String subDomain) throws UnregisteredServiceException {
+
+ subDomain = checkSubDomain(subDomain);
+
+ // find the service context
+ ServiceContext subjectedSerCtxt =
+ FasterLookUpDataHolder.getInstance()
+ .getServiceContext(domain,
+ subDomain);
+
+ if(subjectedSerCtxt == null){
+ throw new UnregisteredServiceException("No registered service found for domain: "+domain+" - sub domain: "+subDomain);
+ }
+
+ // get the service definition file.
+ File serviceDefFile = subjectedSerCtxt.getFile();
+
+ // delete that file, so that it gets automatically undeployed.
+ return serviceDefFile.delete();
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/e8c32dac/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/CloudControllerService.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/CloudControllerService.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/CloudControllerService.java
new file mode 100644
index 0000000..462afd9
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/CloudControllerService.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. 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.interfaces;
+
+import org.apache.stratos.cloud.controller.exception.UnregisteredServiceException;
+import org.apache.stratos.cloud.controller.util.CartridgeInfo;
+import org.apache.stratos.cloud.controller.util.Properties;
+import org.apache.stratos.lb.common.conf.util.Constants;
+import org.apache.stratos.cloud.controller.exception.UnregisteredCartridgeException;
+
+/**
+ * This Interface provides a way to communicate with underline
+ * Infrastructure which are supported by <i>JClouds</i>.
+ *
+ */
+public interface CloudControllerService {
+
+ /**
+ * Creates a key pair in all IaaSes that are configured for the given cartridge,
+ * having the given name and public key.
+ *
+ * <p/>
+ * <h4>Supported Formats</h4>
+ * <ul>
+ * <li>OpenSSH public key format (e.g., the format in ~/.ssh/authorized_keys)</li>
+ * <li>Base64 encoded DER format</li>
+ * <li>SSH public key file format as specified in RFC4716</li>
+ * </ul>
+ * DSA keys are not supported. Make sure your key generator is set up to create RSA keys.
+ * <p/>
+ * Supported lengths: 1024, 2048, and 4096.
+ * <p/>
+ *
+ * @param cartridgeType
+ * type of the cartridge. Note this cartridge type should be already
+ * registered one.
+ * @param keyPairName
+ * name of the key pair which is going to get created in IaaSes.
+ * @param publicKey
+ * The public key.
+ *
+ */
+ @Deprecated
+ public boolean createKeyPairFromPublicKey(String cartridgeType, String keyPairName,
+ String publicKey);
+
+ /**
+ * This method will return the information regarding the given cartridge, if present.
+ * Else this will return <code>null</code>.
+ *
+ * @param cartridgeType
+ * type of the cartridge.
+ * @return {@link org.apache.stratos.cloud.controller.util.CartridgeInfo} of the given cartridge type or <code>null</code>.
+ * @throws UnregisteredCartridgeException if there is no registered cartridge with this type.
+ */
+ public CartridgeInfo getCartridgeInfo(String cartridgeType) throws UnregisteredCartridgeException;
+
+ /**
+ * Calling this method will result in returning the pending instances
+ * count of a particular domain.
+ *
+ * @param domainName
+ * service cluster domain
+ * @param sudDomainName
+ * service clustering sub domain of the instance to be started up.
+ * If this is null, the default value will be used. Default value is
+ * {@link Constants}.DEFAULT_SUB_DOMAIN.
+ * @return number of pending instances for this domain. If no instances of this
+ * domain is present, this will return zero.
+ */
+ public int getPendingInstanceCount(String domainName, String subDomainName);
+
+ /**
+ * Calling this method will result in returning the types of {@link org.apache.stratos.cloud.controller.util.Cartridge}s
+ * registered in Cloud Controller.
+ *
+ * @return String array containing types of registered {@link org.apache.stratos.cloud.controller.util.Cartridge}s.
+ */
+ public String[] getRegisteredCartridges();
+
+ /**
+ * <p>
+ * Registers the details of a newly created service cluster. This will override an already
+ * present service cluster, if there is any. A service cluster is uniquely identified by its
+ * domain and sub domain combination.
+ * </p>
+ * @param domain
+ * service cluster domain
+ * @param subDomain
+ * service cluster sub domain
+ * @param tenantRange
+ * tenant range eg: '1-10' or '2'
+ * @param cartridgeType
+ * cartridge type of the new service. This should be an already registered cartridge
+ * type.
+ * @param hostName
+ * host name of this service instance
+ * @param properties
+ * Set of properties related to this service definition.
+ * @param payload
+ * payload which will be passed to instance to be started. Payload shouldn't contain
+ * xml tags.
+ * @return whether the registration is successful or not.
+ *
+ * @throws UnregisteredCartridgeException
+ * when the cartridge type requested by this service is
+ * not a registered one.
+ */
+ public boolean registerService(String domain, String subDomain, String tenantRange, String cartridgeType,
+ String hostName, Properties properties, byte[] payload) throws UnregisteredCartridgeException;
+
+ /**
+ * Calling this method will result in an instance startup, which is belong
+ * to the provided service domain. Also note that the instance that is starting up
+ * belongs to the group whose name is derived from its service domain, replacing <i>.</i>
+ * by a hyphen (<i>-</i>).
+ *
+ * @param domainName
+ * service clustering domain of the instance to be started up.
+ * @param subDomainName
+ * service clustering sub domain of the instance to be started up.
+ * If this is null, the default value will be used. Default value is
+ * {@link Constants}.DEFAULT_SUB_DOMAIN.
+ * @return public IP which is associated with the newly started instance.
+ */
+ public String startInstance(String domainName, String subDomainName);
+
+ /**
+ * Calling this method will result in termination of all instances belong
+ * to the provided service domain and sub domain.
+ *
+ * @param domainName
+ * service domain of the instance to be terminated.
+ * @param sudDomainName
+ * service clustering sub domain of the instances to be terminated.
+ * If this is null, the default value will be used. Default value is
+ * {@link Constants}.DEFAULT_SUB_DOMAIN.
+ * @return whether an instance terminated successfully or not.
+ */
+ public boolean terminateAllInstances(String domainName, String subDomainName);
+
+ /**
+ * Calling this method will result in termination of an instance which is belong
+ * to the provided service domain and sub domain.
+ *
+ * @param domainName
+ * service domain of the instance to be terminated.
+ * @param sudDomainName
+ * service clustering sub domain of the instance to be terminated.
+ * If this is null, the default value will be used. Default value is
+ * {@link Constants}.DEFAULT_SUB_DOMAIN.
+ * @return whether an instance terminated successfully or not.
+ */
+ public boolean terminateInstance(String domainName, String subDomainName);
+
+ /**
+ * Calling this method will result in termination of the lastly spawned instance which is
+ * belong to the provided service domain and sub domain.
+ *
+ * @param domainName
+ * service domain of the instance to be terminated.
+ * @param sudDomainName
+ * service clustering sub domain of the instance to be terminated.
+ * If this is null, the default value will be used. Default value is
+ * {@link Constants}.DEFAULT_SUB_DOMAIN.
+ * @return whether the termination is successful or not.
+ */
+ public boolean terminateLastlySpawnedInstance(String domainName, String subDomainName);
+
+ /**
+ * Unregister the service cluster which represents by this domain and sub domain.
+ * @param domain service cluster domain
+ * @param subDomain service cluster sub domain
+ * @return whether the unregistration was successful or not.
+ * @throws org.apache.stratos.cloud.controller.exception.UnregisteredServiceException if the service cluster requested is not a registered one.
+ */
+ public boolean unregisterService(String domain, String subDomain) throws UnregisteredServiceException;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/e8c32dac/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/Iaas.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/Iaas.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/Iaas.java
new file mode 100644
index 0000000..ceb1bcb
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/interfaces/Iaas.java
@@ -0,0 +1,73 @@
+/*
+* Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. 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.interfaces;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.apache.stratos.cloud.controller.util.IaasProvider;
+
+/**
+ * All IaaSes that are going to support by Cloud Controller, should extend this abstract class.
+ */
+public abstract class Iaas {
+
+ /**
+ * This should build the {@link ComputeService} object and the {@link Template} object,
+ * using the information from {@link IaasProvider} and should set the built
+ * {@link ComputeService} object in the {@link IaasProvider#setComputeService(ComputeService)}
+ * and also should set the built {@link Template} object in the
+ * {@link IaasProvider#setTemplate(Template)}.
+ * @param iaasInfo corresponding {@link IaasProvider}
+ */
+ public abstract void buildComputeServiceAndTemplate(IaasProvider iaasInfo);
+
+ /**
+ * This method provides a way to set payload that can be obtained from {@link IaasProvider#getPayload()}
+ * in the {@link Template} of this IaaS.
+ * @param iaasInfo corresponding {@link IaasProvider}
+ */
+ public abstract void setDynamicPayload(IaasProvider iaasInfo);
+
+ /**
+ * This will obtain an IP address from the allocated list and associate that IP with this node.
+ * @param iaasInfo corresponding {@link IaasProvider}
+ * @param node Node to be associated with an IP.
+ * @return associated public IP.
+ */
+ public abstract String associateAddress(IaasProvider iaasInfo, NodeMetadata node);
+
+ /**
+ * This will deallocate/release the given IP address back to pool.
+ * @param iaasInfo corresponding {@link IaasProvider}
+ * @param ip public IP address to be released.
+ */
+ public abstract void releaseAddress(IaasProvider iaasInfo, String ip);
+
+ /**
+ * This method should create a Key Pair corresponds to a given public key in the respective region having the name given.
+ * Also should override the value of the key pair in the {@link Template} of this IaaS.
+ * @param iaasInfo {@link IaasProvider}
+ * @param region region that the key pair will get created.
+ * @param keyPairName name of the key pair. NOTE: Jclouds adds a prefix : <code>jclouds#</code>
+ * @param publicKey public key, from which the key pair will be created.
+ * @return whether the key pair creation is successful or not.
+ */
+ public abstract boolean createKeyPairFromPublicKey(IaasProvider iaasInfo, String region, String keyPairName, String publicKey);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/e8c32dac/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/internal/CloudControllerDSComponent.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/internal/CloudControllerDSComponent.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/internal/CloudControllerDSComponent.java
new file mode 100644
index 0000000..0152a75
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/internal/CloudControllerDSComponent.java
@@ -0,0 +1,85 @@
+package org.apache.stratos.cloud.controller.internal;
+
+import org.apache.stratos.cloud.controller.exception.CloudControllerException;
+import org.apache.stratos.cloud.controller.impl.CloudControllerServiceImpl;
+import org.apache.stratos.cloud.controller.interfaces.CloudControllerService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.wso2.carbon.ntask.core.service.TaskService;
+import org.wso2.carbon.registry.core.exceptions.RegistryException;
+import org.wso2.carbon.registry.core.service.RegistryService;
+import org.apache.stratos.cloud.controller.topic.ConfigurationPublisher;
+import org.apache.stratos.cloud.controller.util.DeclarativeServiceReferenceHolder;
+
+/**
+ * Registering Cloud Controller Service.
+ *
+ * @scr.component name="org.wso2.carbon.stratos.cloud.controller" immediate="true"
+ * @scr.reference name="ntask.component" interface="org.wso2.carbon.ntask.core.service.TaskService"
+ * cardinality="1..1" policy="dynamic" bind="setTaskService"
+ * unbind="unsetTaskService"
+ * @scr.reference name="registry.service"
+ * interface=
+ * "org.wso2.carbon.registry.core.service.RegistryService"
+ * cardinality="1..1" policy="dynamic" bind="setRegistryService"
+ * unbind="unsetRegistryService"
+ */
+public class CloudControllerDSComponent {
+
+ private static final Log log = LogFactory.getLog(CloudControllerDSComponent.class);
+
+ protected void activate(ComponentContext context) {
+ try {
+ if (DeclarativeServiceReferenceHolder.getInstance().getConfigPub() == null) {
+ DeclarativeServiceReferenceHolder.getInstance()
+ .setConfigPub(new ConfigurationPublisher());
+ }
+
+ BundleContext bundleContext = context.getBundleContext();
+ bundleContext.registerService(CloudControllerService.class.getName(),
+ new CloudControllerServiceImpl(), null);
+
+
+ log.debug("******* Cloud Controller Service bundle is activated ******* ");
+ } catch (Throwable e) {
+ log.error("******* Cloud Controller Service bundle is failed to activate ****", e);
+ }
+ }
+
+ protected void setTaskService(TaskService taskService) {
+ if (log.isDebugEnabled()) {
+ log.debug("Setting the Task Service");
+ }
+ DeclarativeServiceReferenceHolder.getInstance().setTaskService(taskService);
+ }
+
+ protected void unsetTaskService(TaskService taskService) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unsetting the Task Service");
+ }
+ DeclarativeServiceReferenceHolder.getInstance().setTaskService(null);
+ }
+
+ protected void setRegistryService(RegistryService registryService) {
+ if (log.isDebugEnabled()) {
+ log.debug("Setting the Registry Service");
+ }
+ try {
+ DeclarativeServiceReferenceHolder.getInstance()
+ .setRegistry(registryService.getGovernanceSystemRegistry());
+ } catch (RegistryException e) {
+ String msg = "Failed when retrieving Governance System Registry.";
+ log.error(msg, e);
+ throw new CloudControllerException(msg, e);
+ }
+ }
+
+ protected void unsetRegistryService(RegistryService registryService) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unsetting the Registry Service");
+ }
+ DeclarativeServiceReferenceHolder.getInstance().setRegistry(null);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/e8c32dac/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/jcloud/ComputeServiceBuilderUtil.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/jcloud/ComputeServiceBuilderUtil.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/jcloud/ComputeServiceBuilderUtil.java
new file mode 100644
index 0000000..e80f949
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/jcloud/ComputeServiceBuilderUtil.java
@@ -0,0 +1,182 @@
+/*
+* Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. 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.jcloud;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.stratos.cloud.controller.util.CloudControllerConstants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.synapse.SynapseException;
+import org.jclouds.ContextBuilder;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.enterprise.config.EnterpriseConfigurationModule;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.apache.stratos.cloud.controller.util.IaasProvider;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * This class is responsible for creating a JClouds specific ComputeService object.
+ */
+public class ComputeServiceBuilderUtil {
+
+ private static final Log log = LogFactory.getLog(ComputeServiceBuilderUtil.class);
+
+ public static byte[] getUserData(String payloadFileName) {
+ // String userData = null;
+ byte[] bytes = null;
+ try {
+ File file = new File(payloadFileName);
+ if (!file.exists()) {
+ handleException("Payload file " + payloadFileName + " does not exist");
+ }
+ if (!file.canRead()) {
+ handleException("Payload file " + payloadFileName + " does cannot be read");
+ }
+ bytes = getBytesFromFile(file);
+
+ } catch (IOException e) {
+ handleException("Cannot read data from payload file " + payloadFileName, e);
+ }
+ return bytes;
+ }
+
+
+ public static void buildDefaultComputeService(IaasProvider iaas) {
+
+ Properties properties = new Properties();
+
+ // load properties
+ for (Map.Entry<String, String> entry : iaas.getProperties().entrySet()) {
+ properties.put(entry.getKey(), entry.getValue());
+ }
+
+ // set modules
+ Iterable<Module> modules =
+ ImmutableSet.<Module> of(new SshjSshClientModule(), new SLF4JLoggingModule(),
+ new EnterpriseConfigurationModule());
+
+ // build context
+ ContextBuilder builder =
+ ContextBuilder.newBuilder(iaas.getProvider())
+ .credentials(iaas.getIdentity(), iaas.getCredential()).modules(modules)
+ .overrides(properties);
+
+ // set the compute service object
+ iaas.setComputeService(builder.buildView(ComputeServiceContext.class).getComputeService());
+ }
+
+ public static String extractRegion(IaasProvider iaas) {
+ String region;
+ // try to find region
+ if ((region = iaas.getProperty(CloudControllerConstants.REGION_PROPERTY)) == null) {
+ // if the property, isn't specified, try to obtain from the image id
+ // image id can be in following format - {region}/{UUID}
+ region = iaas.getImage().contains("/") ? iaas.getImage().split("/")[0] : null;
+ }
+
+ return region;
+ }
+
+ /** Returns the contents of the file in a byte array
+ *
+ * @param file
+ * - Input File
+ * @return Bytes from the file
+ * @throws java.io.IOException
+ * , if retrieving the file contents failed.
+ */
+ public static byte[] getBytesFromFile(File file) throws IOException {
+ if (!file.exists()) {
+ log.error("Payload file " + file.getAbsolutePath() + " does not exist");
+ return null;
+ }
+ InputStream is = new FileInputStream(file);
+ byte[] bytes;
+
+ try {
+ // Get the size of the file
+ long length = file.length();
+
+ // You cannot create an array using a long type.
+ // It needs to be an int type.
+ // Before converting to an int type, check
+ // to ensure that file is not larger than Integer.MAX_VALUE.
+ if (length > Integer.MAX_VALUE) {
+ if (log.isDebugEnabled()) {
+ log.debug("File is too large");
+ }
+ }
+
+ // Create the byte array to hold the data
+ bytes = new byte[(int) length];
+
+ // Read in the bytes
+ int offset = 0;
+ int numRead;
+ while (offset < bytes.length &&
+ (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException("Could not completely read file " + file.getName());
+ }
+ } finally {
+ // Close the input stream and return bytes
+ is.close();
+ }
+
+ return bytes;
+ }
+
+ /**
+ * handles the exception
+ *
+ * @param msg
+ * exception message
+ */
+ private static void handleException(String msg) {
+ log.error(msg);
+ throw new SynapseException(msg);
+ }
+
+ /**
+ * handles the exception
+ *
+ * @param msg
+ * exception message
+ * @param e
+ * exception
+ */
+ private static void handleException(String msg, Exception e) {
+ log.error(msg, e);
+ throw new SynapseException(msg, e);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/e8c32dac/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Deserializer.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Deserializer.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Deserializer.java
new file mode 100644
index 0000000..bafddb7
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Deserializer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. 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.persist;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class Deserializer {
+
+ private static final Log log = LogFactory.getLog(Deserializer.class);
+
+ /**
+ * We deserialize only if the path to the serialized object file is exists.
+ * @param filePath path to the serialized object file
+ * @return the object obtained after deserialization or null if file isn't valid.
+ * @throws Exception
+ */
+ public static Object deserialize(String filePath) throws Exception {
+
+ ObjectInputStream objIn = null;
+ Object obj = null;
+
+ if(!new File(filePath).isFile()){
+ return obj;
+ }
+
+ try {
+
+ objIn = new ObjectInputStream(new FileInputStream(filePath));
+ obj = objIn.readObject();
+
+ } catch (IOException e) {
+ log.error("Failed to deserialize the file at "+filePath , e);
+ throw e;
+
+ } catch (ClassNotFoundException e) {
+ log.error("Failed to deserialize the file at "+filePath , e);
+ throw e;
+
+ } finally{
+ objIn.close();
+ }
+
+ return obj;
+
+ }
+
+ /**
+ * Deserialize a byte array and retrieve the object.
+ * @param bytes bytes to be deserialized
+ * @return the deserialized {@link Object}
+ * @throws Exception if the deserialization is failed.
+ */
+ public static Object deserializeFromByteArray(byte[] bytes) throws Exception {
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ ObjectInput in = null;
+ try {
+ in = new ObjectInputStream(bis);
+ Object o = in.readObject();
+
+ return o;
+
+ } finally {
+ bis.close();
+ in.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/e8c32dac/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Serializer.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Serializer.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Serializer.java
new file mode 100644
index 0000000..9ce69cb
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/persist/Serializer.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. 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.persist;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+
+import org.apache.stratos.cloud.controller.runtime.FasterLookUpDataHolder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class Serializer {
+
+ private static final Log log = LogFactory.getLog(Serializer.class);
+
+ public static void serializeToFile(Object serializableObj, String filePath) throws IOException {
+
+ File outFile = new File(filePath);
+ ObjectOutput ObjOut = null;
+
+ try {
+
+ if(outFile.createNewFile()){
+ log.debug("Serialization file is created at "+filePath);
+ } else{
+ log.debug("Serialization file is already existing at "+filePath);
+ }
+
+ ObjOut = new ObjectOutputStream(new FileOutputStream(outFile));
+ ObjOut.writeObject(serializableObj);
+
+ } catch (IOException e) {
+ log.error("Failed to serialize the object "+serializableObj.toString()
+ + " to file "+filePath , e);
+ throw e;
+
+ } finally{
+ ObjOut.close();
+ }
+
+ }
+
+ /**
+ * Serialize a {@link org.apache.stratos.cloud.controller.runtime.FasterLookUpDataHolder} to a byte array.
+ * @param serializableObj
+ * @return byte[]
+ * @throws IOException
+ */
+ public static byte[] serializeToByteArray(FasterLookUpDataHolder serializableObj) throws IOException {
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutput out = null;
+ try {
+ out = new ObjectOutputStream(bos);
+ out.writeObject(serializableObj);
+
+ return bos.toByteArray();
+
+ } finally {
+ out.close();
+ bos.close();
+ }
+
+ }
+
+}