Allows for lists in templateOptions

Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/638d3e9b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/638d3e9b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/638d3e9b

Branch: refs/heads/master
Commit: 638d3e9b732dc30aab720bbfe258678de0d61347
Parents: 42e9aad
Author: Martin Harris <[email protected]>
Authored: Tue May 12 15:33:24 2015 +0100
Committer: Richard Downer <[email protected]>
Committed: Thu May 28 17:27:34 2015 +0100

----------------------------------------------------------------------
 .../location/jclouds/JcloudsLocation.java       | 99 ++++++++++++--------
 .../location/jclouds/JcloudsLocationConfig.java |  4 +-
 ...ationTemplateOptionsCustomisersLiveTest.java | 27 +++++-
 3 files changed, 85 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/638d3e9b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index d0cc0ce..69cfea6 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -1039,7 +1039,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                             LOG.info("ignoring keyPair({}) in VM creation 
because not supported for cloud/type ({})", v, t);
                         }
                     }})
-             .put(AUTO_GENERATE_KEYPAIRS, new CustomizeTemplateOptions() {
+            .put(AUTO_GENERATE_KEYPAIRS, new CustomizeTemplateOptions() {
                     public void apply(TemplateOptions t, ConfigBag props, 
Object v) {
                         if (t instanceof NovaTemplateOptions) {
                             
((NovaTemplateOptions)t).generateKeyPair((Boolean)v);
@@ -1049,7 +1049,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                             LOG.info("ignoring auto-generate-keypairs({}) in 
VM creation because not supported for cloud/type ({})", v, t);
                         }
                     }})
-             .put(AUTO_CREATE_FLOATING_IPS, new CustomizeTemplateOptions() {
+            .put(AUTO_CREATE_FLOATING_IPS, new CustomizeTemplateOptions() {
                     public void apply(TemplateOptions t, ConfigBag props, 
Object v) {
                         if (t instanceof NovaTemplateOptions) {
                             
((NovaTemplateOptions)t).autoAssignFloatingIp((Boolean)v);
@@ -1057,7 +1057,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                             LOG.info("ignoring auto-generate-floating-ips({}) 
in VM creation because not supported for cloud/type ({})", v, t);
                         }
                     }})
-             .put(AUTO_ASSIGN_FLOATING_IP, new CustomizeTemplateOptions() {
+            .put(AUTO_ASSIGN_FLOATING_IP, new CustomizeTemplateOptions() {
                     public void apply(TemplateOptions t, ConfigBag props, 
Object v) {
                         if (t instanceof NovaTemplateOptions) {
                             
((NovaTemplateOptions)t).autoAssignFloatingIp((Boolean)v);
@@ -1067,11 +1067,11 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                             LOG.info("ignoring auto-assign-floating-ip({}) in 
VM creation because not supported for cloud/type ({})", v, t);
                         }
                     }})
-              .put(NETWORK_NAME, new CustomizeTemplateOptions() {
+            .put(NETWORK_NAME, new CustomizeTemplateOptions() {
                     public void apply(TemplateOptions t, ConfigBag props, 
Object v) {
                         t.networks((String)v);
                     }})
-              .put(DOMAIN_NAME, new CustomizeTemplateOptions() {
+            .put(DOMAIN_NAME, new CustomizeTemplateOptions() {
                     public void apply(TemplateOptions t, ConfigBag props, 
Object v) {
                         if (t instanceof SoftLayerTemplateOptions) {
                             
((SoftLayerTemplateOptions)t).domainName(TypeCoercions.coerce(v, String.class));
@@ -1079,42 +1079,59 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                             LOG.info("ignoring domain-name({}) in VM creation 
because not supported for cloud/type ({})", v, t);                            
                         }
                     }})
-              .put(TEMPLATE_OPTIONS, new CustomizeTemplateOptions() {
-                  @Override
-                  public void apply(TemplateOptions options, ConfigBag config, 
Object v) {
-                      if (v == null) return;
-                      @SuppressWarnings("unchecked") Map<String, String> 
optionsMap = (Map<String, String>) v;
-                      if (optionsMap.isEmpty()) return;
-
-                      Class<? extends TemplateOptions> clazz = 
options.getClass();
-                      Iterable<Method> methods = 
Arrays.asList(clazz.getMethods());
-                      for(final Map.Entry<String, String> option : 
optionsMap.entrySet()) {
-                          Optional<Method> methodOptional = 
Iterables.tryFind(methods, new Predicate<Method>() {
-                              @Override
-                              public boolean apply(@Nullable Method input) {
-                                  // Matches a method with the expected name, 
and a single parameter that TypeCoercions
-                                  // can coerce to
-                                  if (input == null) return false;
-                                  if 
(!input.getName().equals(option.getKey())) return false;
-                                  Type[] parameterTypes = 
input.getGenericParameterTypes();
-                                  return parameterTypes.length == 1
-                                          && 
TypeCoercions.tryCoerce(option.getValue(), 
TypeToken.of(parameterTypes[0])).isPresentAndNonNull();
-                              }
-                          });
-                          if(methodOptional.isPresent()) {
-                              try {
-                                  Method method = methodOptional.get();
-                                  method.invoke(options, 
TypeCoercions.coerce(option.getValue(), 
TypeToken.of(method.getGenericParameterTypes()[0])));
-                              } catch (IllegalAccessException e) {
-                                  throw Exceptions.propagate(e);
-                              } catch (InvocationTargetException e) {
-                                  throw Exceptions.propagate(e);
-                              }
-                          } else {
-                              LOG.warn("Ignoring request to set template 
option {} because this is not supported by {}", new Object[] { option.getKey(), 
clazz.getCanonicalName() });
-                          }
-                      }
-                  }
+            .put(TEMPLATE_OPTIONS, new CustomizeTemplateOptions() {
+                @Override
+                public void apply(TemplateOptions options, ConfigBag config, 
Object v) {
+                    if (v == null) return;
+                    @SuppressWarnings("unchecked") Map<String, Object> 
optionsMap = (Map<String, Object>) v;
+                    if (optionsMap.isEmpty()) return;
+
+                    Class<? extends TemplateOptions> clazz = 
options.getClass();
+                    Iterable<Method> methods = 
Arrays.asList(clazz.getMethods());
+                    for(final Map.Entry<String, Object> option : 
optionsMap.entrySet()) {
+                        Optional<Method> methodOptional = 
Iterables.tryFind(methods, new Predicate<Method>() {
+                            @Override
+                            public boolean apply(@Nullable Method input) {
+                                // Matches a method with the expected name, 
and a single parameter that TypeCoercions
+                                // can coerce to
+                                if (input == null) return false;
+                                if (!input.getName().equals(option.getKey())) 
return false;
+                                int numOptionParams = option.getValue() 
instanceof List ? ((List)option.getValue()).size() : 1;
+                                Type[] parameterTypes = 
input.getGenericParameterTypes();
+                                if (parameterTypes.length != numOptionParams) 
return false;
+                                if (numOptionParams == 1 && 
!(option.getValue() instanceof List) && parameterTypes.length == 1) {
+                                    return true;
+                                }
+                                for (int paramCount = 0; paramCount < 
numOptionParams; paramCount ++) {
+                                    if 
(!TypeCoercions.tryCoerce(((List)option.getValue()).get(paramCount),
+                                            
TypeToken.of(parameterTypes[paramCount])).isPresentAndNonNull()) return false;
+                                }
+                                return true;
+                            }
+                        });
+                        if(methodOptional.isPresent()) {
+                            try {
+                                Method method = methodOptional.get();
+                                if (option.getValue() instanceof List) {
+                                    List<Object> parameters = 
Lists.newArrayList();
+                                    int numOptionParams = 
((List)option.getValue()).size();
+                                    for (int paramCount = 0; paramCount < 
numOptionParams; paramCount++) {
+                                        
parameters.add(TypeCoercions.coerce(((List)option.getValue()).get(paramCount), 
TypeToken.of(method.getGenericParameterTypes()[paramCount])));
+                                    }
+                                    method.invoke(options, 
parameters.toArray());
+                                } else {
+                                    method.invoke(options, 
TypeCoercions.coerce(option.getValue(), 
TypeToken.of(method.getGenericParameterTypes()[0])));
+                                }
+                            } catch (IllegalAccessException e) {
+                                throw Exceptions.propagate(e);
+                            } catch (InvocationTargetException e) {
+                                throw Exceptions.propagate(e);
+                            }
+                        } else {
+                            LOG.warn("Ignoring request to set template option 
{} because this is not supported by {}", new Object[] { option.getKey(), 
clazz.getCanonicalName() });
+                        }
+                    }
+                }
               })
             .build();
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/638d3e9b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
index fb3e2ad..fcaa0a3 100644
--- 
a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
+++ 
b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
@@ -257,8 +257,8 @@ public interface JcloudsLocationConfig extends 
CloudLocationConfig {
             ComputeServiceRegistryImpl.INSTANCE);
     
     @SuppressWarnings("serial")
-    public static final ConfigKey<Map<String,String>> TEMPLATE_OPTIONS = 
ConfigKeys.newConfigKey(
-            new TypeToken<Map<String, String>>() {}, "templateOptions", 
"Additional jclouds template options");
+    public static final ConfigKey<Map<String,Object>> TEMPLATE_OPTIONS = 
ConfigKeys.newConfigKey(
+            new TypeToken<Map<String, Object>>() {}, "templateOptions", 
"Additional jclouds template options");
 
     // TODO
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/638d3e9b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
index f4c44a4..d22e134 100644
--- 
a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
+++ 
b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
@@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
 import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.ec2.domain.BlockDeviceMapping;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -44,6 +45,7 @@ import java.util.Map;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
 
 public class JcloudsLocationTemplateOptionsCustomisersLiveTest extends 
AbstractJcloudsLiveTest {
 
@@ -59,10 +61,10 @@ public class 
JcloudsLocationTemplateOptionsCustomisersLiveTest extends AbstractJ
     // Doesn't actually do much with the cloud, but jclouds requires identity 
and credential before it will work
     @Test(groups = "Live")
     public void testGeneralPurposeTemplateOptionCustomisation() throws 
Exception {
-        ConfigKey<Map<String, String>> key = 
JcloudsLocationConfig.TEMPLATE_OPTIONS;
+        ConfigKey<Map<String, Object>> key = 
JcloudsLocationConfig.TEMPLATE_OPTIONS;
 
         ConfigBag config = ConfigBag.newInstance()
-                .configure(key, ImmutableMap.of("iamInstanceProfileName", 
"helloworld"));
+                .configure(key, ImmutableMap.of("iamInstanceProfileName", 
(Object)"helloworld"));
         AWSEC2TemplateOptions templateOptions = 
jcloudsLocation.getComputeService().templateOptions().as(AWSEC2TemplateOptions.class);
 
         invokeCustomizeTemplateOptions(templateOptions, 
JcloudsLocationConfig.TEMPLATE_OPTIONS, config);
@@ -70,6 +72,27 @@ public class 
JcloudsLocationTemplateOptionsCustomisersLiveTest extends AbstractJ
         assertEquals(templateOptions.getIAMInstanceProfileName(), 
"helloworld");
     }
 
+    // Doesn't actually do much with the cloud, but jclouds requires identity 
and credential before it will work
+    @Test(groups = "Live")
+    public void testGeneralPurposeTemplateOptionCustomisationWithList() throws 
Exception {
+        ConfigKey<Map<String, Object>> key = 
JcloudsLocationConfig.TEMPLATE_OPTIONS;
+
+        ConfigBag config = ConfigBag.newInstance()
+                        .configure(key, ImmutableMap.of(
+                                "iamInstanceProfileName", (Object) 
"helloworld",
+                                "mapNewVolumeToDeviceName", (Object) 
ImmutableList.of("/dev/sda1/", 123, true)));
+        AWSEC2TemplateOptions templateOptions = 
jcloudsLocation.getComputeService().templateOptions().as(AWSEC2TemplateOptions.class);
+
+        invokeCustomizeTemplateOptions(templateOptions, 
JcloudsLocationConfig.TEMPLATE_OPTIONS, config);
+
+        assertEquals(templateOptions.getIAMInstanceProfileName(), 
"helloworld");
+        assertEquals(templateOptions.getBlockDeviceMappings().size(), 1);
+        BlockDeviceMapping blockDeviceMapping = 
templateOptions.getBlockDeviceMappings().iterator().next();
+        assertEquals(blockDeviceMapping.getDeviceName(), "/dev/sda1/");
+        assertEquals(blockDeviceMapping.getEbsVolumeSize(), (Integer)123);
+        assertTrue(blockDeviceMapping.getEbsDeleteOnTermination());
+    }
+
     /**
      * Invoke a specific template options customizer on a TemplateOptions 
instance.
      *

Reply via email to