Backporting cloudstack support to stratos 4.0.0
diff --git a/components/org.apache.stratos.cloud.controller/pom.xml b/components/org.apache.stratos.cloud.controller/pom.xml
index c551566..cb11ed0 100644
--- a/components/org.apache.stratos.cloud.controller/pom.xml
+++ b/components/org.apache.stratos.cloud.controller/pom.xml
@@ -184,6 +184,11 @@
 			<artifactId>jclouds-enterprise</artifactId>
 			<version>${jclouds.version}</version>
 		</dependency>
+        <dependency>
+            <groupId>org.apache.jclouds.api</groupId>
+            <artifactId>cloudstack</artifactId>
+            <version>${jclouds.version}</version>
+        </dependency>
 		<dependency>
 			<groupId>org.apache.stratos</groupId>
 			<artifactId>ec2</artifactId>
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/CloudStackIaas.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/CloudStackIaas.java
new file mode 100644
index 0000000..ddffd1f
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/CloudStackIaas.java
@@ -0,0 +1,542 @@
+package org.apache.stratos.cloud.controller.iaases;
+
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.cloud.controller.exception.CloudControllerException;
+import org.apache.stratos.cloud.controller.exception.InvalidHostException;
+import org.apache.stratos.cloud.controller.exception.InvalidRegionException;
+import org.apache.stratos.cloud.controller.exception.InvalidZoneException;
+import org.apache.stratos.cloud.controller.interfaces.Iaas;
+import org.apache.stratos.cloud.controller.jcloud.ComputeServiceBuilderUtil;
+import org.apache.stratos.cloud.controller.pojo.IaasProvider;
+import org.apache.stratos.cloud.controller.util.CloudControllerConstants;
+import org.apache.stratos.cloud.controller.validate.CloudStackPartitionValidator;
+import org.apache.stratos.cloud.controller.validate.interfaces.PartitionValidator;
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
+import org.jclouds.cloudstack.domain.*;
+import org.jclouds.cloudstack.features.VolumeApi;
+import org.jclouds.cloudstack.options.ListPublicIPAddressesOptions;
+import org.jclouds.cloudstack.options.ListZonesOptions;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Location;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeoutException;
+
+public class CloudStackIaas extends Iaas {
+
+    private static final Log log = LogFactory.getLog(CloudStackIaas.class);
+
+    public CloudStackIaas(IaasProvider iaasProvider) {
+        super(iaasProvider);
+    }
+
+    @Override
+    public void buildComputeServiceAndTemplate() {
+        // builds and sets Compute Service
+        ComputeServiceBuilderUtil.buildDefaultComputeService(getIaasProvider());
+        // builds and sets Template
+        buildTemplate();
+    }
+
+    @Override
+    public void buildTemplate() {
+
+        IaasProvider iaasInfo = getIaasProvider();
+
+        //if compute service is not available
+        if (iaasInfo.getComputeService() == null) {
+            String msg = "Compute service is null for IaaS provider: "
+                    + iaasInfo.getName();
+            log.error(msg);
+            throw new CloudControllerException(msg);
+        }
+
+        //create templateBuilder
+        TemplateBuilder templateBuilder = iaasInfo.getComputeService()
+                .templateBuilder();
+
+        //**SET PROPERTIES TO templateBuilder OBJECT**//
+
+        /**
+         * PROPERTY - 1
+         * set image id specified
+         */
+        templateBuilder.imageId(iaasInfo.getImage());
+
+        /**
+         *  PROPERTY-2
+         *  if user has specified a zone in cloud-controller.xml, set the zone into templateBuilder object
+         *  (user should provide the zone id for this, because zone name is not unique in cloudstack)
+         */
+        if (iaasInfo.getProperty(CloudControllerConstants.AVAILABILITY_ZONE) != null) {
+            Set<? extends Location> locations = iaasInfo.getComputeService().listAssignableLocations();
+            for (Location location : locations) {
+                if (location.getId().equals(iaasInfo.getProperty(CloudControllerConstants.AVAILABILITY_ZONE))) {
+                    //if the zone is valid set the zone to templateBuilder Object
+                    templateBuilder.locationId(location.getId());
+                    log.info("Zone has been set as " + iaasInfo.getProperty(CloudControllerConstants.AVAILABILITY_ZONE)
+                            + " with id: " + location.getId());
+                    break;
+                }
+            }
+        }
+
+        /**
+         * PROPERTY-3
+         * if user has specified an instance type in cloud-controller.xml, set the instance type into templateBuilder
+         * object.(service offering)
+         *Important:Specify the Service Offering type ID. Not the name. Because the name is not unique in cloudstack.
+         */
+        if (iaasInfo.getProperty(CloudControllerConstants.INSTANCE_TYPE) != null) {
+            templateBuilder.hardwareId(iaasInfo.getProperty(CloudControllerConstants.INSTANCE_TYPE));
+        }
+
+        //build the template
+        Template template = templateBuilder.build();
+
+        /**if you wish to auto assign IPs, instance spawning call should be
+         * blocking, but if you
+         * wish to assign IPs manually, it can be non-blocking.
+         * is auto-assign-ip mode or manual-assign-ip mode?
+         */
+        boolean blockUntilRunning = Boolean.parseBoolean(iaasInfo
+                .getProperty(CloudControllerConstants.AUTO_ASSIGN_IP));
+        template.getOptions().as(TemplateOptions.class)
+                .blockUntilRunning(blockUntilRunning);
+
+        // this is required in order to avoid creation of additional security
+        // groups by Jclouds.
+        template.getOptions().as(TemplateOptions.class)
+                .inboundPorts(new int[]{});
+
+
+        //**SET CLOUDSTACK SPECIFIC PROPERTIES TO TEMPLATE OBJECT**//
+
+        //set security group - If you are using basic zone
+        if (iaasInfo.getProperty(CloudControllerConstants.SECURITY_GROUP_IDS) != null) {
+            template.getOptions()
+                    .as(CloudStackTemplateOptions.class)
+                    .securityGroupIds(Arrays.asList(iaasInfo.getProperty(CloudControllerConstants.SECURITY_GROUP_IDS)
+                            .split(CloudControllerConstants.ENTRY_SEPARATOR)));
+        }
+
+
+        /**
+         * set network ID - If you are using advanced zone
+         * in cloudstack sometimes we get unautorized exception if we didn't specify the
+         * domain ID and user name
+         */
+        if (iaasInfo.getProperty(CloudControllerConstants.NETWORK_IDS) != null) {
+            template.getOptions()
+                    .as(CloudStackTemplateOptions.class)
+                    .networks(Arrays.asList(iaasInfo.getProperty(CloudControllerConstants.NETWORK_IDS)
+                            .split(CloudControllerConstants.ENTRY_SEPARATOR)));
+        }
+
+        //set user name
+        if (iaasInfo.getProperty(CloudControllerConstants.USER_NAME) != null) {
+            template.getOptions().as(CloudStackTemplateOptions.class)
+                    .account(iaasInfo.getProperty(CloudControllerConstants.USER_NAME));
+        }
+        //set domain ID
+        if (iaasInfo.getProperty(CloudControllerConstants.DOMAIN_ID) != null) {
+            template.getOptions().as(CloudStackTemplateOptions.class)
+                    .domainId(iaasInfo.getProperty(CloudControllerConstants.DOMAIN_ID));
+        }
+
+        /**
+         *Set key pair
+         * in cloudstack sometimes we get unauthorized exception if we didn't specify the
+         * domain ID and user name
+         */
+        if (iaasInfo.getProperty(CloudControllerConstants.KEY_PAIR) != null) {
+            template.getOptions().as(CloudStackTemplateOptions.class)
+                    .keyPair(iaasInfo.getProperty(CloudControllerConstants.KEY_PAIR));
+        }
+
+        // ability to define tags
+        if (iaasInfo.getProperty(CloudControllerConstants.TAGS) != null) {
+            template.getOptions()
+                    .as(CloudStackTemplateOptions.class)
+                    .tags(Arrays.asList(iaasInfo.getProperty(CloudControllerConstants.TAGS)
+                            .split(CloudControllerConstants.ENTRY_SEPARATOR)));
+        }
+        //set disk offering to the instance
+        if (iaasInfo.getProperty(CloudControllerConstants.DISK_OFFERING) != null) {
+            template.getOptions()
+                    .as(CloudStackTemplateOptions.class)
+                    .diskOfferingId(iaasInfo.getProperty(CloudControllerConstants.DISK_OFFERING));
+        }
+
+        // set Template
+        iaasInfo.setTemplate(template);
+    }
+
+    @Override
+    public void setDynamicPayload() {
+        IaasProvider iaasInfo = getIaasProvider();
+        if (iaasInfo.getTemplate() != null && iaasInfo.getPayload() != null) {
+            iaasInfo.getTemplate().getOptions().as(CloudStackTemplateOptions.class)
+                    .userMetadata(convertByteArrayToHashMap(iaasInfo.getPayload()));
+        }
+    }
+
+    /**
+     * IMPORTANT
+     * In cloudstack we can assign public IPs, if we are using an advanced zone only. If we are using a basic zone
+     * we cannot assign public ips.
+     * <p/>
+     * When we use an advanced zone, a public IP address will get automatically assigned to the vm. So we don't need
+     * to find an unallocated IP address and assign that address to the vm. If you are using a basic zone you cannot
+     * assign public IPs
+     * <p/>
+     * So  this method will find the IP that has been assigned to the vm and return it.
+     */
+    @Override
+    public String associateAddress(NodeMetadata node) {
+
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService().getContext();
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+        String ip = null;
+
+        // get all allocated IPs
+        ListPublicIPAddressesOptions listPublicIPAddressesOptions = new ListPublicIPAddressesOptions();
+        listPublicIPAddressesOptions.zoneId(iaasInfo.getProperty(CloudControllerConstants.AVAILABILITY_ZONE));
+
+        Set<PublicIPAddress> publicIPAddresses = cloudStackApi.getAddressApi()
+                .listPublicIPAddresses(listPublicIPAddressesOptions);
+
+        String id = node.getProviderId(); //vm ID
+
+        for (PublicIPAddress publicIPAddress : publicIPAddresses) {
+            if (publicIPAddress.getVirtualMachineId().equals(id)) { //check whether this instance has
+                // already got an public ip or not
+                ip = publicIPAddress.getIPAddress(); //A public ip has been successfully assigned to the vm
+                log.info("Successfully associated an IP address " + ip
+                        + " for node with id: " + node.getId());
+                break;
+            }
+
+        }
+
+        if (ip == null || ip.isEmpty()) { //IP has not been successfully assigned to VM(That means there are
+            //  no more IPs  available for the VM)
+            String msg = "No address associated for node with id: " + node.getId();
+            log.warn(msg);
+            throw new CloudControllerException(msg);
+        }
+
+        return ip;
+    }
+
+    @Override
+    public String associatePredefinedAddress(NodeMetadata node, String ip) {
+        return "";
+    }
+
+    @Override
+    public void releaseAddress(String ip) {
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService().getContext();
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+        cloudStackApi.getAddressApi().disassociateIPAddress(ip);
+    }
+
+    @Override
+    public boolean createKeyPairFromPublicKey(String region, String keyPairName, String publicKey) {
+
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService().getContext();
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+        SshKeyPair sshKeyPair = cloudStackApi.getSSHKeyPairApi().createSSHKeyPair(keyPairName);
+
+        if (sshKeyPair != null) {
+
+            iaasInfo.getTemplate().getOptions().as(CloudStackTemplateOptions.class)
+                    .keyPair(sshKeyPair.getName());
+
+            log.info("A key-pair is created successfully - Key Pair Name: " + sshKeyPair.getName());
+            return true;
+        }
+        log.error("Key-pair is unable to create");
+        return false;
+    }
+
+    @Override
+    public boolean isValidRegion(String region) throws InvalidRegionException {
+
+        IaasProvider iaasInfo = getIaasProvider();
+        //no such method in Jclouds cloudstack api
+        String msg = "Invalid region: " + region + " in the iaas: " + iaasInfo.getType();
+        log.error(msg);
+        throw new InvalidRegionException(msg);
+    }
+
+    @Override
+    public boolean isValidZone(String region, String zone) throws InvalidZoneException {
+
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService().getContext();
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+        ListZonesOptions listZonesOptions = new ListZonesOptions();
+        listZonesOptions.available(true);
+        Set<Zone> zoneSet = cloudStackApi.getZoneApi().listZones(listZonesOptions);
+
+        for (org.jclouds.cloudstack.domain.Zone configuredZone : zoneSet) {
+            if (configuredZone.getName().equalsIgnoreCase(zone)) {
+                return true;
+            }
+        }
+        String msg = "Invalid zone: " + zone + " in the iaas: " + iaasInfo.getType();
+        log.error(msg);
+        throw new InvalidZoneException(msg);
+    }
+
+    @Override
+    public boolean isValidHost(String zone, String host) throws InvalidHostException {
+
+        IaasProvider iaasInfo = getIaasProvider();
+        // there's no such method in jclouds cloustack api
+        String msg = "Invalid host: " + host + " in the zone: " + zone + " and of the iaas: " + iaasInfo.getType();
+        log.error(msg);
+        throw new InvalidHostException(msg);
+
+    }
+
+    @Override
+    public PartitionValidator getPartitionValidator() {
+        return new CloudStackPartitionValidator();
+    }
+
+    @Override
+    public String createVolume(int sizeGB) {
+
+        // Snapshot id is not there in IaaS.createVolume() method in stratos 4.0.0
+        String snapshotId = null;
+        //todo return volume ID if volume is created
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService()
+                .getContext();
+
+        String zone = ComputeServiceBuilderUtil.extractZone(iaasInfo);
+        String diskOfferingID = iaasInfo.getTemplate().getOptions().as(CloudStackTemplateOptions.class)
+                .getDiskOfferingId();
+        if (zone == null && diskOfferingID == null) {
+            log.error("Could not create a volume in the , [zone] : " + zone + " of Iaas : " + iaasInfo);
+            return null;
+        }
+
+        VolumeApi volumeApi = context.unwrapApi(CloudStackApi.class).getVolumeApi();
+
+        Volume volume;
+        if (StringUtils.isEmpty(snapshotId)) {
+            if (log.isInfoEnabled()) {
+                log.info("Creating a volume in the zone " + zone);
+            }
+
+            //cloudstack jcloud api does not return a volume object
+            volumeApi.createVolumeFromCustomDiskOfferingInZone(null, diskOfferingID, zone, sizeGB);
+
+            //  volume = blockStoreApi.createVolumeInAvailabilityZone(zone, sizeGB);
+        } else {
+            if (log.isInfoEnabled()) {
+                log.info("Creating a volume in the zone " + zone + " from the snapshot " + snapshotId);
+            }
+            volumeApi.createVolumeFromSnapshotInZone(null, diskOfferingID, zone);
+        }
+
+        return null;
+    }
+
+    @Override
+    public String attachVolume(String instanceId, String volumeId, String deviceName) {
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService()
+                .getContext();
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+
+        //get volume
+        org.jclouds.cloudstack.domain.Volume volume = cloudStackApi.getVolumeApi().getVolume(volumeId);
+
+        //get current volume state
+        Volume.State volumeState = volume.getState();
+
+        if (log.isDebugEnabled()) {
+            log.debug("Volume " + volumeId + " is in state " + volumeState);
+        }
+
+        //if volume is not available, not allocated or cannot use
+        //volume state ALLOCATED   means that volume has not been attached to any instance.
+
+        //TODO there is an error with logic.
+        if (!(volumeState == Volume.State.ALLOCATED || volumeState == Volume.State.CREATING
+                || volumeState == Volume.State.READY)) {
+            log.error(String.format("Volume %s can not be attached. Volume status is %s", volumeId, volumeState));
+        }
+
+        //check whether the account of volume and instance is same
+        if (!volume.getAccount().equals(cloudStackApi.getVirtualMachineApi()
+                .getVirtualMachine(instanceId).getAccount())) {
+            log.error(String.format("Volume %s can not be attached. Instance account and Volume account " +
+                    "are not the same ", volumeId));
+        }
+
+        boolean volumeBecameAvailable = false, volumeBecameAttached = false;
+
+        try {
+            if (volumeState == Volume.State.CREATING) {
+
+                volumeBecameAvailable = waitForStatus(volumeId, Volume.State.ALLOCATED, 5);
+
+            } else if (volumeState == Volume.State.READY) {
+                volumeBecameAvailable = true;
+            }
+
+        } catch (TimeoutException e) {
+            log.error("[Volume ID] " + volumeId + "did not become ALLOCATED within expected timeout");
+        }
+
+        //if volume state is 'ALLOCATED'
+        if (volumeBecameAvailable) {
+
+            //attach volume into instance
+            cloudStackApi.getVolumeApi().attachVolume(volumeId, instanceId);
+
+            try {
+                volumeBecameAttached = waitForStatus(volumeId, Volume.State.READY, 2);
+            } catch (TimeoutException e) {
+                log.error("[Volume ID] " + volumeId + "did not become READY within expected timeout");
+            }
+        }
+
+        try {
+            // waiting 5seconds till volumes are actually attached.
+            Thread.sleep(5000);
+        } catch (InterruptedException ignored) {
+
+        }
+
+        //If volume state is not 'READY'
+        if (!volumeBecameAttached) {
+            log.error(String.format("[Volume ID] %s attachment is called, but not yet became attached", volumeId));
+        }
+
+        log.info(String.format("Volume [id]: %s attachment for instance [id]: %s was successful [status]: Attaching." +
+                " of Iaas : %s", volumeId, instanceId, iaasInfo));
+
+        return "Attaching";
+
+    }
+
+    @Override
+    public void detachVolume(String instanceId, String volumeId) {
+
+
+        IaasProvider iaasInfo = getIaasProvider();
+
+        ComputeServiceContext context = iaasInfo.getComputeService()
+                .getContext();
+
+        if (log.isDebugEnabled()) {
+            log.debug(String.format("Starting to detach volume %s from the instance %s", volumeId, instanceId));
+        }
+
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+
+        cloudStackApi.getVolumeApi().detachVolume(volumeId);
+
+        try {
+            //TODO this is true only for newly created volumes
+            if (waitForStatus(volumeId, Volume.State.ALLOCATED, 5)) {
+                log.info(String.format("Detachment of Volume [id]: %s from instance [id]: %s was successful of Iaas : %s", volumeId, instanceId, iaasInfo));
+            }
+        } catch (TimeoutException e) {
+            log.error(String.format("Detachment of Volume [id]: %s from instance [id]: %s was unsuccessful. [volume Status] : %s", volumeId, instanceId, iaasInfo));
+        }
+
+    }
+
+    @Override
+    public void deleteVolume(String volumeId) {
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService()
+                .getContext();
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+        cloudStackApi.getVolumeApi().deleteVolume(volumeId);
+        log.info("Deletion of Volume [id]: " + volumeId + " was successful. "
+                + " of Iaas : " + iaasInfo);
+    }
+
+    @Override
+    public String getIaasDevice(String device) {//todo implement this method(auto generated method)
+        return null;
+    }
+
+    private boolean waitForStatus(String volumeId, Volume.State expectedStatus, int timeoutInMilliseconds) throws TimeoutException {
+        int timeout = 1000 * 60 * timeoutInMilliseconds;
+        long timout = System.currentTimeMillis() + timeout;
+
+        IaasProvider iaasInfo = getIaasProvider();
+        ComputeServiceContext context = iaasInfo.getComputeService().getContext();
+        CloudStackApi cloudStackApi = context.unwrapApi(CloudStackApi.class);
+
+        //get volume
+        org.jclouds.cloudstack.domain.Volume volume = cloudStackApi.getVolumeApi().getVolume(volumeId);
+
+        Volume.State volumeState = volume.getState();
+
+        while (volumeState != expectedStatus) {
+            try {
+                if (log.isDebugEnabled()) {
+                    log.debug(String.format("Volume %s is still NOT in %s. Current State=%s", volumeId, expectedStatus, volumeState));
+                }
+                if (volumeState == Volume.State.FAILED || volumeState == Volume.State.DESTROYED || volumeState == Volume.State.UNRECOGNIZED) {
+                    log.error("Volume " + volumeId + " is in state" + volumeState);
+                    return false;
+                }
+
+                Thread.sleep(1000);
+                volumeState = volume.getState();
+                if (System.currentTimeMillis() > timout) {
+                    throw new TimeoutException();
+                }
+            } catch (InterruptedException e) {
+                // Ignoring the exception
+            }
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(String.format("Volume %s status became %s", volumeId, expectedStatus));
+        }
+
+        return true;
+    }
+
+    private Map<String, String> convertByteArrayToHashMap(byte[] byteArray) {
+
+        Map<String, String> map = new HashMap<String, String>();
+
+        String stringFromByteArray = new String(byteArray);
+        String[] keyValuePairs = stringFromByteArray.split(",");
+
+        for (String keyValuePair : keyValuePairs) {
+            String[] keyValue = keyValuePair.split("=");
+            if (keyValue.length > 1) {
+                map.put(keyValue[0], keyValue[1]);
+            }
+        }
+
+        return map;
+    }
+}
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/util/CloudControllerConstants.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/util/CloudControllerConstants.java
index 3b81dc8..8df2767 100644
--- a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/util/CloudControllerConstants.java
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/util/CloudControllerConstants.java
@@ -258,4 +258,10 @@
     public static final String NETWORK_FIXED_IP = "fixedIp";
     public static final String NETWORK_PORT = "portUuid";
     public static final String NETWORK_UUID = "networkUuid";
+
+    // CloudStack specific
+    public static final String USER_NAME = "username";
+    public static final String DOMAIN_ID = "domainId";
+    public static final String DISK_OFFERING = "diskOffering";
+    public static final String NETWORK_IDS= "networkIds";
 }
diff --git a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/validate/CloudstackPartitionValidator.java b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/validate/CloudstackPartitionValidator.java
new file mode 100644
index 0000000..4f3fbce
--- /dev/null
+++ b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/validate/CloudstackPartitionValidator.java
@@ -0,0 +1,53 @@
+package org.apache.stratos.cloud.controller.validate;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.cloud.controller.exception.InvalidPartitionException;
+import org.apache.stratos.cloud.controller.interfaces.Iaas;
+import org.apache.stratos.cloud.controller.pojo.IaasProvider;
+import org.apache.stratos.cloud.controller.util.CloudControllerConstants;
+import org.apache.stratos.cloud.controller.util.CloudControllerUtil;
+import org.apache.stratos.cloud.controller.validate.interfaces.PartitionValidator;
+import org.apache.stratos.messaging.domain.topology.Scope;
+
+import java.util.Properties;
+
+
+public class CloudStackPartitionValidator implements PartitionValidator {
+
+
+    private static final Log log = LogFactory.getLog(AWSEC2PartitionValidator.class);
+    private IaasProvider iaasProvider;
+    private Iaas iaas;
+
+
+    @Override
+    public void setIaasProvider(IaasProvider iaas) {
+        this.iaasProvider = iaas;
+        this.iaas = iaas.getIaas();
+    }
+
+    @Override
+    public IaasProvider validate(String partitionId, Properties properties) throws InvalidPartitionException {
+
+        try {
+            IaasProvider updatedIaasProvider = new IaasProvider(iaasProvider);
+            Iaas updatedIaas = CloudControllerUtil.getIaas(updatedIaasProvider);
+            updatedIaas.setIaasProvider(updatedIaasProvider);
+
+            if (properties.containsKey(Scope.zone.toString())) {
+                String zone = properties.getProperty(Scope.zone.toString());
+                iaas.isValidZone(null, zone);
+                updatedIaasProvider.setProperty(CloudControllerConstants.AVAILABILITY_ZONE, zone);
+                updatedIaas = CloudControllerUtil.getIaas(updatedIaasProvider);
+                updatedIaas.setIaasProvider(updatedIaasProvider);
+            }
+
+    } catch (Exception ex) {
+        String msg = "Invalid Partition Detected : "+partitionId+". Cause: "+ex.getMessage();
+        log.error(msg, ex);
+        throw new InvalidPartitionException(msg, ex);
+    }
+        return iaasProvider;
+    }
+}
diff --git a/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml b/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml
index 40d9775..208daff 100644
--- a/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml
+++ b/features/cloud-controller/org.apache.stratos.cloud.controller.feature/pom.xml
@@ -88,7 +88,11 @@
            <artifactId>openstack-nova</artifactId>
            <version>1.7.1-stratos</version>
          </dependency>
-         
+         <dependency>
+            <groupId>org.apache.jclouds.api</groupId>
+            <artifactId>cloudstack</artifactId>
+            <version>${jclouds.version}</version>
+         </dependency>
          <dependency>
            <groupId>org.apache.jclouds.api</groupId>
            <artifactId>openstack-keystone</artifactId>
@@ -232,6 +236,7 @@
                                 <bundleDef>org.apache.stratos:ec2:1.7.1-stratos</bundleDef>
                                 <bundleDef>org.apache.stratos:openstack-nova:1.7.1-stratos</bundleDef>
                                 <bundleDef>org.apache.stratos:vcloud:1.7.1-stratos</bundleDef>
+                                <bundleDef>org.apache.jclouds.api:cloudstack:${jclouds.version}</bundleDef>
                                 <bundleDef>com.jamesmurty.utils.wso2:java-xmlbuilder:0.4.wso2v1</bundleDef>
                                 <bundleDef>org.apache.jclouds.common:openstack-common:${jclouds.version}</bundleDef>
                                 <bundleDef>org.apache.jclouds.api:openstack-keystone:${jclouds.version}</bundleDef>
diff --git a/features/cloud-controller/org.apache.stratos.cloud.controller.feature/src/main/resources/conf/cloud-controller.xml b/features/cloud-controller/org.apache.stratos.cloud.controller.feature/src/main/resources/conf/cloud-controller.xml
index 24ff621..e6ab96a 100644
--- a/features/cloud-controller/org.apache.stratos.cloud.controller.feature/src/main/resources/conf/cloud-controller.xml
+++ b/features/cloud-controller/org.apache.stratos.cloud.controller.feature/src/main/resources/conf/cloud-controller.xml
@@ -16,62 +16,79 @@
   #  KIND, either express or implied.  See the License for the
   #  specific language governing permissions and limitations
   #  under the License.
-  --> 
+  -->
 <cloudController xmlns:svns="http://org.wso2.securevault/configuration">
 
-	<svns:secureVault
-		provider="org.wso2.securevault.secret.handler.SecretManagerSecretCallbackHandler" />
+    <svns:secureVault
+            provider="org.wso2.securevault.secret.handler.SecretManagerSecretCallbackHandler"/>
 
-    	<dataPublisher enable="false">
-		<!-- BAM Server Info - default values are 'admin' and 'admin' 
-			 Optional element. -->
-		<bamServer>
-            	<!-- BAM server URL should be specified in carbon.xml -->
-			<adminUserName>admin</adminUserName>
-			<adminPassword svns:secretAlias="cloud.controller.bam.server.admin.password">admin</adminPassword>
-		</bamServer>
-		<!-- Default cron expression is '1 * * * * ? *' meaning 'first second of every minute'.
-			 Optional element. -->
-		<cron>1 * * * * ? *</cron>
-		<!-- Cassandra cluster related info -->
-		<!--cassandraInfo>
-			<connectionUrl>localhost:9160</connectionUrl>
-			<userName>admin</userName>
-			<password svns:secretAlias="cloud.controller.cassandra.server.password">admin</password>
-		</cassandraInfo-->
-	</dataPublisher>
+    <dataPublisher enable="false">
+        <!-- BAM Server Info - default values are 'admin' and 'admin'
+             Optional element. -->
+        <bamServer>
+            <!-- BAM server URL should be specified in carbon.xml -->
+            <adminUserName>admin</adminUserName>
+            <adminPassword svns:secretAlias="cloud.controller.bam.server.admin.password">admin</adminPassword>
+        </bamServer>
+        <!-- Default cron expression is '1 * * * * ? *' meaning 'first second of every minute'.
+             Optional element. -->
+        <cron>1 * * * * ? *</cron>
+        <!-- Cassandra cluster related info -->
+        <!--cassandraInfo>
+            <connectionUrl>localhost:9160</connectionUrl>
+            <userName>admin</userName>
+            <password svns:secretAlias="cloud.controller.cassandra.server.password">admin</password>
+        </cassandraInfo-->
+    </dataPublisher>
 
-    	<topologySync enable="true">
-		<property name="cron" value="1 * * * * ? *" />
-	</topologySync>	
+    <topologySync enable="true">
+        <property name="cron" value="1 * * * * ? *"/>
+    </topologySync>
 
-	<!-- Specify the properties that are common to an IaaS here. This element 
-		is not necessary [0..1]. But you can use this section to avoid specifying 
-		same property over and over again. -->
-	<iaasProviders>
-        	<!--iaasProvider type="ec2" name="ec2 specific details">
-            		<className>org.apache.stratos.cloud.controller.iaases.AWSEC2Iaas</className>
-			<provider>aws-ec2</provider>
-			<identity svns:secretAlias="cloud.controller.ec2.identity">dhsaghfdal</identity>
-			<credential svns:secretAlias="cloud.controller.ec2.credential">jdkjaskd</credential>
-			<scaleUpOrder>1</scaleUpOrder>
-			<scaleDownOrder>2</scaleDownOrder>
-			<property name="jclouds.ec2.ami-query" value="owner-id=XX-XX-XX;state=available;image-type=machine"/>
-            		<property name="availabilityZone" value="us-east-1c"/>
-			<property name="securityGroups" value="manager,cep,mb,default"/>
-            		<property name="instanceType" value="m1.large"/>
-            		<property name="keyPair" value="nirmal-key"/>
-		</iaasProvider-->
-		<iaasProvider type="openstack" name="openstack specific details">
-            		<className>org.apache.stratos.cloud.controller.iaases.OpenstackNovaIaas</className>
-			<provider>openstack-nova</provider>
-			<identity svns:secretAlias="cloud.controller.openstack.identity">demo:demo</identity>
-			<credential svns:secretAlias="cloud.controller.openstack.credential">openstack</credential>
-			<property name="jclouds.endpoint" value="http://192.168.16.20:5000/" />
-           		<property name="jclouds.openstack-nova.auto-create-floating-ips" value="false"/>
-			<property name="jclouds.api-version" value="2.0/" />
-			<property name="X" value="x" />
-			<property name="Y" value="y" />
-		</iaasProvider>
-	</iaasProviders>
+    <!-- Specify the properties that are common to an IaaS here. This element
+        is not necessary [0..1]. But you can use this section to avoid specifying
+        same property over and over again. -->
+    <iaasProviders>
+        <!--iaasProvider type="ec2" name="ec2 specific details">
+                <className>org.apache.stratos.cloud.controller.iaases.AWSEC2Iaas</className>
+        <provider>aws-ec2</provider>
+        <identity svns:secretAlias="cloud.controller.ec2.identity">dhsaghfdal</identity>
+        <credential svns:secretAlias="cloud.controller.ec2.credential">jdkjaskd</credential>
+        <scaleUpOrder>1</scaleUpOrder>
+        <scaleDownOrder>2</scaleDownOrder>
+        <property name="jclouds.ec2.ami-query" value="owner-id=XX-XX-XX;state=available;image-type=machine"/>
+                <property name="availabilityZone" value="us-east-1c"/>
+        <property name="securityGroups" value="manager,cep,mb,default"/>
+                <property name="instanceType" value="m1.large"/>
+                <property name="keyPair" value="nirmal-key"/>
+    </iaasProvider-->
+        <iaasProvider type="openstack" name="openstack specific details">
+            <className>org.apache.stratos.cloud.controller.iaases.OpenstackNovaIaas</className>
+            <provider>openstack-nova</provider>
+            <identity svns:secretAlias="cloud.controller.openstack.identity">demo:demo</identity>
+            <credential svns:secretAlias="cloud.controller.openstack.credential">openstack</credential>
+            <property name="jclouds.endpoint" value="http://192.168.16.20:5000/"/>
+            <property name="jclouds.openstack-nova.auto-create-floating-ips" value="false"/>
+            <property name="jclouds.api-version" value="2.0/"/>
+            <property name="X" value="x"/>
+            <property name="Y" value="y"/>
+        </iaasProvider>
+        <!-- iaasProvider type="cloudstack" name="cloudstack specific details">
+            <className>org.apache.stratos.cloud.controller.iaases.CloudstackIaas</className>
+            <provider>cloudstack</provider>
+            <identity svns:secretAlias="cloud.controller.cloudstack.identity">api-key</identity>
+            <credential svns:secretAlias="cloud.controller.cloudstack.credential">secret-key</credential>
+            <property name="jclouds.endpoint" value="ip:port"/>
+            <property name="availabilityZone" value="zone_Id"/>
+            <property name="instanceType" value="instance_type_Id"/>
+            <property name="securityGroupIds" value="security_group_Id1,security_group_id2"/>
+            <property name="networkIds" value="network_Id1,network_Id2"/>
+            <property name="diskOffering" value="disk_offering_Id"/>
+            <property name="username" value="username"/>
+            <property name="domainId" value="domainId"/>
+            <property name="keyPair" value="asanka-key"/>
+            <property name="tags" value="tag1,tag2,tag3"/>
+            <property name="autoAssignIp" value="false"/>
+        </iaasProvider -->
+    </iaasProviders>
 </cloudController>