Stratos developers,

I found an issue where defining an availability "zone" property in a partition has no affect on controlling the placement of a VM launched under openstack.

The code which builds the template (iaas.initialize) used by jclouds is executed only once before stratos appends the availability zone properties to the iaas datastructure.

The problem is in the buildIaas() call shown below:

https://github.com/apache/stratos/blob/92ff7e9b5800d578a37d6aa82551d60fbdd66529/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/openstack/OpenstackPartitionValidator.java


The issue also exists in the cloudstack, ec2, gce and docker variants of this 
function.

       @Override
            public IaasProvider validate(Partition partition, Properties 
properties) throws InvalidPartitionException {
                try {
                    // validate the existence of the zone and hosts properties.
                    if (properties.containsKey(Scope.region.toString())) {
                        String region = 
properties.getProperty(Scope.region.toString());

                        if (iaasProvider.getImage() != null && 
!iaasProvider.getImage().contains(region)) {

                            String msg = "Invalid partition detected, invalid 
region: [partition-id] " + partition.getId() +
                                    " [region] " + region;
                            log.error(msg);
                            throw new InvalidPartitionException(msg);
                        }

                        iaas.isValidRegion(region);

                        IaasProvider updatedIaasProvider = new 
IaasProvider(iaasProvider);
       *                Iaas updatedIaas = 
CloudControllerServiceUtil.buildIaas(updatedIaasProvider);*
       updatedIaas.setIaasProvider(updatedIaasProvider);

                        if (properties.containsKey(Scope.zone.toString())) {
                            String zone = 
properties.getProperty(Scope.zone.toString());
                            iaas.isValidZone(region, zone);

       
updatedIaasProvider.setProperty(CloudControllerConstants.AVAILABILITY_ZONE, 
zone);
       *                    updatedIaas = 
CloudControllerServiceUtil.buildIaas(updatedIaasProvider);*
       updatedIaas.setIaasProvider(updatedIaasProvider);
                        }

                        updateOtherProperties(updatedIaasProvider, properties);
                        return updatedIaasProvider;
                    } else {

                        return iaasProvider;
                    }
                } catch (Exception e) {
                    String msg = "Invalid partition detected: [partition-id] " 
+ partition.getId() + e.getMessage();
                    log.error(msg, e);
                    throw new InvalidPartitionException(msg, e);
                }
            }


            private void updateOtherProperties(IaasProvider updatedIaasProvider,
                                               Properties properties) {
                Iaas updatedIaas;
                try {
       *            updatedIaas = 
CloudControllerServiceUtil.buildIaas(updatedIaasProvider);*

                    for (Object property : properties.keySet()) {
                        if (property instanceof String) {
                            String key = (String) property;
                            updatedIaasProvider.setProperty(key,
                                    properties.getProperty(key));
                            if (log.isDebugEnabled()) {
                                log.debug("Added property " + key
                                        + " to the IaasProvider.");
                            }
                        }
                    }
       *            updatedIaas = 
CloudControllerServiceUtil.buildIaas(updatedIaasProvider);*
                    updatedIaas.setIaasProvider(updatedIaasProvider);
                } catch (InvalidIaasProviderException ignore) {
                }

            }



       buidIaas() calls getIaas() under the covers and only initializes the 
compute template the first time it is called.   buildIaas() is
       called a second time after the availability_zone property is set, and 
then a third/fourth time in updateOtherProperties().

       As show below,   getIaas() only calls iaas.initilize() the first time 
it's called.

           public class CloudControllerServiceUtil {

           ...
                public static Iaas buildIaas(IaasProvider iaasProvider) throws 
InvalidIaasProviderException {
                    return iaasProvider.getIaas();
                }
           ....

           public class IaasProvider implements Serializable {
           ....
                public Iaas getIaas() {
                    if (iaas == null) {
                        synchronized (IaasProvider.this) {
                            if (iaas == null) {
                                try {
                                    iaas = 
CloudControllerUtil.createIaasInstance(this);
                                    iaas.initialize();
                                } catch (InvalidIaasProviderException e) {
                                    throw new RuntimeException("Could not create 
IaaS instance", e);
                                }
                            }
                        }
                    }
                    return iaas;
                }
           ....

       I propose the attached diffs to define buildIaas() such that it forces 
the iaas datastructure to be reinitialized,  if this looks
       okay, I'll see about getting this pushed upstream.
       I've also validated this on my openstack setup.


       Regards,

       -Vanson

diff --git 
a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/domain/IaasProvider.java
 
b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/domain/IaasProvider.java
index f4d7173..cad774e 100644
--- 
a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/domain/IaasProvider.java
+++ 
b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/domain/IaasProvider.java
@@ -232,6 +232,15 @@ public class IaasProvider implements Serializable {
     }
 
 
+    public Iaas buildIaas() {
+        Iaas iaas = getIaas();
+       /** 
+        * Force iaas to be reinitialized each time this funciton is called
+        */ 
+        iaas.initialize();
+        return iaas;
+    }
+
     public byte[] getPayload() {
         return payload;
     }
diff --git 
a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java
 
b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java
index 37580eb..6533945 100644
--- 
a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java
+++ 
b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/services/impl/CloudControllerServiceUtil.java
@@ -45,7 +45,7 @@ public class CloudControllerServiceUtil {
     private static final Log log = 
LogFactory.getLog(CloudControllerServiceUtil.class);
 
     public static Iaas buildIaas(IaasProvider iaasProvider) throws 
InvalidIaasProviderException {
-        return iaasProvider.getIaas();
+        return iaasProvider.buildIaas();
     }
 
     /**

Reply via email to