brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rich...@apache.org
Subject [1/2] incubator-brooklyn git commit: JcloudsLocation set arbitrary template options
Date Wed, 28 Jan 2015 15:44:47 GMT
Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master ec7448947 -> ecc62b040


JcloudsLocation set arbitrary template options

Adds new config key for JcloudsLocation, templateOptions, that takes a
Map<String,String> for setting arbitrary template options. For each
entry, searches for a method with the same name as the key, with a
single parameter that TypeCoercions supports. The method is then invoked
with the value. If such a method cannot be found, then a warning is
printed to the log.

The config key's value can be expressed as a YAML fragment in blueprints
or in brooklyn.properties:

```properties
brooklyn.location.named.softlayer-ams01.templateOptions={ domainName: 'example.com' }
```

```yaml
location:
  jclouds:softlayer:ams01:
    templateOptions:
      domainName: 'example.com'
```


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

Branch: refs/heads/master
Commit: 22d127b283c0e72336f8d29ed244d238e482d4ac
Parents: ec74489
Author: Richard Downer <richard@apache.org>
Authored: Wed Jan 21 12:41:22 2015 +0000
Committer: Richard Downer <richard@apache.org>
Committed: Wed Jan 28 13:20:52 2015 +0000

----------------------------------------------------------------------
 .../location/jclouds/JcloudsLocation.java       | 45 ++++++++-
 .../location/jclouds/JcloudsLocationConfig.java |  4 +
 ...ationTemplateOptionsCustomisersLiveTest.java | 96 ++++++++++++++++++++
 3 files changed, 143 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/22d127b2/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 ccf5e17..054ce93 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -30,6 +30,9 @@ import static org.jclouds.scriptbuilder.domain.Statements.exec;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.security.KeyPair;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -48,6 +51,7 @@ import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 
+import com.google.common.reflect.TypeToken;
 import org.jclouds.abiquo.compute.options.AbiquoTemplateOptions;
 import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
 import org.jclouds.compute.ComputeService;
@@ -831,7 +835,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation
im
         void apply(TemplateBuilder tb, ConfigBag props, Object v);
     }
     
-    private static interface CustomizeTemplateOptions {
+    public static interface CustomizeTemplateOptions {
         void apply(TemplateOptions tb, ConfigBag props, Object v);
     }
     
@@ -1050,6 +1054,43 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation
im
                     public void apply(TemplateOptions t, ConfigBag props, Object v) {
                         t.networks((String)v);
                     }})
+              .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() });
+                          }
+                      }
+                  }
+              })
             .build();
 
     private static boolean listedAvailableTemplatesOnNoSuchTemplate = false;
@@ -1140,7 +1181,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation
im
             if (config.containsKey(key))
                 code.apply(options, config, config.get(key));
         }
-        
+
         return template;
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/22d127b2/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 5047166..b7b61a7 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
@@ -20,6 +20,7 @@ package brooklyn.location.jclouds;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.Semaphore;
 
 import org.jclouds.Constants;
@@ -249,6 +250,9 @@ public interface JcloudsLocationConfig extends CloudLocationConfig {
             "Registry/Factory for creating jclouds ComputeService; default is almost always
fine, except where tests want to customize behaviour",
             ComputeServiceRegistryImpl.INSTANCE);
     
+    public static final ConfigKey<Map<String,String>> TEMPLATE_OPTIONS = ConfigKeys.newConfigKey(
+            new TypeToken<Map<String, String>>() {}, "templateOptions", "Additional
jclouds template options");
+
     // TODO
     
 //  "noDefaultSshKeys" - hints that local ssh keys should not be read as defaults

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/22d127b2/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
new file mode 100644
index 0000000..f4c44a4
--- /dev/null
+++ b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 brooklyn.location.jclouds;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.location.NoMachinesAvailableException;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.text.Identifiers;
+import com.google.common.collect.ImmutableList;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.List;
+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;
+
+public class JcloudsLocationTemplateOptionsCustomisersLiveTest extends AbstractJcloudsLiveTest
{
+
+    private static final String LOCATION_SPEC = AWS_EC2_PROVIDER + ":" + AWS_EC2_USEAST_REGION_NAME;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        jcloudsLocation = resolve(LOCATION_SPEC);
+    }
+
+    // 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;
+
+        ConfigBag config = ConfigBag.newInstance()
+                .configure(key, ImmutableMap.of("iamInstanceProfileName", "helloworld"));
+        AWSEC2TemplateOptions templateOptions = jcloudsLocation.getComputeService().templateOptions().as(AWSEC2TemplateOptions.class);
+
+        invokeCustomizeTemplateOptions(templateOptions, JcloudsLocationConfig.TEMPLATE_OPTIONS,
config);
+
+        assertEquals(templateOptions.getIAMInstanceProfileName(), "helloworld");
+    }
+
+    /**
+     * Invoke a specific template options customizer on a TemplateOptions instance.
+     *
+     * @param templateOptions the TemplateOptions instance that you expect the customizer
to modify.
+     * @param keyToTest the config key that identifies the customizer. This must be present
in both @{code locationConfig} and @{link JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES}.
+     * @param locationConfig simulated configuration for the location. This must contain
at least an entry for @{code keyToTest}.
+     */
+    private void invokeCustomizeTemplateOptions(TemplateOptions templateOptions, ConfigKey<?>
keyToTest, ConfigBag locationConfig) {
+        checkNotNull(templateOptions, "templateOptions");
+        checkNotNull(keyToTest, "keyToTest");
+        checkNotNull(locationConfig, "locationConfig");
+        checkState(JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES.containsKey(keyToTest),
+                "SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES does not contain a customiser for
the key " + keyToTest.getName());
+        checkState(locationConfig.containsKey(keyToTest),
+                "location config does not contain the key " + keyToTest.getName());
+
+        JcloudsLocation.CustomizeTemplateOptions code = JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES.get(keyToTest);
+        code.apply(templateOptions, locationConfig, locationConfig.get(keyToTest));
+    }
+
+    private JcloudsLocation resolve(String spec) {
+        return (JcloudsLocation) managementContext.getLocationRegistry().resolve("jclouds:"+spec);
+    }
+}


Mime
View raw message