You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by dr...@apache.org on 2017/06/29 15:36:06 UTC

[24/50] [abbrv] brooklyn-server git commit: no_entry: Move kubernetes classes to new location

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesEmptyMachineLocation.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesEmptyMachineLocation.java b/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesEmptyMachineLocation.java
new file mode 100644
index 0000000..8875ef3
--- /dev/null
+++ b/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesEmptyMachineLocation.java
@@ -0,0 +1,68 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location.machine;
+
+import java.net.InetAddress;
+import java.util.Set;
+
+import org.apache.brooklyn.api.location.MachineDetails;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.net.Networking;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * A {@link MachineLocation} represemnting a Kubernetes resource that does not support SSH access.
+ *
+ * @see {@link KubernetesSshMachineLocation}
+ */
+public class KubernetesEmptyMachineLocation extends SshMachineLocation implements KubernetesMachineLocation {
+
+    @Override
+    public String getHostname() {
+        return getResourceName();
+    }
+
+    @Override
+    public Set<String> getPublicAddresses() {
+        return ImmutableSet.of("0.0.0.0");
+    }
+
+    @Override
+    public Set<String> getPrivateAddresses() {
+        return ImmutableSet.of("0.0.0.0");
+    }
+
+    @Override
+    public InetAddress getAddress() {
+        return Networking.getInetAddressWithFixedName("0.0.0.0");
+    }
+
+    @Override
+    public OsDetails getOsDetails() {
+        return null;
+        // throw new UnsupportedOperationException("No OS details for empty KubernetesMachineLocation");
+    }
+
+    @Override
+    public MachineDetails getMachineDetails() {
+        return null;
+        // throw new UnsupportedOperationException("No machine details for empty KubernetesMachineLocation");
+    }
+
+    @Override
+    public String getResourceName() {
+        return config().get(KUBERNETES_RESOURCE_NAME);
+    }
+
+    @Override
+    public String getResourceType() {
+        return config().get(KUBERNETES_RESOURCE_TYPE);
+    }
+
+    @Override
+    public String getNamespace() {
+        return config().get(KUBERNETES_NAMESPACE);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesMachineLocation.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesMachineLocation.java b/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesMachineLocation.java
new file mode 100644
index 0000000..6d8838b
--- /dev/null
+++ b/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesMachineLocation.java
@@ -0,0 +1,27 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location.machine;
+
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+public interface KubernetesMachineLocation extends MachineLocation {
+
+    ConfigKey<String> KUBERNETES_NAMESPACE = ConfigKeys.builder(String.class, "kubernetes.namespace")
+            .description("Namespace for the KubernetesMachineLocation")
+            .build();
+
+    ConfigKey<String> KUBERNETES_RESOURCE_NAME = ConfigKeys.builder(String.class, "kubernetes.name")
+            .description("Name of the resource represented by the KubernetesMachineLocation")
+            .build();
+
+    ConfigKey<String> KUBERNETES_RESOURCE_TYPE = ConfigKeys.builder(String.class, "kubernetes.type")
+            .description("Type of the resource represented by the KubernetesMachineLocation")
+            .build();
+
+    public String getResourceName();
+
+    public String getResourceType();
+
+    public String getNamespace();
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesSshMachineLocation.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesSshMachineLocation.java b/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesSshMachineLocation.java
new file mode 100644
index 0000000..ad83f8f
--- /dev/null
+++ b/brooklyn-server/locations/container/src/main/java/org/apache/brooklyn/container/location/kubernetes/machine/KubernetesSshMachineLocation.java
@@ -0,0 +1,28 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location.machine;
+
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+/**
+ * A {@link MachineLocation} represemnting a Kubernetes resource that allows SSH access.
+ *
+ * @see {@link KubernetesSshMachineLocation}
+ */
+public class KubernetesSshMachineLocation extends SshMachineLocation implements KubernetesMachineLocation {
+
+    @Override
+    public String getResourceName() {
+        return config().get(KUBERNETES_RESOURCE_NAME);
+    }
+
+    @Override
+    public String getResourceType() {
+        return config().get(KUBERNETES_RESOURCE_TYPE);
+    }
+
+    @Override
+    public String getNamespace() {
+        return config().get(KUBERNETES_NAMESPACE);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/ImageChooserTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/ImageChooserTest.java b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/ImageChooserTest.java
new file mode 100644
index 0000000..8f28929
--- /dev/null
+++ b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/ImageChooserTest.java
@@ -0,0 +1,67 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class ImageChooserTest {
+
+    private ImageChooser chooser;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        chooser = new ImageChooser();
+    }
+    
+    @Test
+    public void testDefault() throws Exception {
+        assertEquals(chooser.chooseImage((String)null, null).get(), "cloudsoft/centos:7");
+    }
+
+    @Test
+    public void testCentos() throws Exception {
+        assertEquals(chooser.chooseImage("cEnToS", null).get(), "cloudsoft/centos:7");
+    }
+
+    @Test
+    public void testCentos7() throws Exception {
+        assertEquals(chooser.chooseImage("cEnToS", "7").get(), "cloudsoft/centos:7");
+    }
+
+    @Test
+    public void testUbnutu() throws Exception {
+        assertEquals(chooser.chooseImage("uBuNtU", null).get(), "cloudsoft/ubuntu:14.04");
+    }
+
+    @Test
+    public void testUbnutu14() throws Exception {
+        assertEquals(chooser.chooseImage("uBuNtU", "14.*").get(), "cloudsoft/ubuntu:14.04");
+    }
+
+    @Test
+    public void testUbnutu16() throws Exception {
+        assertEquals(chooser.chooseImage("uBuNtU", "16.*").get(), "cloudsoft/ubuntu:16.04");
+    }
+
+    @Test
+    public void testAbsentForCentos6() throws Exception {
+        assertFalse(chooser.chooseImage("cEnToS", "6").isPresent());
+    }
+
+    @Test
+    public void testAbsentForUbuntu15() throws Exception {
+        assertFalse(chooser.chooseImage("uBuNtU", "15").isPresent());
+    }
+
+    @Test
+    public void testAbsentForDebian() throws Exception {
+        assertFalse(chooser.chooseImage("debian", null).isPresent());
+    }
+
+    @Test
+    public void testAbsentForWrongOsFamily() throws Exception {
+        assertFalse(chooser.chooseImage("weirdOsFamily", null).isPresent());
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesCertsTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesCertsTest.java b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesCertsTest.java
new file mode 100644
index 0000000..27c1b79
--- /dev/null
+++ b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesCertsTest.java
@@ -0,0 +1,146 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.LogWatcher;
+import org.apache.brooklyn.test.LogWatcher.EventPredicates;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.text.Identifiers;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+
+public class KubernetesCertsTest {
+
+    private List<File> tempFiles;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        tempFiles = Lists.newArrayList();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (tempFiles != null) {
+            for (File tempFile : tempFiles) {
+                tempFile.delete();
+            }
+        }
+    }
+    
+    @Test
+    public void testCertsAbsent() throws Exception {
+        ConfigBag config = ConfigBag.newInstance();
+        KubernetesCerts certs = new KubernetesCerts(config);
+        
+        assertFalse(certs.caCertData.isPresent());
+        assertFalse(certs.clientCertData.isPresent());
+        assertFalse(certs.clientKeyData.isPresent());
+        assertFalse(certs.clientKeyAlgo.isPresent());
+        assertFalse(certs.clientKeyPassphrase.isPresent());
+    }
+
+    @Test
+    public void testCertsFromData() throws Exception {
+        ConfigBag config = ConfigBag.newInstance(ImmutableMap.builder()
+                .put(KubernetesLocationConfig.CA_CERT_DATA, "myCaCertData")
+                .put(KubernetesLocationConfig.CLIENT_CERT_DATA, "myClientCertData")
+                .put(KubernetesLocationConfig.CLIENT_KEY_DATA, "myClientKeyData")
+                .put(KubernetesLocationConfig.CLIENT_KEY_ALGO, "myClientKeyAlgo")
+                .put(KubernetesLocationConfig.CLIENT_KEY_PASSPHRASE, "myClientKeyPassphrase")
+                .build());
+        KubernetesCerts certs = new KubernetesCerts(config);
+        
+        assertEquals(certs.caCertData.get(), "myCaCertData");
+        assertEquals(certs.clientCertData.get(), "myClientCertData");
+        assertEquals(certs.clientKeyData.get(), "myClientKeyData");
+        assertEquals(certs.clientKeyAlgo.get(), "myClientKeyAlgo");
+        assertEquals(certs.clientKeyPassphrase.get(), "myClientKeyPassphrase");
+    }
+
+    @Test
+    public void testCertsFromFile() throws Exception {
+        ConfigBag config = ConfigBag.newInstance(ImmutableMap.builder()
+                .put(KubernetesLocationConfig.CA_CERT_FILE, newTempFile("myCaCertData").getAbsolutePath())
+                .put(KubernetesLocationConfig.CLIENT_CERT_FILE, newTempFile("myClientCertData").getAbsolutePath())
+                .put(KubernetesLocationConfig.CLIENT_KEY_FILE, newTempFile("myClientKeyData").getAbsolutePath())
+                .build());
+        KubernetesCerts certs = new KubernetesCerts(config);
+        
+        assertEquals(certs.caCertData.get(), "myCaCertData");
+        assertEquals(certs.clientCertData.get(), "myClientCertData");
+        assertEquals(certs.clientKeyData.get(), "myClientKeyData");
+    }
+    
+    @Test
+    public void testCertsFailsIfConflictingConfig() throws Exception {
+        ConfigBag config = ConfigBag.newInstance(ImmutableMap.builder()
+                .put(KubernetesLocationConfig.CA_CERT_DATA, "myCaCertData")
+                .put(KubernetesLocationConfig.CA_CERT_FILE, newTempFile("differentCaCertData").getAbsolutePath())
+                .build());
+        try {
+            new KubernetesCerts(config);
+            Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureContains(e, "Duplicate conflicting configuration for caCertData and caCertFile");
+        }
+    }
+    
+    @Test
+    public void testCertsWarnsIfConflictingConfig() throws Exception {
+        ConfigBag config = ConfigBag.newInstance(ImmutableMap.builder()
+                .put(KubernetesLocationConfig.CA_CERT_DATA, "myCaCertData")
+                .put(KubernetesLocationConfig.CA_CERT_FILE, newTempFile("myCaCertData").getAbsolutePath())
+                .build());
+        
+        String loggerName = KubernetesCerts.class.getName();
+        ch.qos.logback.classic.Level logLevel = ch.qos.logback.classic.Level.WARN;
+        Predicate<ILoggingEvent> filter = EventPredicates.containsMessage("Duplicate (matching) configuration for " 
+                    + "caCertData and caCertFile (continuing)");
+        LogWatcher watcher = new LogWatcher(loggerName, logLevel, filter);
+
+        watcher.start();
+        KubernetesCerts certs;
+        try {
+            certs = new KubernetesCerts(config);
+            watcher.assertHasEvent();
+        } finally {
+            watcher.close();
+        }
+        
+        assertEquals(certs.caCertData.get(), "myCaCertData");
+    }
+    
+    @Test
+    public void testCertsFailsIfFileNotFound() throws Exception {
+        ConfigBag config = ConfigBag.newInstance(ImmutableMap.builder()
+                .put(KubernetesLocationConfig.CA_CERT_FILE, "/path/to/fileDoesNotExist-"+Identifiers.makeRandomId(8))
+                .build());
+        try {
+            new KubernetesCerts(config);
+            Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureContains(e, "not found on classpath or filesystem");
+        }
+    }
+    
+    private File newTempFile(String contents) throws Exception {
+        File file = File.createTempFile("KubernetesCertsTest", ".txt");
+        tempFiles.add(file);
+        Files.write(contents, file, Charsets.UTF_8);
+        return file;
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationLiveTest.java b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationLiveTest.java
new file mode 100644
index 0000000..4fb416f
--- /dev/null
+++ b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationLiveTest.java
@@ -0,0 +1,226 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.MachineDetails;
+import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.location.BasicMachineDetails;
+import org.apache.brooklyn.core.location.LocationConfigKeys;
+import org.apache.brooklyn.core.location.access.PortForwardManager;
+import org.apache.brooklyn.core.location.access.PortForwardManagerLocationResolver;
+import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.net.HostAndPort;
+
+import io.cloudsoft.amp.containerservice.kubernetes.location.machine.KubernetesMachineLocation;
+import io.cloudsoft.amp.containerservice.kubernetes.location.machine.KubernetesSshMachineLocation;
+
+/**
+/**
+ * Live tests for deploying simple containers. Particularly useful during dev, but not so useful
+ * after that (because assumes the existence of a kubernetes endpoint). It needs configured with
+ * something like:
+ *
+ *   {@code -Dtest.amp.kubernetes.endpoint=http://10.104.2.206:8080}).
+ *
+ * The QA Framework is more important for that - hence these tests (trying to be) kept simple
+ * and focused.
+ */
+public class KubernetesLocationLiveTest extends BrooklynAppLiveTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(KubernetesLocationLiveTest.class);
+
+    public static final String KUBERNETES_ENDPOINT = System.getProperty("test.amp.kubernetes.endpoint", "");
+    public static final String IDENTITY = System.getProperty("test.amp.kubernetes.identity", "");
+    public static final String CREDENTIAL = System.getProperty("test.amp.kubernetes.credential", "");
+
+    protected KubernetesLocation loc;
+    protected List<KubernetesMachineLocation> machines;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        machines = Lists.newCopyOnWriteArrayList();
+    }
+
+    // FIXME: Clear up properly: Test leaves deployment, replicas and pods behind if obtain fails.
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        for (KubernetesMachineLocation machine : machines) {
+            try {
+                loc.release(machine);
+            } catch (Exception e) {
+                LOG.error("Error releasing machine "+machine+" in location "+loc, e);
+            }
+        }
+        super.tearDown();
+    }
+
+    protected KubernetesLocation newKubernetesLocation(Map<String, ?> flags) throws Exception {
+        Map<String,?> allFlags = MutableMap.<String,Object>builder()
+                .put("identity", IDENTITY)
+                .put("credential", CREDENTIAL)
+                .put("endpoint", KUBERNETES_ENDPOINT)
+                .putAll(flags)
+                .build();
+        return (KubernetesLocation) mgmt.getLocationRegistry().getLocationManaged("kubernetes", allFlags);
+    }
+
+    @Test(groups={"Live"})
+    public void testDefault() throws Exception {
+        // Default is "cloudsoft/centos:7"
+        runImage(ImmutableMap.<String, Object>of(), "centos", "7");
+    }
+
+    @Test(groups={"Live"})
+    public void testMatchesCentos() throws Exception {
+        runImage(ImmutableMap.<String, Object>of(KubernetesLocationConfig.OS_FAMILY.getName(), "centos"), "centos", "7");
+    }
+
+    @Test(groups={"Live"})
+    public void testMatchesCentos7() throws Exception {
+        ImmutableMap<String, Object> conf = ImmutableMap.<String, Object>of(
+                KubernetesLocationConfig.OS_FAMILY.getName(), "centos",
+                KubernetesLocationConfig.OS_VERSION_REGEX.getName(), "7.*");
+        runImage(conf, "centos", "7");
+    }
+
+    @Test(groups={"Live"})
+    public void testMatchesUbuntu() throws Exception {
+        runImage(ImmutableMap.<String, Object>of(KubernetesLocationConfig.OS_FAMILY.getName(), "ubuntu"), "ubuntu", "14.04");
+    }
+
+    @Test(groups={"Live"})
+    public void testMatchesUbuntu16() throws Exception {
+        ImmutableMap<String, Object> conf = ImmutableMap.<String, Object>of(
+                KubernetesLocationConfig.OS_FAMILY.getName(), "ubuntu",
+                KubernetesLocationConfig.OS_VERSION_REGEX.getName(), "16.*");
+        runImage(conf, "ubuntu", "16.04");
+    }
+
+    @Test(groups={"Live"})
+    public void testCloudsoftCentos7() throws Exception {
+        runImage(ImmutableMap.of(KubernetesLocationConfig.IMAGE.getName(), "cloudsoft/centos:7"), "centos", "7");
+    }
+
+    @Test(groups={"Live"})
+    public void testCloudsoftUbuntu14() throws Exception {
+        runImage(ImmutableMap.of(KubernetesLocationConfig.IMAGE.getName(), "cloudsoft/ubuntu:14.04"), "ubuntu", "14.04");
+    }
+
+    @Test(groups={"Live"})
+    public void testCloudsoftUbuntu16() throws Exception {
+        runImage(ImmutableMap.of(KubernetesLocationConfig.IMAGE.getName(), "cloudsoft/ubuntu:16.04"), "ubuntu", "16.04");
+    }
+
+    @Test(groups={"Live"})
+    public void testFailsForNonMatching() throws Exception {
+        ImmutableMap<String, Object> conf = ImmutableMap.<String, Object>of(
+                KubernetesLocationConfig.OS_FAMILY.getName(), "weirdOsFamiliy");
+        try {
+            runImage(conf, null, null);
+            Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureContains(e, "No matching image found");
+        }
+    }
+
+    protected void runImage(Map<String, ?> config, String expectedOs, String expectedVersion) throws Exception {
+        loc = newKubernetesLocation(ImmutableMap.<String, Object>of());
+        SshMachineLocation machine = newContainerMachine(loc, ImmutableMap.<String, Object>builder()
+                .putAll(config)
+                .put(LocationConfigKeys.CALLER_CONTEXT.getName(), app)
+                .build());
+
+        assertTrue(machine.isSshable(), "not sshable machine="+machine);
+        assertOsNameContains(machine, expectedOs, expectedVersion);
+        assertMachinePasswordSecure(machine);
+    }
+
+    @Test(groups={"Live"})
+    protected void testUsesSuppliedLoginPassword() throws Exception {
+        // Because defaulting to "cloudsoft/centos:7", it knows to set the loginUserPassword
+        // on container creation.
+        String password = "myCustomP4ssword";
+        loc = newKubernetesLocation(ImmutableMap.<String, Object>of());
+        SshMachineLocation machine = newContainerMachine(loc, ImmutableMap.<String, Object>builder()
+                .put(KubernetesLocationConfig.LOGIN_USER_PASSWORD.getName(), password)
+                .put(LocationConfigKeys.CALLER_CONTEXT.getName(), app)
+                .build());
+
+        assertTrue(machine.isSshable(), "not sshable machine="+machine);
+        assertEquals(machine.config().get(SshMachineLocation.PASSWORD), password);
+    }
+
+    @Test(groups={"Live"})
+    public void testOpenPorts() throws Exception {
+        List<Integer> inboundPorts = ImmutableList.of(22, 443, 8000, 8081);
+        loc = newKubernetesLocation(ImmutableMap.<String, Object>of());
+        SshMachineLocation machine = newContainerMachine(loc, ImmutableMap.<String, Object>builder()
+                .put(KubernetesLocationConfig.IMAGE.getName(), "cloudsoft/centos:7")
+                .put(KubernetesLocationConfig.LOGIN_USER_PASSWORD.getName(), "p4ssw0rd")
+                .put(KubernetesLocationConfig.INBOUND_PORTS.getName(), inboundPorts)
+                .put(LocationConfigKeys.CALLER_CONTEXT.getName(), app)
+                .build());
+        assertTrue(machine.isSshable());
+
+        String publicHostText = machine.getSshHostAndPort().getHostText();
+        PortForwardManager pfm = (PortForwardManager) mgmt.getLocationRegistry().getLocationManaged(PortForwardManagerLocationResolver.PFM_GLOBAL_SPEC);
+        for (int targetPort : inboundPorts) {
+            HostAndPort mappedPort = pfm.lookup(machine, targetPort);
+            assertNotNull(mappedPort, "no mapping for targetPort "+targetPort);
+            assertEquals(mappedPort.getHostText(), publicHostText);
+            assertTrue(mappedPort.hasPort(), "no port-part in "+mappedPort+" for targetPort "+targetPort);
+        }
+    }
+
+    protected void assertOsNameContains(SshMachineLocation machine, String expectedNamePart, String expectedVersionPart) {
+        MachineDetails machineDetails = app.getExecutionContext()
+                .submit(BasicMachineDetails.taskForSshMachineLocation(machine))
+                .getUnchecked();
+        OsDetails osDetails = machineDetails.getOsDetails();
+        String osName = osDetails.getName();
+        String osVersion = osDetails.getVersion();
+        assertTrue(osName != null && osName.toLowerCase().contains(expectedNamePart), "osDetails="+osDetails);
+        assertTrue(osVersion != null && osVersion.toLowerCase().contains(expectedVersionPart), "osDetails="+osDetails);
+    }
+
+    protected SshMachineLocation newContainerMachine(KubernetesLocation loc, Map<?, ?> flags) throws Exception {
+        KubernetesMachineLocation result = loc.obtain(flags);
+        machines.add(result);
+        assertTrue(result instanceof KubernetesSshMachineLocation);
+        return (SshMachineLocation) result;
+    }
+
+    protected void assertMachinePasswordSecure(SshMachineLocation machine) {
+        String password = machine.config().get(SshMachineLocation.PASSWORD);
+        assertTrue(password.length() > 10, "password="+password);
+        boolean hasUpper = false;
+        boolean hasLower = false;
+        boolean hasNonAlphabetic = false;
+        for (char c : password.toCharArray()) {
+            if (Character.isUpperCase(c)) hasUpper = true;
+            if (Character.isLowerCase(c)) hasLower = true;
+            if (!Character.isAlphabetic(c)) hasNonAlphabetic = true;
+        }
+        assertTrue(hasUpper && hasLower && hasNonAlphabetic, "password="+password);
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationResolverTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationResolverTest.java b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationResolverTest.java
new file mode 100644
index 0000000..acd366b
--- /dev/null
+++ b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationResolverTest.java
@@ -0,0 +1,84 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class KubernetesLocationResolverTest extends BrooklynMgmtUnitTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(KubernetesLocationResolverTest.class);
+    
+    private BrooklynProperties brooklynProperties;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        super.setUp();
+        brooklynProperties = mgmt.getBrooklynProperties();
+
+        brooklynProperties.put("brooklyn.location.kubernetes.identity", "kubernetes-id");
+        brooklynProperties.put("brooklyn.location.kubernetes.credential", "kubernetes-cred");
+    }
+
+    @Test
+    public void testGivesCorrectLocationType() {
+        LocationSpec<?> spec = getLocationSpec("kubernetes");
+        assertEquals(spec.getType(), KubernetesLocation.class);
+
+        KubernetesLocation loc = resolve("kubernetes");
+        assertTrue(loc instanceof KubernetesLocation, "loc="+loc);
+    }
+
+    @Test
+    public void testParametersInSpecString() {
+        KubernetesLocation loc = resolve("kubernetes(endpoint=myMasterUrl)");
+        assertEquals(loc.getConfig(KubernetesLocation.MASTER_URL), "myMasterUrl");
+    }
+
+    @Test
+    public void testTakesDotSeparateProperty() {
+        brooklynProperties.put("brooklyn.location.kubernetes.endpoint", "myMasterUrl");
+        KubernetesLocation loc = resolve("kubernetes");
+        assertEquals(loc.getConfig(KubernetesLocation.MASTER_URL), "myMasterUrl");
+    }
+
+    @Test
+    public void testPropertiesPrecedence() {
+        // prefer those in "spec" over everything else
+        brooklynProperties.put("brooklyn.location.named.mykubernetes", "kubernetes:(loginUser=\"loginUser-inSpec\")");
+
+        brooklynProperties.put("brooklyn.location.named.mykubernetes.loginUser", "loginUser-inNamed");
+        brooklynProperties.put("brooklyn.location.kubernetes.loginUser", "loginUser-inDocker");
+
+        // prefer those in "named" over everything else
+        brooklynProperties.put("brooklyn.location.named.mykubernetes.privateKeyFile", "privateKeyFile-inNamed");
+        brooklynProperties.put("brooklyn.location.kubernetes.privateKeyFile", "privateKeyFile-inDocker");
+
+        // prefer those in kubernetes-specific
+        brooklynProperties.put("brooklyn.location.kubernetes.publicKeyFile", "publicKeyFile-inDocker");
+
+        Map<String, Object> conf = resolve("named:mykubernetes").config().getBag().getAllConfig();
+
+        assertEquals(conf.get("loginUser"), "loginUser-inSpec");
+        assertEquals(conf.get("privateKeyFile"), "privateKeyFile-inNamed");
+        assertEquals(conf.get("publicKeyFile"), "publicKeyFile-inDocker");
+    }
+
+    private LocationSpec<?> getLocationSpec(String spec) {
+        LOG.debug("Obtaining location spec '{}'", spec);
+        return mgmt.getLocationRegistry().getLocationSpec(spec).get();
+    }
+
+    private KubernetesLocation resolve(String spec) {
+        LOG.debug("Resolving location spec '{}'", spec);
+        return (KubernetesLocation) mgmt.getLocationRegistry().getLocationManaged(spec);
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationYamlLiveTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationYamlLiveTest.java b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationYamlLiveTest.java
new file mode 100644
index 0000000..6c09b16
--- /dev/null
+++ b/brooklyn-server/locations/container/src/test/java/org/apache/brooklyn/container/location/kubernetes/KubernetesLocationYamlLiveTest.java
@@ -0,0 +1,518 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Predicates.notNull;
+import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationLiveTest.CREDENTIAL;
+import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationLiveTest.IDENTITY;
+import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationLiveTest.KUBERNETES_ENDPOINT;
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertAttributeEquals;
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertAttributeEqualsEventually;
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertAttributeEventually;
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertAttributeEventuallyNonNull;
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertEntityHealthy;
+import static org.apache.brooklyn.test.Asserts.succeedsEventually;
+import static org.apache.brooklyn.util.http.HttpAsserts.assertHttpStatusCodeEventuallyEquals;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityPredicates;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.network.OnPublicNetworkEnricher;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
+import org.apache.brooklyn.entity.stock.BasicStartable;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.net.Networking;
+import org.apache.brooklyn.util.text.Identifiers;
+import org.apache.logging.log4j.util.Strings;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.net.HostAndPort;
+
+import io.cloudsoft.amp.containerservice.dockercontainer.DockerContainer;
+import io.cloudsoft.amp.containerservice.kubernetes.entity.KubernetesPod;
+import io.cloudsoft.amp.containerservice.kubernetes.entity.KubernetesResource;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+/**
+ * Live tests for deploying simple blueprints. Particularly useful during dev, but not so useful
+ * after that (because assumes the existence of a kubernetes endpoint). It needs configured with
+ * something like:
+ *
+ *   {@code -Dtest.amp.kubernetes.endpoint=http://10.104.2.206:8080}).
+ *
+ * The QA Framework is more important for that - hence these tests (trying to be) kept simple
+ * and focused.
+ */
+public class KubernetesLocationYamlLiveTest extends AbstractYamlTest {
+
+    protected KubernetesLocation loc;
+    protected List<MachineLocation> machines;
+    protected String locationYaml;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        locationYaml = Joiner.on("\n").join(
+                "location:",
+                "  kubernetes:",
+                "    " + KubernetesLocationConfig.MASTER_URL.getName() + ": \"" + KUBERNETES_ENDPOINT + "\"",
+                "    " + (Strings.isBlank(IDENTITY) ? "" : "identity: "+IDENTITY),
+                "    " + (Strings.isBlank(CREDENTIAL) ? "" : "credential: "+CREDENTIAL));
+    }
+
+    @Test(groups={"Live"})
+    public void testLoginPasswordOverride() throws Exception {
+        String customPassword = "myDifferentPassword";
+
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + EmptySoftwareProcess.class.getName(),
+                "    brooklyn.config:",
+                "      provisioning.properties:",
+                "        " + KubernetesLocationConfig.LOGIN_USER_PASSWORD.getName() + ": " + customPassword);
+
+        Entity app = createStartWaitAndLogApplication(yaml);
+        EmptySoftwareProcess entity = Iterables.getOnlyElement(Entities.descendantsAndSelf(app, EmptySoftwareProcess.class));
+
+        SshMachineLocation machine = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class).get();
+        assertEquals(machine.config().get(SshMachineLocation.PASSWORD), customPassword);
+        assertTrue(machine.isSshable());
+    }
+
+    @Test(groups={"Live"})
+    public void testNetcatServer() throws Exception {
+        // Runs as root user (hence not `sudo yum install ...`)
+        // breaks if shell.env uses attributeWhenReady, so not doing that - see testNetcatServerWithDslInShellEnv()
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + VanillaSoftwareProcess.class.getName(),
+                "    brooklyn.parameters:",
+                "      - name: netcat.port",
+                "        type: port",
+                "        default: 8081",
+                "    brooklyn.config:",
+                "      install.command: |",
+                "        yum install -y nc",
+                "      launch.command: |",
+                "        echo $MESSAGE | nc -l $NETCAT_PORT &",
+                "        echo $! > $PID_FILE",
+                "      shell.env:",
+                "        MESSAGE: mymessage",
+                "        NETCAT_PORT: $brooklyn:attributeWhenReady(\"netcat.port\")",
+                "    brooklyn.enrichers:",
+                "      - type: " + OnPublicNetworkEnricher.class.getName(),
+                "        brooklyn.config:",
+                "          " + OnPublicNetworkEnricher.SENSORS.getName() + ":",
+                "            - netcat.port");
+
+        Entity app = createStartWaitAndLogApplication(yaml);
+        VanillaSoftwareProcess entity = Iterables.getOnlyElement(Entities.descendantsAndSelf(app, VanillaSoftwareProcess.class));
+
+        String publicMapped = assertAttributeEventuallyNonNull(entity, Sensors.newStringSensor("netcat.endpoint.mapped.public"));
+        HostAndPort publicPort = HostAndPort.fromString(publicMapped);
+
+        assertTrue(Networking.isReachable(publicPort), "publicPort="+publicPort);
+    }
+
+    @Test(groups={"Live"})
+    public void testInterContainerNetworking() throws Exception {
+        String message = "mymessage";
+        int netcatPort = 8081;
+
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + VanillaSoftwareProcess.class.getName(),
+                "    name: server1",
+                "    brooklyn.parameters:",
+                "      - name: netcat.port",
+                "        type: port",
+                "        default: " + netcatPort,
+                "    brooklyn.config:",
+                "      install.command: |",
+                "        yum install -y nc",
+                "      launch.command: |",
+                "        echo " + message + " | nc -l " + netcatPort + " > netcat.out &",
+                "        echo $! > $PID_FILE",
+                "  - type: " + VanillaSoftwareProcess.class.getName(),
+                "    name: server2",
+                "    brooklyn.config:",
+                "      install.command: |",
+                "        yum install -y nc",
+                "      launch.command: true",
+                "      checkRunning.command: true");
+
+        Entity app = createStartWaitAndLogApplication(yaml);
+        Entities.dumpInfo(app);
+
+        Entity server1 = Iterables.find(Entities.descendantsAndSelf(app), EntityPredicates.displayNameEqualTo("server1"));
+        Entity server2 = Iterables.find(Entities.descendantsAndSelf(app), EntityPredicates.displayNameEqualTo("server2"));
+
+        SshMachineLocation machine1 = Machines.findUniqueMachineLocation(server1.getLocations(), SshMachineLocation.class).get();
+        SshMachineLocation machine2 = Machines.findUniqueMachineLocation(server2.getLocations(), SshMachineLocation.class).get();
+
+        String addr1 = server1.sensors().get(Attributes.SUBNET_ADDRESS);
+        String addr2 = server2.sensors().get(Attributes.SUBNET_ADDRESS);
+
+        // Ping between containers
+        int result1 = machine1.execCommands("ping-server2", ImmutableList.of("ping -c 4 " + addr2));
+        int result2 = machine2.execCommands("ping-server1", ImmutableList.of("ping -c 4 " + addr1));
+
+        // Reach netcat port from other container
+        int result3 = machine2.execCommands("nc-to-server1", ImmutableList.of(
+                "echo \"fromServer2\" | nc " + addr1 + " " + netcatPort + " > netcat.out",
+                "cat netcat.out",
+                "grep " + message + " netcat.out"));
+
+        String errMsg = "result1="+result1+"; result2="+result2+"; result3="+result3;
+        assertEquals(result1, 0, errMsg);
+        assertEquals(result2, 0, errMsg);
+        assertEquals(result3, 0, errMsg);
+    }
+
+    @Test(groups={"Live"})
+    public void testTomcatPod() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + KubernetesPod.class.getName(),
+                "    brooklyn.config:",
+                "      docker.container.imageName: tomcat",
+                "      docker.container.inboundPorts: [ \"8080\" ]");
+
+        runTomcat(yaml, KubernetesPod.class);
+    }
+
+    @Test(groups={"Live"})
+    public void testTomcatPodExtras() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + KubernetesPod.class.getName(),
+                "    brooklyn.config:",
+                "      docker.container.imageName: tomcat",
+                "      docker.container.inboundPorts: [ \"8080\" ]",
+                "      metadata:",
+                "        extra: test");
+
+        KubernetesPod entity = runTomcat(yaml, KubernetesPod.class);
+
+        String namespace = entity.sensors().get(KubernetesPod.KUBERNETES_NAMESPACE);
+        String podName = entity.sensors().get(KubernetesPod.KUBERNETES_POD);
+        KubernetesClient client = getClient(entity);
+        Pod pod = client.pods().inNamespace(namespace).withName(podName).get();
+        Map<String, String> labels = pod.getMetadata().getLabels();
+        assertTrue(labels.containsKey("extra"));
+        assertEquals(labels.get("extra"), "test");
+    }
+
+    @Test(groups={"Live"})
+    public void testTomcatContainer() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + DockerContainer.class.getName(),
+                "    brooklyn.config:",
+                "      docker.container.imageName: tomcat",
+                "      docker.container.inboundPorts: [ \"8080\" ]");
+
+        runTomcat(yaml, DockerContainer.class);
+    }
+
+    /**
+     * Assumes that the container entity uses port 8080.
+     */
+    protected <T extends Entity> T runTomcat(String yaml, Class<T> type) throws Exception {
+        Entity app = createStartWaitAndLogApplication(yaml);
+        T entity = Iterables.getOnlyElement(Entities.descendantsAndSelf(app, type));
+
+        Entities.dumpInfo(app);
+        String publicMapped = assertAttributeEventuallyNonNull(entity, Sensors.newStringSensor("docker.port.8080.mapped.public"));
+        HostAndPort publicPort = HostAndPort.fromString(publicMapped);
+
+        assertReachableEventually(publicPort);
+        assertHttpStatusCodeEventuallyEquals("http://"+publicPort.getHostText()+":"+publicPort.getPort(), 200);
+
+        return entity;
+    }
+
+    @Test(groups={"Live"})
+    public void testWordpressInContainersWithStartableParent() throws Exception {
+        // TODO docker.container.inboundPorts doesn't accept list of ints - need to use quotes
+        String randomId = Identifiers.makeRandomLowercaseId(4);
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + BasicStartable.class.getName(),
+                "    brooklyn.children:",
+                "      - type: " + DockerContainer.class.getName(),
+                "        id: wordpress-mysql",
+                "        name: mysql",
+                "        brooklyn.config:",
+                "          docker.container.imageName: mysql:5.6",
+                "          docker.container.inboundPorts:",
+                "            - \"3306\"",
+                "          docker.container.environment:",
+                "            MYSQL_ROOT_PASSWORD: \"password\"",
+                "          provisioning.properties:",
+                "            deployment: wordpress-mysql-" + randomId,
+                "      - type: " + DockerContainer.class.getName(),
+                "        id: wordpress",
+                "        name: wordpress",
+                "        brooklyn.config:",
+                "          docker.container.imageName: wordpress:4-apache",
+                "          docker.container.inboundPorts:",
+                "            - \"80\"",
+                "          docker.container.environment:",
+                "            WORDPRESS_DB_HOST: \"wordpress-mysql-" + randomId + "\"",
+                "            WORDPRESS_DB_PASSWORD: \"password\"",
+                "          provisioning.properties:",
+                "            deployment: wordpress-" + randomId);
+
+        runWordpress(yaml, randomId);
+    }
+
+    @Test(groups={"Live"})
+    public void testWordpressInPodsWithStartableParent() throws Exception {
+        // TODO docker.container.inboundPorts doesn't accept list of ints - need to use quotes
+        String randomId = Identifiers.makeRandomLowercaseId(4);
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + BasicStartable.class.getName(),
+                "    brooklyn.children:",
+                "      - type: " + KubernetesPod.class.getName(),
+                "        id: wordpress-mysql",
+                "        name: mysql",
+                "        brooklyn.config:",
+                "          docker.container.imageName: mysql:5.6",
+                "          docker.container.inboundPorts:",
+                "            - \"3306\"",
+                "          docker.container.environment:",
+                "            MYSQL_ROOT_PASSWORD: \"password\"",
+                "          deployment: wordpress-mysql-" + randomId,
+                "      - type: " + KubernetesPod.class.getName(),
+                "        id: wordpress",
+                "        name: wordpress",
+                "        brooklyn.config:",
+                "          docker.container.imageName: wordpress:4-apache",
+                "          docker.container.inboundPorts:",
+                "            - \"80\"",
+                "          docker.container.environment:",
+                "            WORDPRESS_DB_HOST: \"wordpress-mysql-" + randomId + "\"",
+                "            WORDPRESS_DB_PASSWORD: \"password\"",
+                "          deployment: wordpress-" + randomId);
+
+        runWordpress(yaml, randomId);
+    }
+
+    @Test(groups={"Live"})
+    public void testWordpressInPods() throws Exception {
+        // TODO docker.container.inboundPorts doesn't accept list of ints - need to use quotes
+        String randomId = Identifiers.makeRandomLowercaseId(4);
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + KubernetesPod.class.getName(),
+                "    id: wordpress-mysql",
+                "    name: mysql",
+                "    brooklyn.config:",
+                "      docker.container.imageName: mysql:5.6",
+                "      docker.container.inboundPorts:",
+                "        - \"3306\"",
+                "      docker.container.environment:",
+                "        MYSQL_ROOT_PASSWORD: \"password\"",
+                "      deployment: wordpress-mysql-" + randomId,
+                "  - type: " + KubernetesPod.class.getName(),
+                "    id: wordpress",
+                "    name: wordpress",
+                "    brooklyn.config:",
+                "      docker.container.imageName: wordpress:4-apache",
+                "      docker.container.inboundPorts:",
+                "        - \"80\"",
+                "      docker.container.environment:",
+                "        WORDPRESS_DB_HOST: \"wordpress-mysql-" + randomId + "\"",
+                "        WORDPRESS_DB_PASSWORD: \"password\"",
+                "      deployment: wordpress-" + randomId);
+
+        runWordpress(yaml, randomId);
+    }
+
+    /**
+     * Assumes that the {@link DockerContainer} entities have display names of "mysql" and "wordpress",
+     * and that they use ports 3306 and 80 respectively.
+     */
+    protected void runWordpress(String yaml, String randomId) throws Exception {
+        Entity app = createStartWaitAndLogApplication(yaml);
+        Entities.dumpInfo(app);
+
+        Iterable<DockerContainer> containers = Entities.descendantsAndSelf(app, DockerContainer.class);
+        DockerContainer mysql = Iterables.find(containers, EntityPredicates.displayNameEqualTo("mysql"));
+        DockerContainer wordpress = Iterables.find(containers, EntityPredicates.displayNameEqualTo("wordpress"));
+
+        String mysqlPublicPort = assertAttributeEventuallyNonNull(mysql, Sensors.newStringSensor("docker.port.3306.mapped.public"));
+        assertReachableEventually(HostAndPort.fromString(mysqlPublicPort));
+        assertAttributeEquals(mysql, KubernetesPod.KUBERNETES_NAMESPACE, "amp");
+        assertAttributeEquals(mysql, KubernetesPod.KUBERNETES_SERVICE, "wordpress-mysql-" + randomId);
+
+        String wordpressPublicPort = assertAttributeEventuallyNonNull(wordpress, Sensors.newStringSensor("docker.port.80.mapped.public"));
+        assertReachableEventually(HostAndPort.fromString(wordpressPublicPort));
+        assertAttributeEquals(wordpress, KubernetesPod.KUBERNETES_NAMESPACE, "amp");
+        assertAttributeEquals(wordpress, KubernetesPod.KUBERNETES_SERVICE, "wordpress-" + randomId);
+
+        // TODO more assertions (e.g. wordpress can successfully reach the database)
+    }
+
+    @Test(groups={"Live"})
+    public void testPod() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + KubernetesPod.class.getName(),
+                "    brooklyn.config:",
+                "      docker.container.imageName: tomcat",
+                "      docker.container.inboundPorts:",
+                "        - \"8080\"",
+                "      shell.env:",
+                "        CLUSTER_ID: \"id\"",
+                "        CLUSTER_TOKEN: \"token\"");
+
+        Entity app = createStartWaitAndLogApplication(yaml);
+        checkPod(app, KubernetesPod.class);
+    }
+
+    /* Test disabled as QA framework AMP does not have catalog entries deployed yet */
+    @Test(groups={"Live"}, enabled=false)
+    public void testPodCatalogEntry() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: kubernetes-pod-entity",
+                "    brooklyn.config:",
+                "      docker.container.imageName: tomcat",
+                "      docker.container.inboundPorts:",
+                "        - \"8080\"",
+                "      shell.env:",
+                "        CLUSTER_ID: \"id\"",
+                "        CLUSTER_TOKEN: \"token\"");
+
+        Entity app = createStartWaitAndLogApplication(yaml);
+        checkPod(app, KubernetesPod.class);
+    }
+
+    protected <T extends Entity> void checkPod(Entity app, Class<T> type) {
+        T container = Iterables.getOnlyElement(Entities.descendantsAndSelf(app, type));
+
+        Entities.dumpInfo(app);
+
+        String publicMapped = assertAttributeEventuallyNonNull(container, Sensors.newStringSensor("docker.port.8080.mapped.public"));
+        HostAndPort publicPort = HostAndPort.fromString(publicMapped);
+
+        assertReachableEventually(publicPort);
+        assertHttpStatusCodeEventuallyEquals("http://"+publicPort.getHostText()+":"+publicPort.getPort(), 200);
+    }
+
+    @Test(groups={"Live"})
+    public void testNginxReplicationController() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + KubernetesResource.class.getName(),
+                "    id: nginx-replication-controller",
+                "    name: \"nginx-replication-controller\"",
+                "    brooklyn.config:",
+                "      resource: classpath://nginx-replication-controller.yaml");
+
+        Entity app = createStartWaitAndLogApplication(yaml);
+        checkNginxResource(app, KubernetesResource.class);
+    }
+
+    protected <T extends Entity> void checkNginxResource(Entity app, Class<T> type) {
+        T entity = Iterables.getOnlyElement(Entities.descendantsAndSelf(app, type));
+
+        Entities.dumpInfo(app);
+
+        assertEntityHealthy(entity);
+        assertAttributeEqualsEventually(entity, KubernetesResource.RESOURCE_NAME, "nginx-replication-controller");
+        assertAttributeEqualsEventually(entity, KubernetesResource.RESOURCE_TYPE, "ReplicationController");
+        assertAttributeEqualsEventually(entity, KubernetesResource.KUBERNETES_NAMESPACE, "default");
+        assertAttributeEventually(entity, SoftwareProcess.ADDRESS, and(notNull(), not(equalTo("0.0.0.0"))));
+        assertAttributeEventually(entity, SoftwareProcess.SUBNET_ADDRESS, and(notNull(), not(equalTo("0.0.0.0"))));
+    }
+
+    @Test(groups={"Live"})
+    public void testNginxService() throws Exception {
+        String yaml = Joiner.on("\n").join(
+                locationYaml,
+                "services:",
+                "  - type: " + KubernetesResource.class.getName(),
+                "    id: nginx-replication-controller",
+                "    name: \"nginx-replication-controller\"",
+                "    brooklyn.config:",
+                "      resource: classpath://nginx-replication-controller.yaml",
+                "  - type: " + KubernetesResource.class.getName(),
+                "    id: nginx-service",
+                "    name: \"nginx-service\"",
+                "    brooklyn.config:",
+                "      resource: classpath://nginx-service.yaml");
+        Entity app = createStartWaitAndLogApplication(yaml);
+
+        Iterable<KubernetesResource> resources = Entities.descendantsAndSelf(app, KubernetesResource.class);
+        KubernetesResource nginxReplicationController = Iterables.find(resources, EntityPredicates.displayNameEqualTo("nginx-replication-controller"));
+        KubernetesResource nginxService = Iterables.find(resources, EntityPredicates.displayNameEqualTo("nginx-service"));
+
+        assertEntityHealthy(nginxReplicationController);
+        assertEntityHealthy(nginxService);
+
+        Entities.dumpInfo(app);
+
+        Integer httpPort = assertAttributeEventuallyNonNull(nginxService, Sensors.newIntegerSensor("kubernetes.http.port"));
+        assertEquals(httpPort, Integer.valueOf(80));
+        String httpPublicPort = assertAttributeEventuallyNonNull(nginxService, Sensors.newStringSensor("kubernetes.http.endpoint.mapped.public"));
+        assertReachableEventually(HostAndPort.fromString(httpPublicPort));
+    }
+
+    protected void assertReachableEventually(final HostAndPort hostAndPort) {
+        succeedsEventually(new Runnable() {
+            public void run() {
+                assertTrue(Networking.isReachable(hostAndPort), "publicPort="+hostAndPort);
+            }});
+    }
+
+    public KubernetesClient getClient(Entity entity) {
+        MachineProvisioningLocation location = entity.sensors().get(SoftwareProcess.PROVISIONING_LOCATION);
+        if (location instanceof KubernetesLocation) {
+            KubernetesLocation kubernetes = (KubernetesLocation) location;
+            ConfigBag config = kubernetes.config().getBag();
+            KubernetesClientRegistry registry = kubernetes.config().get(KubernetesLocationConfig.KUBERNETES_CLIENT_REGISTRY);
+            KubernetesClient client = registry.getKubernetesClient(config);
+            return client;
+        }
+        throw new IllegalStateException("Cannot find KubernetesLocation on entity: " + Iterables.toString(entity.getLocations()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPod.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPod.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPod.java
deleted file mode 100644
index bf5444d..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPod.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.entity;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.BasicConfigInheritance;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.config.MapConfigKey;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.util.math.MathPredicates;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.reflect.TypeToken;
-
-import io.cloudsoft.amp.containerservice.dockercontainer.DockerContainer;
-import io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig;
-
-@ImplementedBy(KubernetesPodImpl.class)
-public interface KubernetesPod extends DockerContainer {
-
-    ConfigKey<String> NAMESPACE = KubernetesLocationConfig.NAMESPACE;
-
-    ConfigKey<Boolean> PRIVILEGED = KubernetesLocationConfig.PRIVILEGED;
-
-    @SuppressWarnings("serial")
-    ConfigKey<List<String>> PERSISTENT_VOLUMES = ConfigKeys.builder(new TypeToken<List<String>>() {})
-            .name("persistentVolumes")
-            .description("Persistent volumes used by the pod")
-            .build();
-
-    ConfigKey<String> DEPLOYMENT = ConfigKeys.builder(String.class)
-            .name("deployment")
-            .description("The name of the service the deployed pod will use")
-            .build();
-
-    ConfigKey<Integer> REPLICAS = ConfigKeys.builder(Integer.class)
-            .name("replicas")
-            .description("Number of replicas in the pod")
-            .constraint(MathPredicates.greaterThanOrEqual(1d))
-            .defaultValue(1)
-            .build();
-
-    @SuppressWarnings("serial")
-    ConfigKey<Map<String, String>> SECRETS = ConfigKeys.builder(new TypeToken<Map<String, String>>() {})
-            .name("secrets")
-            .description("Secrets to be added to the pod")
-            .build();
-
-    @SuppressWarnings("serial")
-    ConfigKey<Map<String, String>> LIMITS = ConfigKeys.builder(new TypeToken<Map<String, String>>() {})
-            .name("limits")
-            .description("Container resource limits for the pod")
-            .build();
-
-    MapConfigKey<Object> METADATA = new MapConfigKey.Builder<Object>(Object.class, "metadata")
-            .description("Metadata to set on the pod")
-            .defaultValue(ImmutableMap.<String, Object>of())
-            .typeInheritance(BasicConfigInheritance.DEEP_MERGE)
-            .runtimeInheritance(BasicConfigInheritance.NOT_REINHERITED_ELSE_DEEP_MERGE)
-            .build();
-
-    AttributeSensor<String> KUBERNETES_DEPLOYMENT = Sensors.builder(String.class, "kubernetes.deployment")
-            .description("Deployment resources run in")
-            .build();
-
-    AttributeSensor<String> KUBERNETES_NAMESPACE = Sensors.builder(String.class, "kubernetes.namespace")
-            .description("Namespace that resources run in")
-            .build();
-
-    AttributeSensor<String> KUBERNETES_SERVICE = Sensors.builder(String.class, "kubernetes.service")
-            .description("Service that exposes the deployment")
-            .build();
-
-    AttributeSensor<String> KUBERNETES_POD = Sensors.builder(String.class, "kubernetes.pod")
-            .description("Pod running the deployment")
-            .build();
-
-    String EMPTY = "Empty";
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPodImpl.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPodImpl.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPodImpl.java
deleted file mode 100644
index 2acf734..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesPodImpl.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.entity;
-
-import io.cloudsoft.amp.containerservice.dockercontainer.DockerContainerImpl;
-
-public class KubernetesPodImpl extends DockerContainerImpl implements KubernetesPod {
-
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResource.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResource.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResource.java
deleted file mode 100644
index 320c924..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResource.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.entity;
-
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.util.core.ResourcePredicates;
-
-@ImplementedBy(KubernetesResourceImpl.class)
-public interface KubernetesResource extends SoftwareProcess {
-
-    ConfigKey<String> RESOURCE_FILE = ConfigKeys.builder(String.class)
-                                             .name("resource")
-                                             .description("Kubernetes resource YAML file URI")
-                                             .constraint(ResourcePredicates.urlExists())
-                                             .build();
-
-    AttributeSensor<String> RESOURCE_TYPE = Sensors.builder(String.class, "kubernetes.resource.type")
-                                             .description("Kubernetes resource type")
-                                             .build();
-
-    AttributeSensor<String> RESOURCE_NAME = Sensors.builder(String.class, "kubernetes.resource.name")
-                                             .description("Kubernetes resource name")
-                                             .build();
-
-    AttributeSensor<String> KUBERNETES_NAMESPACE = KubernetesPod.KUBERNETES_NAMESPACE;
-
-    String POD = "Pod";
-    String DEPLOYMENT = "Deployment";
-    String REPLICA_SET = "ReplicaSet";
-    String CONFIG_MAP = "ConfigMap";
-    String PERSISTENT_VOLUME = "PersistentVolume";
-    String SECRET = "Secret";
-    String SERVICE = "Service";
-    String REPLICATION_CONTROLLER = "ReplicationController";
-    String NAMESPACE = "Namespace";
-
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResourceImpl.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResourceImpl.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResourceImpl.java
deleted file mode 100644
index 3e7dad3..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/entity/KubernetesResourceImpl.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.entity;
-
-import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl;
-
-public class KubernetesResourceImpl extends EmptySoftwareProcessImpl implements KubernetesResource {
-
-    @Override
-    public void init() {
-        super.init();
-
-        config().set(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true);
-        config().set(PROVISIONING_PROPERTIES.subKey("useJcloudsSshInit"), false);
-        config().set(PROVISIONING_PROPERTIES.subKey("waitForSshable"), false);
-        config().set(PROVISIONING_PROPERTIES.subKey("pollForFirstReachableAddress"), false);
-        config().set(EmptySoftwareProcessImpl.USE_SSH_MONITORING, false);
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/ImageChooser.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/ImageChooser.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/ImageChooser.java
deleted file mode 100644
index 1bda432..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/ImageChooser.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.location;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-import org.jclouds.compute.domain.OsFamily;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-
-public class ImageChooser {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ImageChooser.class);
-
-    public static class ImageMetadata {
-        private final OsFamily osFamily;
-        private final String osVersion;
-        private final String imageName;
-        
-        public ImageMetadata(OsFamily osFamily, String osVersion, String imageName) {
-            this.osFamily = checkNotNull(osFamily, "osFamily");
-            this.osVersion = checkNotNull(osVersion, "osVersion");
-            this.imageName = checkNotNull(imageName, "imageName");
-        }
-        
-        public boolean matches(@Nullable OsFamily osFamily, @Nullable String osVersionRegex) {
-            if (osFamily != null && osFamily != this.osFamily) return false;
-            if (osVersionRegex != null && !osVersion.matches(osVersionRegex)) return false;
-            return true;
-        }
-        
-        public String getImageName() {
-            return imageName;
-        }
-    }
-
-    private static final List<ImageMetadata> DEFAULT_IMAGES = ImmutableList.of(
-            new ImageMetadata(OsFamily.CENTOS, "7", "cloudsoft/centos:7"),
-            new ImageMetadata(OsFamily.UBUNTU, "14.04", "cloudsoft/ubuntu:14.04"),
-            new ImageMetadata(OsFamily.UBUNTU, "16.04", "cloudsoft/ubuntu:16.04"));
-    
-    private final List<ImageMetadata> images;
-
-    public ImageChooser() {
-        this.images = DEFAULT_IMAGES;
-    }
-    
-    public ImageChooser(List<? extends ImageMetadata> images) {
-        this.images = ImmutableList.copyOf(images);
-    }
-
-    public Optional<String> chooseImage(String osFamily, String osVersionRegex) {
-        return chooseImage((osFamily == null ? (OsFamily)null : OsFamily.fromValue(osFamily)), osVersionRegex);
-    }
-    
-    public Optional<String> chooseImage(OsFamily osFamily, String osVersionRegex) {
-        for (ImageMetadata imageMetadata : images) {
-            if (imageMetadata.matches(osFamily, osVersionRegex)) {
-                String imageName = imageMetadata.getImageName();
-                LOG.debug("Choosing container image {}, for osFamily={} and osVersionRegex={}", new Object[] {imageName, osFamily, osVersionRegex});
-                return Optional.of(imageName);
-            }
-        }
-        return Optional.absent();
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesCerts.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesCerts.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesCerts.java
deleted file mode 100644
index 9bb840f..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesCerts.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.location;
-
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CA_CERT_DATA;
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CA_CERT_FILE;
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CLIENT_CERT_DATA;
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CLIENT_CERT_FILE;
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CLIENT_KEY_ALGO;
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CLIENT_KEY_DATA;
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CLIENT_KEY_FILE;
-import static io.cloudsoft.amp.containerservice.kubernetes.location.KubernetesLocationConfig.CLIENT_KEY_PASSPHRASE;
-
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.util.core.ResourceUtils;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Optional;
-
-class KubernetesCerts {
-
-    private static final Logger LOG = LoggerFactory.getLogger(KubernetesCerts.class);
-
-    public final Optional<String> caCertData;
-    public final Optional<String> clientCertData;
-    public final Optional<String> clientKeyData;
-    public final Optional<String> clientKeyAlgo;
-    public final Optional<String> clientKeyPassphrase;
-    
-    public KubernetesCerts(ConfigBag config) {
-        caCertData = getData(CA_CERT_DATA, CA_CERT_FILE, config);
-        clientCertData = getData(CLIENT_CERT_DATA, CLIENT_CERT_FILE, config);
-        clientKeyData = getData(CLIENT_KEY_DATA, CLIENT_KEY_FILE, config);
-        clientKeyAlgo = getNonBlankOptional(CLIENT_KEY_ALGO, config);
-        clientKeyPassphrase = getNonBlankOptional(CLIENT_KEY_PASSPHRASE, config);
-    }
-
-    protected Optional<String> getData(ConfigKey<String> dataKey, ConfigKey<String> fileKey, ConfigBag config) {
-        String data = Strings.isNonBlank(config.get(dataKey)) ? config.get(dataKey).trim() : null;
-        String file = config.get(fileKey);
-        String fileData = Strings.isNonBlank(file) ? getFileContents(file).trim() : null;
-        
-        if (Strings.isNonBlank(data) && Strings.isNonBlank(fileData)) {
-            if (data.equals(fileData)) {
-                LOG.warn("Duplicate (matching) configuration for " + dataKey.getName() + " and " + fileKey.getName() + " (continuing)");
-            } else {
-                throw new IllegalStateException("Duplicate conflicting configuration for " + dataKey.getName() + " and " + fileKey.getName());
-            }
-        }
-        
-        String result = Strings.isNonBlank(data) ? data : (Strings.isNonBlank(fileData) ? fileData : null);
-        return Optional.fromNullable(result);
-    }
-
-    protected Optional<String> getNonBlankOptional(ConfigKey<? extends String> key, ConfigBag config) {
-        String result = config.get(key);
-        return Optional.fromNullable(Strings.isNonBlank(result) ? result : null);
-    }
-    
-    protected String getFileContents(String file) {
-        return ResourceUtils.create(this).getResourceAsString(file);
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistry.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistry.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistry.java
deleted file mode 100644
index c240378..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistry.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.location;
-
-import org.apache.brooklyn.util.core.config.ConfigBag;
-
-import io.fabric8.kubernetes.client.KubernetesClient;
-
-public interface KubernetesClientRegistry {
-
-    KubernetesClient getKubernetesClient(ConfigBag conf);
-
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/445884b1/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistryImpl.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistryImpl.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistryImpl.java
deleted file mode 100644
index 32bfee6..0000000
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesClientRegistryImpl.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package io.cloudsoft.amp.containerservice.kubernetes.location;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.text.Strings;
-import org.apache.brooklyn.util.time.Duration;
-
-import com.google.common.base.Throwables;
-import com.google.common.io.BaseEncoding;
-
-import io.fabric8.kubernetes.client.ConfigBuilder;
-import io.fabric8.kubernetes.client.DefaultKubernetesClient;
-import io.fabric8.kubernetes.client.KubernetesClient;
-
-public class KubernetesClientRegistryImpl implements KubernetesClientRegistry {
-
-    public static final KubernetesClientRegistryImpl INSTANCE = new KubernetesClientRegistryImpl();
-
-    @Override
-    public KubernetesClient getKubernetesClient(ConfigBag conf) {
-        String masterUrl = checkNotNull(conf.get(KubernetesLocationConfig.MASTER_URL), "master url must not be null");
-
-        URL url;
-        try {
-            url = new URL(masterUrl);
-        } catch (MalformedURLException e) {
-            throw Throwables.propagate(e);
-        }
-
-        ConfigBuilder configBuilder = new ConfigBuilder()
-                .withMasterUrl(masterUrl)
-                .withTrustCerts(false);
-
-        if (url.getProtocol().equals("https")) {
-            KubernetesCerts certs = new KubernetesCerts(conf);
-            if (certs.caCertData.isPresent()) configBuilder.withCaCertData(toBase64Encoding(certs.caCertData.get()));
-            if (certs.clientCertData.isPresent()) configBuilder.withClientCertData(toBase64Encoding(certs.clientCertData.get()));
-            if (certs.clientKeyData.isPresent()) configBuilder.withClientKeyData(toBase64Encoding(certs.clientKeyData.get()));
-            if (certs.clientKeyAlgo.isPresent()) configBuilder.withClientKeyAlgo(certs.clientKeyAlgo.get());
-            if (certs.clientKeyPassphrase.isPresent()) configBuilder.withClientKeyPassphrase(certs.clientKeyPassphrase.get());
-            // TODO Should we also set configBuilder.withTrustCerts(true) here?
-        }
-
-        String username = conf.get(KubernetesLocationConfig.ACCESS_IDENTITY);
-        if (Strings.isNonBlank(username)) configBuilder.withUsername(username);
-
-        String password = conf.get(KubernetesLocationConfig.ACCESS_CREDENTIAL);
-        if (Strings.isNonBlank(password)) configBuilder.withPassword(password);
-
-        String token = conf.get(KubernetesLocationConfig.OAUTH_TOKEN);
-        if (Strings.isNonBlank(token)) configBuilder.withOauthToken(token);
-
-        Duration clientTimeout = conf.get(KubernetesLocationConfig.CLIENT_TIMEOUT);
-        if (clientTimeout.isPositive()) {
-            configBuilder.withConnectionTimeout((int) clientTimeout.toMilliseconds());
-            configBuilder.withRequestTimeout((int) clientTimeout.toMilliseconds());
-        } else {
-            throw new IllegalArgumentException("Kubernetes client timeout should be a positive duration: " + clientTimeout.toString());
-        }
-        Duration actionTimeout = conf.get(KubernetesLocationConfig.ACTION_TIMEOUT);
-        if (actionTimeout.isPositive()) {
-            configBuilder.withRollingTimeout(actionTimeout.toMilliseconds());
-            configBuilder.withScaleTimeout(actionTimeout.toMilliseconds());
-        } else {
-            throw new IllegalArgumentException("Kubernetes action timeout should be a positive duration: " + actionTimeout.toString());
-        }
-
-        return new DefaultKubernetesClient(configBuilder.build());
-    }
-
-    private String toBase64Encoding(String val) {
-        return BaseEncoding.base64().encode(val.getBytes());
-    }
-}