brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aleds...@apache.org
Subject [1/3] incubator-brooklyn git commit: Adds SetHostnameCustomizer
Date Wed, 21 Oct 2015 09:12:32 GMT
Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 238816f88 -> 9790e8b6b


Adds SetHostnameCustomizer


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

Branch: refs/heads/master
Commit: f792fdfb3a4bccbf863997f401212657619317ef
Parents: 76b098b
Author: Aled Sage <aled.sage@gmail.com>
Authored: Mon Oct 19 18:13:44 2015 +0100
Committer: Aled Sage <aled.sage@gmail.com>
Committed: Wed Oct 21 09:50:30 2015 +0100

----------------------------------------------------------------------
 .../core/effector/ssh/SshEffectorTasks.java     |   7 +
 .../entity/machine/SetHostnameCustomizer.java   | 201 +++++++++++++++++++
 .../machine/SetHostnameCustomizerLiveTest.java  | 143 +++++++++++++
 .../machine/SetHostnameCustomizerTest.java      |  67 +++++++
 4 files changed, 418 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f792fdfb/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
b/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
index 37e582d..a8e427c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/ssh/SshEffectorTasks.java
@@ -200,6 +200,13 @@ public class SshEffectorTasks {
         }
     }
 
+    /**
+     * @since 0.9.0
+     */
+    public static SshEffectorTaskFactory<Integer> ssh(SshMachineLocation machine, String
...commands) {
+        return new SshEffectorTaskFactory<Integer>(machine, commands);
+    }
+
     public static SshEffectorTaskFactory<Integer> ssh(String ...commands) {
         return new SshEffectorTaskFactory<Integer>(commands);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f792fdfb/software/base/src/main/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizer.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizer.java
b/software/base/src/main/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizer.java
new file mode 100644
index 0000000..7fdb86a
--- /dev/null
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizer.java
@@ -0,0 +1,201 @@
+/*
+ * 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.entity.machine;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.apache.brooklyn.api.location.BasicMachineLocationCustomizer;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks.SshEffectorTaskFactory;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.core.text.TemplateProcessor;
+import org.apache.brooklyn.util.net.Networking;
+import org.apache.brooklyn.util.ssh.BashCommands;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+/**
+ * Sets the hostname on an ssh'able machine. Currently only CentOS and RHEL are supported.
+ * <p>
+ * The customizer can be configured with a hard-coded hostname, or with a freemarker template
+ * whose value (after substitutions) will be used for the hostname. 
+ */
+public class SetHostnameCustomizer extends BasicMachineLocationCustomizer {
+
+    public static final Logger log = LoggerFactory.getLogger(SetHostnameCustomizer.class);
+    
+    public static final ConfigKey<String> FIXED_HOSTNAME = ConfigKeys.newStringConfigKey(
+            "hostname.fixed",
+            "The statically defined hostname to be set on the machine (if non-null)");
+    
+    public static final ConfigKey<String> FIXED_DOMAIN = ConfigKeys.newStringConfigKey(
+            "domain.fixed",
+            "The statically defined domain name to be set on the machine (if non-null)");
+    
+    // the  var??  tests if it exists, passing value to ?string(if_present,if_absent)
+    // the ! provides a default value afterwards, which is never used, but is required for
parsing
+    // when the config key is not available;
+    // thus the below prefers the first private address, then the first public address, and
then
+    // substitutes dots for dashes.
+    public static final ConfigKey<String> HOSTNAME_TEMPLATE = ConfigKeys.newStringConfigKey(
+            "hostname.templated",
+            "The hostname template, to be resolved and then set on the machine (if non-null).
"
+                    +"Assumed to be in free-marker format.",
+            "ip-"
+                    + "${((location.privateAddresses[0]??)?string("
+                            + "location.privateAddresses[0]!'X', location.publicAddresses[0]))"
+                    + "?replace(\".\",\"-\")}"
+                    + "-${location.id}");
+
+    public static final ConfigKey<String> LOCAL_HOSTNAME = ConfigKeys.newStringConfigKey(
+            "hostname.local.hostname",
+            "Host name, as known on the local box. Config is set on the location.");
+    
+    public static final ConfigKey<String> LOCAL_IP = ConfigKeys.newStringConfigKey(
+            "hostname.local.address",
+            "Host address, as known on the local box. Config is set on the location.");
+    
+    private final ConfigBag config;
+
+    public SetHostnameCustomizer(ConfigBag config) {
+        // TODO Any checks that they've given us sufficient configuration?
+        this.config = config;
+    }
+    
+    @Override
+    public void customize(MachineLocation machine) {
+        String localHostname = setLocalHostname((SshMachineLocation) machine);
+        machine.config().set(LOCAL_HOSTNAME, localHostname);
+
+        String localIp = execHostnameMinusI((SshMachineLocation) machine);
+        machine.config().set(LOCAL_IP, localIp);
+    }
+
+    protected String generateHostname(SshMachineLocation machine) {
+        String hostnameTemplate = config.get(HOSTNAME_TEMPLATE);
+        if (Strings.isNonBlank(hostnameTemplate)) {
+            return TemplateProcessor.processTemplateContents(hostnameTemplate, machine, ImmutableMap.<String,
Object>of());
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Sets the machine's hostname to the value controlled by fixed_hostname and hostname_template.

+     * If these are blank (and fixed_domain is blank), then just return the current hostname
of 
+     * the machine.
+     */
+    public String setLocalHostname(SshMachineLocation machine) {
+        String hostFixed = config.get(FIXED_HOSTNAME);
+        String domainFixed = config.get(FIXED_DOMAIN);
+        String hostnameTemplate = config.get(HOSTNAME_TEMPLATE);
+        
+        String hostname;
+        if (Strings.isNonBlank(hostFixed)) {
+            hostname = hostFixed;
+        } else {
+            if (Strings.isNonBlank(hostnameTemplate)) {
+                hostname = generateHostname(machine);
+            } else {
+                hostname = execHostname(machine);
+                if (Strings.isBlank(domainFixed)) {
+                    return hostname;
+                }
+            }
+        }
+        
+        return setLocalHostname(machine, hostname, domainFixed);
+    }
+    
+    /**
+     * Sets the machine's hostname to the given value, ensuring /etc/hosts and /etc/sysconfig/network
are both 
+     * correctly updated.
+     */
+    public String setLocalHostname(SshMachineLocation machine, String hostName, String domainFixed)
{
+        log.info("Setting local hostname of " + machine + " to " + hostName 
+                + (Strings.isNonBlank(domainFixed) ? ", " + domainFixed : ""));
+        
+        boolean hasDomain = Strings.isNonBlank(domainFixed);
+        String fqdn = hasDomain ? hostName+"."+domainFixed : hostName;
+        
+        exec(machine, true, 
+                BashCommands.sudo(String.format("sed -i.bak -e '1i127.0.0.1 %s %s' -e '/^127.0.0.1/d'
/etc/hosts", fqdn, hostName)),
+                BashCommands.sudo(String.format("sed -i.bak -e 's/^HOSTNAME=.*$/HOSTNAME=%s/'
/etc/sysconfig/network", fqdn)),
+                BashCommands.sudo(String.format("hostname %s", fqdn)));
+
+        return hostName;
+    }
+    
+    protected void registerEtcHosts(SshMachineLocation machine, String ip, Iterable<String>
hostnames) {
+        log.info("Updating /etc/hosts of "+machine+": adding "+ip+" = "+hostnames);
+        
+        checkArgument(Strings.isNonBlank(ip) && Networking.isValidIp4(ip), "invalid
IPv4 address %s", ip);
+        if (Strings.isBlank(ip) || Iterables.isEmpty(hostnames)) return;
+        String line = ip+" "+Joiner.on(" ").join(hostnames);
+        exec(machine, true, "echo " + line + " >> /etc/hosts");
+    }
+    
+    protected String execHostname(SshMachineLocation machine) {
+        if (log.isDebugEnabled()) log.debug("Retrieve `hostname` via ssh for {}", machine);
+        
+        ProcessTaskWrapper<Integer> cmd = exec(machine, false, "echo hostname=`hostname`");
+//        ProcessTaskWrapper<Integer> cmd = DynamicTasks.queue(SshEffectorTasks.ssh(machine,
"echo hostname=`hostname`")
+//                .summary("getHostname"))
+//                .block();
+
+        for (String line : cmd.getStdout().split("\n")) {
+            if (line.contains("hostname=") && !line.contains("`hostname`")) {
+                return line.substring(line.indexOf("hostname=") + "hostname=".length()).trim();
+            }
+        }
+        log.info("No hostname found for {} (got {}; {})", new Object[] {machine, cmd.getStdout(),
cmd.getStderr()});
+        return null;
+    }
+
+    protected String execHostnameMinusI(SshMachineLocation machine) {
+        if (log.isDebugEnabled()) log.debug("Retrieve `hostname -I` via ssh for {}", machine);
+        
+        ProcessTaskWrapper<Integer> cmd = exec(machine, false, "echo localip=`hostname
-I`");
+
+        for (String line : cmd.getStdout().split("\n")) {
+            if (line.contains("localip=") && !line.contains("`hostname -I`")) {
+                return line.substring(line.indexOf("localip=") + "localip=".length()).trim();
+            }
+        }
+        log.info("No local ip found for {} (got {}; {})", new Object[] {machine, cmd.getStdout(),
cmd.getStderr()});
+        return null;
+    }
+    
+    protected ProcessTaskWrapper<Integer> exec(SshMachineLocation machine, boolean
asRoot, String... cmds) {
+        SshEffectorTaskFactory<Integer> taskFactory = SshEffectorTasks.ssh(machine,
cmds);
+        if (asRoot) taskFactory.runAsRoot();
+        return DynamicTasks.queue(taskFactory).block();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f792fdfb/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerLiveTest.java
b/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerLiveTest.java
new file mode 100644
index 0000000..7e139f3
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerLiveTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.entity.machine;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.entity.AbstractSoftlayerLiveTest;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.CaseFormat;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+public class SetHostnameCustomizerLiveTest extends BrooklynAppLiveTestSupport {
+
+    public static final String PROVIDER = AbstractSoftlayerLiveTest.PROVIDER;
+    public static final String REGION = "ams01";
+    public static final String PROVIDER_IMAGE_ID = "CENTOS_6_64";
+    public static final String LOCATION_SPEC = PROVIDER + ":" + REGION;
+    
+    public static final int MAX_TAG_LENGTH = AbstractSoftlayerLiveTest.MAX_TAG_LENGTH;
+    public static final int MAX_VM_NAME_LENGTH = AbstractSoftlayerLiveTest.MAX_VM_NAME_LENGTH;
+
+    protected BrooklynProperties brooklynProperties;
+    
+    protected MachineProvisioningLocation<SshMachineLocation> loc;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        List<String> propsToRemove = ImmutableList.of("imageId", "imageDescriptionRegex",
"imageNameRegex", "inboundPorts", "hardwareId", "minRam");
+
+        // Don't let any defaults from brooklyn.properties (except credentials) interfere
with test
+        brooklynProperties = BrooklynProperties.Factory.newDefault();
+        for (String propToRemove : propsToRemove) {
+            for (String propVariant : ImmutableList.of(propToRemove, CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN,
propToRemove))) {
+                brooklynProperties.remove("brooklyn.locations.jclouds."+PROVIDER+"."+propVariant);
+                brooklynProperties.remove("brooklyn.locations."+propVariant);
+                brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+"."+propVariant);
+                brooklynProperties.remove("brooklyn.jclouds."+propVariant);
+            }
+        }
+
+        // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then
that can cause "stdin: is not a tty")
+        brooklynProperties.remove("brooklyn.ssh.config.scriptHeader");
+        
+        mgmt = new LocalManagementContext(brooklynProperties);
+        
+        super.setUp();
+        
+        loc = (MachineProvisioningLocation<SshMachineLocation>) mgmt.getLocationRegistry().resolve(LOCATION_SPEC);
+    }
+
+    @Test(groups = {"Live"})
+    public void testSetFixedHostname() throws Exception {
+        SetHostnameCustomizer customizer = new SetHostnameCustomizer(ConfigBag.newInstance()
+                .configure(SetHostnameCustomizer.FIXED_HOSTNAME, "myhostname"));
+        
+        MachineEntity entity = app.createAndManageChild(EntitySpec.create(MachineEntity.class)
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true)
+                .configure(MachineEntity.PROVISIONING_PROPERTIES.subKey(JcloudsLocation.MACHINE_LOCATION_CUSTOMIZERS.getName()),
ImmutableSet.of(customizer))
+                .configure(MachineEntity.PROVISIONING_PROPERTIES.subKey(JcloudsLocation.IMAGE_ID.getName()),
PROVIDER_IMAGE_ID));
+
+
+        app.start(ImmutableList.of(loc));
+        
+        SshMachineLocation machine = Machines.findUniqueMachineLocation(entity.getLocations(),
SshMachineLocation.class).get();
+        
+        assertEquals(getHostname(machine), "myhostname");
+    }
+    
+    @Test(groups = {"Live"})
+    public void testSetAutogeneratedHostname() throws Exception {
+        SetHostnameCustomizer customizer = new SetHostnameCustomizer(ConfigBag.newInstance());
+
+        MachineEntity entity = app.createAndManageChild(EntitySpec.create(MachineEntity.class)
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true)
+                .configure(MachineEntity.PROVISIONING_PROPERTIES.subKey(JcloudsLocation.MACHINE_LOCATION_CUSTOMIZERS.getName()),
ImmutableSet.of(customizer))
+                .configure(MachineEntity.PROVISIONING_PROPERTIES.subKey(JcloudsLocation.IMAGE_ID.getName()),
"CENTOS_6_64"));
+
+
+        app.start(ImmutableList.of(loc));
+        
+        SshMachineLocation machine = Machines.findUniqueMachineLocation(entity.getLocations(),
SshMachineLocation.class).get();
+        
+        String ip;
+        if (machine.getPrivateAddresses().isEmpty()) {
+            ip = Iterables.get(machine.getPublicAddresses(), 0);
+        } else {
+            ip = Iterables.get(machine.getPrivateAddresses(), 0);
+        }
+        String expected = "ip-"+(ip.replace(".", "-")+"-"+machine.getId());
+        assertEquals(getHostname(machine), expected);
+    }
+    
+    protected String getHostname(SshMachineLocation machine) {
+        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
+        ByteArrayOutputStream errstream = new ByteArrayOutputStream();
+        int result = machine.execScript(ImmutableMap.of("out", outstream, "err", errstream),
"getHostname", ImmutableList.of("echo hostname=`hostname`"));
+        assertEquals(result, 0);
+        
+        String out = new String(outstream.toByteArray());
+        String err = new String(errstream.toByteArray());
+        for (String line : out.split("\n")) {
+            if (line.contains("hostname=") && !line.contains("`hostname`")) {
+                return line.substring(line.indexOf("hostname=") + "hostname=".length()).trim();
+            }
+        }
+        throw new IllegalStateException(String.format("No hostname found for %s (got %s;
%s)", machine, out, err));
+    }        
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f792fdfb/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerTest.java
b/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerTest.java
new file mode 100644
index 0000000..5ffdcdc
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/machine/SetHostnameCustomizerTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.entity.machine;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class SetHostnameCustomizerTest extends BrooklynAppUnitTestSupport {
+
+    private SetHostnameCustomizer customizer;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        customizer = new SetHostnameCustomizer(ConfigBag.newInstance());
+    }
+    
+    @Test
+    public void testGeneratedHostnameUsesPrivateIp() throws Exception {
+        SshMachineLocation machine = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
+                .configure("privateAddresses", ImmutableList.of("1.2.3.4", "5.6.7.8"))
+                .configure("address", "4.3.2.1"));
+        
+        assertEquals(customizer.generateHostname(machine), "ip-1-2-3-4-"+machine.getId());
+    }
+    
+    @Test
+    public void testGeneratedHostnameUsesPublicIpIfNoPrivate() throws Exception {
+        SshMachineLocation machine = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
+                .configure("address", "4.3.2.1"));
+        
+        assertEquals(customizer.generateHostname(machine), "ip-4-3-2-1-"+machine.getId());
+    }
+    
+    @Test
+    public void testGeneratedHostnameUsesPublicIpIfEmptyListOfPrivate() throws Exception
{
+        SshMachineLocation machine = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class)
+                .configure("privateAddresses", ImmutableList.of())
+                .configure("address", "4.3.2.1"));
+        
+        assertEquals(customizer.generateHostname(machine), "ip-4-3-2-1-"+machine.getId());
+    }
+}


Mime
View raw message