http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7582ebeb/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/templates/customize/UserMetadataStringOption.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/templates/customize/UserMetadataStringOption.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/templates/customize/UserMetadataStringOption.java new file mode 100644 index 0000000..b01fdcb --- /dev/null +++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/templates/customize/UserMetadataStringOption.java @@ -0,0 +1,80 @@ +/* + * 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 org.apache.brooklyn.location.jclouds.templates.customize; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.brooklyn.util.core.config.ConfigBag; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.text.Strings; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.ec2.compute.options.EC2TemplateOptions; +import org.jclouds.softlayer.compute.options.SoftLayerTemplateOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class UserMetadataStringOption implements TemplateOptionCustomizer { + private static final Logger LOG = LoggerFactory.getLogger(UserMetadataStringOption.class); + + public void apply(TemplateOptions t, ConfigBag props, Object v) { + if (t instanceof EC2TemplateOptions) { + // See AWS docs: http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/UsingConfig_WinAMI.html#user-data-execution + if (v == null) return; + String data = v.toString(); + if (!(data.startsWith("<script>") || data.startsWith("<powershell>"))) { + data = "<script> " + data + " </script>"; + } + ((EC2TemplateOptions) t).userData(data.getBytes()); + } else if (t instanceof SoftLayerTemplateOptions) { + ((SoftLayerTemplateOptions) t).userData(Strings.toString(v)); + } else { + // Try reflection: userData(String), or guestCustomizationScript(String); + // the latter is used by vCloud Director. + Class<? extends TemplateOptions> clazz = t.getClass(); + Method userDataMethod = null; + try { + userDataMethod = clazz.getMethod("userData", String.class); + } catch (SecurityException e) { + LOG.info("Problem reflectively inspecting methods of " + t.getClass() + " for setting userData", e); + } catch (NoSuchMethodException e) { + try { + // For vCloud Director + userDataMethod = clazz.getMethod("guestCustomizationScript", String.class); + } catch (NoSuchMethodException e2) { + // expected on various other clouds + } + } + if (userDataMethod != null) { + try { + userDataMethod.invoke(t, Strings.toString(v)); + } catch (InvocationTargetException e) { + LOG.info("Problem invoking " + userDataMethod.getName() + " of " + t.getClass() + ", for setting userData (rethrowing)", e); + throw Exceptions.propagate(e); + } catch (IllegalAccessException e) { + LOG.debug("Unable to reflectively invoke " + userDataMethod.getName() + " of " + t.getClass() + ", for setting userData (rethrowing)", e); + throw Exceptions.propagate(e); + } + } else { + LOG.info("ignoring userDataString({}) in VM creation because not supported for cloud/type ({})", v, t.getClass()); + } + } + } +}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7582ebeb/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java index b47595f..475fc78 100644 --- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java +++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.location.jclouds.templates.customize.TemplateOptionCustomizer; import org.apache.brooklyn.util.core.config.ConfigBag; import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions; import org.jclouds.compute.options.TemplateOptions; @@ -98,7 +99,7 @@ public class JcloudsLocationTemplateOptionsCustomisersLiveTest extends AbstractJ checkState(locationConfig.containsKey(keyToTest), "location config does not contain the key " + keyToTest.getName()); - JcloudsLocation.CustomizeTemplateOptions code = JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES.get(keyToTest); + TemplateOptionCustomizer code = JcloudsLocation.SUPPORTED_TEMPLATE_OPTIONS_PROPERTIES.get(keyToTest); code.apply(templateOptions, locationConfig, locationConfig.get(keyToTest)); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7582ebeb/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java index 9a4d3b9..dcd1dde 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/lifecycle/MachineLifecycleEffectorTasks.java @@ -491,6 +491,8 @@ public abstract class MachineLifecycleEffectorTasks { SshMachineLocation sshMachine = (SshMachineLocation) machine; UserAndHostAndPort sshAddress = UserAndHostAndPort.fromParts( sshMachine.getUser(), sshMachine.getAddress().getHostName(), sshMachine.getPort()); + // FIXME: Who or what is SSH_ADDRESS intended for? It's not necessarily the address that + // the SshMachineLocation is using for ssh connections (because it accepts SSH_HOST as an override). entity().sensors().set(Attributes.SSH_ADDRESS, sshAddress); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7582ebeb/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java index 22a4f7c..db24b58 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java @@ -28,7 +28,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; - import javax.annotation.Nullable; import org.apache.brooklyn.util.collections.MutableList; @@ -44,7 +43,9 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.google.common.collect.Ordering; public class Strings { @@ -827,6 +828,33 @@ public class Strings { return result; } + /** + * Tries to convert v to a list of strings. + * <p> + * If v is <code>null</code> then the method returns an empty immutable list. + * If v is {@link Iterable} or an <code>Object[]</code> then toString is called on its elements. + * If v is a {@link String} then a singleton list containing v is returned. + * Otherwise the method throws an {@link IllegalArgumentException}. + */ + public static List<String> toStringList(Object v) { + if (v == null) return ImmutableList.of(); + List<String> result = Lists.newArrayList(); + if (v instanceof Iterable) { + for (Object o : (Iterable<?>) v) { + result.add(o.toString()); + } + } else if (v instanceof Object[]) { + for (int i = 0; i < ((Object[]) v).length; i++) { + result.add(((Object[]) v)[i].toString()); + } + } else if (v instanceof String) { + result.add((String) v); + } else { + throw new IllegalArgumentException("Invalid type for List<String>: " + v + " of type " + v.getClass()); + } + return result; + } + /** returns base repeated count times */ public static String repeat(String base, int count) { if (base==null) return null;