Repository: brooklyn-server
Updated Branches:
  refs/heads/master 6a1eafc68 -> 84fb623d1


Prevents premature resolving of external config


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

Branch: refs/heads/master
Commit: 11741d85b9f5417257c1e520553b700e8fdfa242
Parents: 460db56
Author: Martin Harris <[email protected]>
Authored: Fri Jun 10 14:21:40 2016 +0100
Committer: Martin Harris <[email protected]>
Committed: Thu Jun 16 17:40:49 2016 +0100

----------------------------------------------------------------------
 .../camp/brooklyn/ExternalConfigYamlTest.java   |  25 ++++
 .../JcloudsLocationExternalConfigYamlTest.java  | 124 +++++++++++++++++++
 ...bstractCloudMachineProvisioningLocation.java |  12 +-
 .../location/ssh/SshMachineLocation.java        |  16 +--
 .../brooklyn/util/core/config/ConfigBag.java    |  50 +++++++-
 .../location/jclouds/JcloudsLocation.java       |  48 +++++--
 .../jclouds/JcloudsSshMachineLocation.java      |   3 +-
 7 files changed, 250 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/11741d85/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ExternalConfigYamlTest.java
----------------------------------------------------------------------
diff --git 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ExternalConfigYamlTest.java
 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ExternalConfigYamlTest.java
index a5f98b3..f8285af 100644
--- 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ExternalConfigYamlTest.java
+++ 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ExternalConfigYamlTest.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.ExecutionContext;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.config.ConfigKey;
@@ -37,14 +38,17 @@ import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.core.mgmt.internal.CampYamlParser;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 import org.apache.brooklyn.util.core.task.DeferredSupplier;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Joiner;
@@ -218,6 +222,27 @@ public class ExternalConfigYamlTest extends 
AbstractYamlTest {
     }
 
     @Test(groups="Integration")
+    public void testExternalisedLocationConfigInheritanceReferencedFromYaml() 
throws Exception {
+        ConfigKey<String> MY_CONFIG_KEY = 
ConfigKeys.newStringConfigKey("my.config.key");
+
+        String yaml = Joiner.on("\n").join(
+                "services:",
+                "- type: "+EmptySoftwareProcess.class.getName(),
+                "location:",
+                "  localhost:",
+                "    my.config.key: $brooklyn:external(\"myprovider\", 
\"mykey\")");
+
+        Entity app = createAndStartApplication(yaml);
+        waitForApplicationTasks(app);
+        Entity entity = Iterables.getOnlyElement( app.getChildren() );
+        Location l = Iterables.getOnlyElement( entity.getLocations() );
+        assertEquals(l.config().get(MY_CONFIG_KEY), "myval");
+        Maybe<Object> rawConfig = 
((BrooklynObjectInternal.ConfigurationSupportInternal)l.config()).getRaw(MY_CONFIG_KEY);
+        Assert.assertTrue(rawConfig.isPresentAndNonNull());
+        Assert.assertTrue(rawConfig.get() instanceof DeferredSupplier, 
"Expected deferred raw value; got "+rawConfig.get());
+    }
+
+    @Test(groups="Integration")
     public void 
testExternalisedLocationConfigSetViaProvisioningPropertiesReferencedFromYaml() 
throws Exception {
         String yaml = Joiner.on("\n").join(
             "services:",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/11741d85/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsLocationExternalConfigYamlTest.java
----------------------------------------------------------------------
diff --git 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsLocationExternalConfigYamlTest.java
 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsLocationExternalConfigYamlTest.java
new file mode 100644
index 0000000..7e99328
--- /dev/null
+++ 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsLocationExternalConfigYamlTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.camp.brooklyn;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.File;
+import java.io.StringReader;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import 
org.apache.brooklyn.camp.brooklyn.ExternalConfigYamlTest.MyExternalConfigSupplier;
+import 
org.apache.brooklyn.camp.brooklyn.ExternalConfigYamlTest.MyExternalConfigSupplierWithoutMapArg;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.util.core.internal.ssh.SshTool;
+import org.apache.brooklyn.util.core.task.DeferredSupplier;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+
+// also see ExternalConfigYamlTest
+public class JcloudsLocationExternalConfigYamlTest extends 
AbstractYamlRebindTest {
+
+    private static final Logger log = 
LoggerFactory.getLogger(ExternalConfigYamlTest.class);
+
+    private static final ConfigKey<String> MY_CONFIG_KEY = 
ConfigKeys.newStringConfigKey("my.config.key");
+
+    @Override
+    protected BrooklynProperties createBrooklynProperties() {
+        BrooklynProperties props = BrooklynProperties.Factory.newDefault();
+        props.put("brooklyn.external.myprovider", 
MyExternalConfigSupplier.class.getName());
+        props.put("brooklyn.external.myprovider.mykey", "myval");
+        props.put("brooklyn.external.myproviderWithoutMapArg", 
MyExternalConfigSupplierWithoutMapArg.class.getName());
+        return props;
+    }
+
+    @Test(groups="Live")
+    public void testJcloudsInheritanceAndPasswordSecret() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                "services:",
+                "- type: "+EmptySoftwareProcess.class.getName(),
+                "location:",
+                "  jclouds:aws-ec2:",
+                "    password: $brooklyn:external(\"myprovider\", \"mykey\")",
+                "    my.config.key: $brooklyn:external(\"myprovider\", 
\"mykey\")");
+
+        origApp = (StartableApplication) createAndStartApplication(new 
StringReader(yaml));
+
+        Entity entity = Iterables.getOnlyElement( origApp.getChildren() );
+        Location l = Iterables.getOnlyElement( entity.getLocations() );
+        log.info("Location: "+l);
+        assertEquals(l.config().get(MY_CONFIG_KEY), "myval");
+
+        Maybe<Object> rawConfig = 
((BrooklynObjectInternal.ConfigurationSupportInternal)l.config()).getRaw(MY_CONFIG_KEY);
+        log.info("Raw config: "+rawConfig);
+        Assert.assertTrue(rawConfig.isPresentAndNonNull());
+        Assert.assertTrue(rawConfig.get() instanceof DeferredSupplier, 
"Expected deferred raw value; got "+rawConfig.get());
+
+        rawConfig = 
((BrooklynObjectInternal.ConfigurationSupportInternal)l.config()).getRaw(SshTool.PROP_PASSWORD);
+        log.info("Raw config password: "+rawConfig);
+        Assert.assertTrue(rawConfig.isPresentAndNonNull());
+        Assert.assertTrue(rawConfig.get() instanceof DeferredSupplier, 
"Expected deferred raw value; got "+rawConfig.get());
+    }
+
+    @Test(groups="Live")
+    public void testProvisioningPropertyInheritance() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                "services:",
+                "- type: "+EmptySoftwareProcess.class.getName(),
+                "  provisioning.properties:",
+                "      password: $brooklyn:external(\"myprovider\", 
\"mykey\")",
+                // note that these 2 do not get transferred -- see below
+                "      simple: 42",
+                "      my.config.key: $brooklyn:external(\"myprovider\", 
\"mykey\")",
+                "location: aws-ec2");
+
+        origApp = (StartableApplication) createAndStartApplication(new 
StringReader(yaml));
+
+        Entity entity = Iterables.getOnlyElement( origApp.getChildren() );
+        Location l = Iterables.getOnlyElement( entity.getLocations() );
+        log.info("Location: "+l);
+        assertEquals(l.config().get(JcloudsLocation.PASSWORD), "myval");
+
+        Maybe<Object> rawConfig = 
((BrooklynObjectInternal.ConfigurationSupportInternal)l.config()).getRaw(ConfigKeys.newStringConfigKey("password"));
+        log.info("Raw config password: "+rawConfig);
+        Assert.assertTrue(rawConfig.isPresentAndNonNull());
+        Assert.assertTrue(rawConfig.get() instanceof DeferredSupplier, 
"Expected deferred raw value; got "+rawConfig.get());
+
+        // these are null as only recognised provisioning properties are 
transmitted by jclouds
+        log.info("my config key: "+l.getConfig(MY_CONFIG_KEY));
+        log.info("my config key raw: 
"+((BrooklynObjectInternal.ConfigurationSupportInternal)l.config()).getRaw(MY_CONFIG_KEY));
+        log.info("simple: "+l.getConfig(ConfigKeys.builder(Integer.class, 
"simple").build()));
+        log.info("simple raw: 
"+((BrooklynObjectInternal.ConfigurationSupportInternal)l.config()).getRaw(ConfigKeys.builder(Integer.class,
 "simple").build()));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/11741d85/core/src/main/java/org/apache/brooklyn/core/location/cloud/AbstractCloudMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/location/cloud/AbstractCloudMachineProvisioningLocation.java
 
b/core/src/main/java/org/apache/brooklyn/core/location/cloud/AbstractCloudMachineProvisioningLocation.java
index 504033a..90d9f8b 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/location/cloud/AbstractCloudMachineProvisioningLocation.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/location/cloud/AbstractCloudMachineProvisioningLocation.java
@@ -71,22 +71,22 @@ implements MachineProvisioningLocation<MachineLocation>, 
CloudLocationConfig
         ConfigBag sshConfig = new ConfigBag();
         
         if (setup.containsKey(PASSWORD)) {
-            sshConfig.put(SshTool.PROP_PASSWORD, setup.get(PASSWORD));
+            sshConfig.copyKeyAs(setup, PASSWORD, SshTool.PROP_PASSWORD);
         } else if (alt.containsKey(PASSWORD)) {
-            sshConfig.put(SshTool.PROP_PASSWORD, alt.get(PASSWORD));
+            sshConfig.copyKeyAs(alt, PASSWORD, SshTool.PROP_PASSWORD);
         }
         
         if (setup.containsKey(PRIVATE_KEY_DATA)) {
-            sshConfig.put(SshTool.PROP_PRIVATE_KEY_DATA, 
setup.get(PRIVATE_KEY_DATA));
+            sshConfig.copyKeyAs(setup, PRIVATE_KEY_DATA, 
SshTool.PROP_PRIVATE_KEY_DATA);
         } else if (setup.containsKey(PRIVATE_KEY_FILE)) {
-            sshConfig.put(SshTool.PROP_PRIVATE_KEY_FILE, 
setup.get(PRIVATE_KEY_FILE));
+            sshConfig.copyKeyAs(setup, PRIVATE_KEY_FILE, 
SshTool.PROP_PRIVATE_KEY_FILE);
         } else if (alt.containsKey(PRIVATE_KEY_DATA)) {
-            sshConfig.put(SshTool.PROP_PRIVATE_KEY_DATA, 
alt.get(PRIVATE_KEY_DATA));
+            sshConfig.copyKeyAs(setup, PRIVATE_KEY_DATA, 
SshTool.PROP_PRIVATE_KEY_DATA);
         }
         
         if (setup.containsKey(PRIVATE_KEY_PASSPHRASE)) {
             // NB: not supported in jclouds (but it is by our ssh tool)
-            sshConfig.put(SshTool.PROP_PRIVATE_KEY_PASSPHRASE, 
setup.get(PRIVATE_KEY_PASSPHRASE));
+            sshConfig.copyKeyAs(setup, PRIVATE_KEY_PASSPHRASE, 
SshTool.PROP_PRIVATE_KEY_PASSPHRASE);
         }
 
         // TODO extract other SshTool properties ?

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/11741d85/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java 
b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
index b66c94c..54bd648 100644
--- 
a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
+++ 
b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
@@ -630,20 +630,20 @@ public class SshMachineLocation extends AbstractLocation 
implements MachineLocat
                 // default value of host, overridden if SSH_HOST is supplied
                 .configure(SshTool.PROP_HOST, address.getHostName());
 
-            for (Map.Entry<String,Object> entry: 
config().getBag().getAllConfig().entrySet()) {
+            for (Map.Entry<ConfigKey<?>, ?> entry: 
config().getBag().getAllConfigAsConfigKeyMap().entrySet()) {
                 boolean include = false;
-                String key = entry.getKey();
-                if (key.startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
-                    key = Strings.removeFromStart(key, 
SshTool.BROOKLYN_CONFIG_KEY_PREFIX);
+                String keyName = entry.getKey().getName();
+                if (keyName.startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
+                    keyName = Strings.removeFromStart(keyName, 
SshTool.BROOKLYN_CONFIG_KEY_PREFIX);
                     include = true;
                 }
                 
-                if (key.startsWith(SSH_TOOL_CLASS_PROPERTIES_PREFIX)) {
-                    key = Strings.removeFromStart(key, 
SSH_TOOL_CLASS_PROPERTIES_PREFIX);
+                if (keyName.startsWith(SSH_TOOL_CLASS_PROPERTIES_PREFIX)) {
+                    keyName = Strings.removeFromStart(keyName, 
SSH_TOOL_CLASS_PROPERTIES_PREFIX);
                     include = true;
                 }
                 
-                if (ALL_SSH_CONFIG_KEY_NAMES.contains(entry.getKey())) {
+                if (ALL_SSH_CONFIG_KEY_NAMES.contains(keyName)) {
                     // key should be included, and does not need to be changed
 
                     // TODO make this config-setting mechanism more universal
@@ -655,7 +655,7 @@ public class SshMachineLocation extends AbstractLocation 
implements MachineLocat
                 }
                 
                 if (include) {
-                    args.putStringKey(key, entry.getValue());
+                    args.putStringKey(keyName, config().get(entry.getKey()));
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/11741d85/core/src/main/java/org/apache/brooklyn/util/core/config/ConfigBag.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/util/core/config/ConfigBag.java 
b/core/src/main/java/org/apache/brooklyn/util/core/config/ConfigBag.java
index 23a7485..96d2428 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/config/ConfigBag.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/config/ConfigBag.java
@@ -30,7 +30,6 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
@@ -367,6 +366,45 @@ public class ConfigBag {
         }
     }
 
+    /** gets a {@link Maybe}-wrapped value from a key, inferring the type of 
that key (e.g. {@link ConfigKey} or {@link String}) */
+    @Beta
+    private Maybe<Object> getRawObjKeyMaybe(Object key) {
+        if (key instanceof HasConfigKey<?>) key = 
((HasConfigKey<?>)key).getConfigKey();
+        if (key instanceof ConfigKey<?>) key = ((ConfigKey<?>)key).getName();
+        if (key instanceof String) {
+            return this.getRawStringKeyMaybe((String)key, true);
+        } else {
+            logInvalidKey(key);
+            return Maybe.absent();
+        }
+    }
+
+    /** Puts into this bag the raw value for the given key in the given bag, 
if it was present. */
+    @Beta
+    public <T> ConfigBag copyKey(ConfigBag source, ConfigKey<T> key) {
+        return copyKeyAs(source, key, key);
+    }
+
+    /** Puts into this bag the raw value for the given key in the given bag, 
if it was present. */
+    @Beta
+    public <T> ConfigBag copyKeys(ConfigBag source, ConfigKey<T> ...keys) {
+        for (ConfigKey<T> key : keys) {
+            copyKey(source, key);
+        }
+        return this;
+    }
+
+    /** As {@link #copyKey(ConfigBag, ConfigKey)} but allowing a different key 
name to be used when writing here. */
+    @Beta
+    @SuppressWarnings("unchecked")
+    public <T> ConfigBag copyKeyAs(ConfigBag source, ConfigKey<T> sourceKey, 
ConfigKey<T> targetKey) {
+        Maybe<Object> sourceValue = source.getRawObjKeyMaybe(sourceKey);
+        if (sourceValue.isPresent()) {
+            put(targetKey, (T) sourceValue.get());
+        }
+        return this;
+    }
+
     /** like get, but without marking it as used */
     public <T> T peek(ConfigKey<T> key) {
         return get(key, false);
@@ -468,7 +506,8 @@ public class ConfigBag {
     protected Object getStringKey(String key, boolean markUsed) {
         return getStringKeyMaybe(key, markUsed).orNull();
     }
-    protected synchronized Maybe<Object> getStringKeyMaybe(String key, boolean 
markUsed) {
+
+    private synchronized Maybe<Object> getRawStringKeyMaybe(String key, 
boolean markUsed) {
         if (config.containsKey(key)) {
             if (markUsed) markUsed(key);
             return Maybe.of(config.get(key));
@@ -476,6 +515,13 @@ public class ConfigBag {
         return Maybe.absent();
     }
 
+    /**
+     * @return Unresolved configuration value. May be overridden to provide 
resolution - @see {@link ResolvingConfigBag#getStringKeyMaybe(String, boolean)}
+     */
+    protected synchronized Maybe<Object> getStringKeyMaybe(String key, boolean 
markUsed) {
+        return getRawStringKeyMaybe(key, markUsed);
+    }
+
     /** indicates that a string key in the config map has been accessed */
     public synchronized void markUsed(String key) {
         unusedConfig.remove(key);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/11741d85/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
 
b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
index 51e9d6a..4862e47 100644
--- 
a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
+++ 
b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
@@ -569,7 +569,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
     @Override
     public MachineManagementMixins.MachineMetadata 
getMachineMetadata(MachineLocation l) {
         if (l instanceof JcloudsSshMachineLocation) {
-            return getMachineMetadata( ((JcloudsSshMachineLocation)l).node );
+            return 
getMachineMetadata(getComputeService().getNodeMetadata(((JcloudsSshMachineLocation)
 l).getJcloudsId()));
         }
         return null;
     }
@@ -813,8 +813,8 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                 userCredentials = 
LoginCredentials.fromCredentials(node.getCredentials());
             }
             // store the credentials, in case they have changed
-            setup.putIfNotNull(JcloudsLocationConfig.PASSWORD, 
userCredentials.getOptionalPassword().orNull());
-            setup.putIfNotNull(JcloudsLocationConfig.PRIVATE_KEY_DATA, 
userCredentials.getOptionalPrivateKey().orNull());
+            putIfPresentButDifferent(setup, JcloudsLocationConfig.PASSWORD, 
userCredentials.getOptionalPassword().orNull());
+            putIfPresentButDifferent(setup, 
JcloudsLocationConfig.PRIVATE_KEY_DATA, 
userCredentials.getOptionalPrivateKey().orNull());
 
             // Wait for the VM to be reachable over SSH
             if (waitForSshable && !windows) {
@@ -822,10 +822,13 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
             } else {
                 LOG.debug("Skipping ssh check for {} ({}) due to config 
waitForSshable=false", node, setup.getDescription());
             }
+
+            // Do not store the credentials on the node as this may leak the 
credentials if they
+            // are obtained from an external supplier
+            node = 
NodeMetadataBuilder.fromNodeMetadata(node).credentials(null).build();
+
             usableTimestamp = Duration.of(provisioningStopwatch);
 
-//            JcloudsSshMachineLocation jcloudsSshMachineLocation = null;
-//            WinRmMachineLocation winRmMachineLocation = null;
             // Create a JcloudsSshMachineLocation, and register it
             if (windows) {
                 machineLocation = registerWinRmMachineLocation(computeService, 
node, userCredentials, sshHostAndPortOverride, setup);
@@ -1151,6 +1154,21 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
 
     // ------------- suspend and resume ------------------------------------
 
+    private void putIfPresentButDifferent(ConfigBag setup, ConfigKey<String> 
key, String expectedValue) {
+        if (expectedValue==null) return;
+        String currentValue = setup.get(key);
+        if (Objects.equal(currentValue, expectedValue)) {
+            // no need to write -- and good reason not to --
+            // the currentValue may come from an external supplier,
+            // so we prefer to keep the secret in that supplier
+            return;
+        }
+        // either current value is null, or
+        // current value is different (possibly password coming from a 
one-time source)
+        // in either case prefer the expected value
+        setup.put(key, expectedValue);
+    }
+
     /**
      * Suspends the given location.
      * <p>
@@ -2375,7 +2393,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
         if (userCredentials == null)
             userCredentials = node.getCredentials();
 
-        String vmHostname = getPublicHostname(node, sshHostAndPort, setup);
+        String vmHostname = getPublicHostname(node, sshHostAndPort, 
userCredentials, setup);
 
         JcloudsSshMachineLocation machine = 
createJcloudsSshMachineLocation(computeService, node, template, vmHostname, 
sshHostAndPort, userCredentials, setup);
         registerJcloudsMachineLocation(node.getId(), machine);
@@ -2442,8 +2460,12 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                     // FIXME remove "config" -- inserted directly, above
                     .configure("config", sshConfig)
                     .configure("user", userCredentials.getUser())
-                    .configure(SshMachineLocation.PASSWORD, 
userCredentials.getOptionalPassword().orNull())
-                    .configure(SshMachineLocation.PRIVATE_KEY_DATA, 
userCredentials.getOptionalPrivateKey().orNull())
+                    .configure(SshMachineLocation.PASSWORD.getName(), 
sshConfig.get(SshMachineLocation.PASSWORD.getName()) != null ?
+                            
sshConfig.get(SshMachineLocation.PASSWORD.getName()) :
+                            userCredentials.getOptionalPassword().orNull())
+                    .configure(SshMachineLocation.PRIVATE_KEY_DATA.getName(), 
sshConfig.get(SshMachineLocation.PRIVATE_KEY_DATA.getName()) != null ?
+                            
sshConfig.get(SshMachineLocation.PRIVATE_KEY_DATA.getName()) :
+                            userCredentials.getOptionalPrivateKey().orNull())
                     .configure("jcloudsParent", this)
                     .configure("node", node)
                     .configure("template", template.orNull())
@@ -2466,8 +2488,12 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                     // FIXME remove "config" -- inserted directly, above
                     .put("config", sshConfig)
                     .put("user", userCredentials.getUser())
-                    .putIfNotNull(SshMachineLocation.PASSWORD.getName(), 
userCredentials.getOptionalPassword().orNull())
-                    
.putIfNotNull(SshMachineLocation.PRIVATE_KEY_DATA.getName(), 
userCredentials.getOptionalPrivateKey().orNull())
+                    .putIfNotNull(SshMachineLocation.PASSWORD.getName(), 
sshConfig.get(SshMachineLocation.PASSWORD.getName()) != null ?
+                            SshMachineLocation.PASSWORD.getName() :
+                            userCredentials.getOptionalPassword().orNull())
+                    
.putIfNotNull(SshMachineLocation.PRIVATE_KEY_DATA.getName(), 
sshConfig.get(SshMachineLocation.PRIVATE_KEY_DATA.getName()) != null ?
+                            SshMachineLocation.PRIVATE_KEY_DATA.getName() :
+                            userCredentials.getOptionalPrivateKey().orNull())
                     .put("callerContext", setup.get(CALLER_CONTEXT))
                     .putIfNotNull(CLOUD_AVAILABILITY_ZONE_ID.getName(), 
nodeAvailabilityZone)
                     .putIfNotNull(CLOUD_REGION_ID.getName(), nodeRegion)
@@ -2509,7 +2535,7 @@ public class JcloudsLocation extends 
AbstractCloudMachineProvisioningLocation im
                     .configure(WinRmMachineLocation.WINRM_CONFIG_PORT, 
sshHostAndPort.isPresent() ? sshHostAndPort.get().getPort() : 
node.getLoginPort())
                     .configure("user", getUser(setup))
                     .configure(WinRmMachineLocation.USER, setup.get(USER))
-                    .configure(WinRmMachineLocation.PASSWORD, 
setup.get(PASSWORD))
+                    .configure(ConfigBag.newInstance().copyKeyAs(setup, 
PASSWORD, WinRmMachineLocation.PASSWORD).getAllConfigRaw())
                     .configure("node", node)
                     .configureIfNotNull(CLOUD_AVAILABILITY_ZONE_ID, 
nodeAvailabilityZone)
                     .configureIfNotNull(CLOUD_REGION_ID, nodeRegion)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/11741d85/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
 
b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
index 51a476f..3318ba1 100644
--- 
a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
+++ 
b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
@@ -38,6 +38,7 @@ import org.apache.brooklyn.core.location.BasicOsDetails;
 import org.apache.brooklyn.core.location.LocationConfigUtils;
 import org.apache.brooklyn.core.location.LocationConfigUtils.OsCredential;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ResolvingConfigBag;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.net.Networking;
@@ -480,7 +481,7 @@ public class JcloudsSshMachineLocation extends 
SshMachineLocation implements Jcl
     }
 
     private LoginCredentials getLoginCredentials() {
-        OsCredential creds = 
LocationConfigUtils.getOsCredential(config().getBag());
+        OsCredential creds = LocationConfigUtils.getOsCredential(new 
ResolvingConfigBag(getManagementContext(), config().getBag()));
         
         return LoginCredentials.builder()
                 .user(getUser())

Reply via email to