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();
}
/**