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:35:58 UTC

[16/50] [abbrv] brooklyn-server git commit: Add KubernetesMachineLocation interface and implementations

Add KubernetesMachineLocation interface and implementations


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

Branch: refs/heads/master
Commit: fcb0db07b5afa3de7718975977349b5144e1a389
Parents: 90123e4
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Authored: Wed Feb 1 19:32:36 2017 +0000
Committer: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Committed: Fri May 19 14:01:20 2017 +0100

----------------------------------------------------------------------
 .../kubernetes/entity/KubernetesPod.java        |  2 +
 .../KubernetesEmptyMachineLocation.java         | 68 ++++++++++++++++++
 .../kubernetes/location/KubernetesLocation.java | 75 ++++++++++++++------
 .../location/KubernetesMachineLocation.java     | 27 +++++++
 .../location/KubernetesSshMachineLocation.java  | 27 +++++++
 .../KubernetesLocationYamlLiveTest.java         | 39 +++++++++-
 6 files changed, 215 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fcb0db07/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
index 4c334ec..35da4b8 100644
--- 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
@@ -77,4 +77,6 @@ public interface KubernetesPod extends DockerContainer {
     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/fcb0db07/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesEmptyMachineLocation.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesEmptyMachineLocation.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesEmptyMachineLocation.java
new file mode 100644
index 0000000..ffda23f
--- /dev/null
+++ b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesEmptyMachineLocation.java
@@ -0,0 +1,68 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+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.core.location.AbstractLocation;
+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 AbstractLocation 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/fcb0db07/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocation.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocation.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocation.java
index 28f193c..f5123b9 100644
--- a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocation.java
+++ b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocation.java
@@ -128,6 +128,7 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
     public static final String CLOUDSOFT_APPLICATION_ID = "cloudsoft.io/application-id";
     public static final String KUBERNETES_DOCKERCFG = "kubernetes.io/dockercfg";
 
+    public static final String PHASE_AVAILABLE = "Available";
     public static final String PHASE_TERMINATING = "Terminating";
     public static final String PHASE_ACTIVE = "Active";
 
@@ -185,15 +186,41 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
         if (isKubernetesResource(entity)) {
             return createKubernetesResourceLocation(entity, setup);
         } else {
+            // Heuristic for determining whether KubernetesPod is simply a parent entity
+            if (isKubernetesPod(entity) &&
+                    entity.config().get(DockerContainer.IMAGE_NAME) == null &&
+                    entity.config().get(DockerContainer.INBOUND_TCP_PORTS) == null &&
+                    entity.getChildren().size() > 0) {
+                return createEmptyKubernetesMachineLocation(entity);
+            }
             return createKubernetesContainerLocation(entity, setup);
         }
     }
 
+    /** @deprecated This mechanism will be removed in future releases */
+    @Deprecated
+    public KubernetesEmptyMachineLocation createEmptyKubernetesMachineLocation(Entity entity) {
+        LOG.warn("IMPORTANT: Deprecated behaviour: Use of KubernetesPod as a parent entity is deprecated and support will be removed in future versions");
+
+        LocationSpec<KubernetesEmptyMachineLocation> locationSpec = LocationSpec.create(KubernetesEmptyMachineLocation.class)
+                .configure(KubernetesLocationConfig.CALLER_CONTEXT, entity)
+                .configure(KubernetesMachineLocation.KUBERNETES_RESOURCE_TYPE, KubernetesPod.EMPTY)
+                .configure(KubernetesMachineLocation.KUBERNETES_RESOURCE_NAME, entity.getId());
+
+        KubernetesEmptyMachineLocation machine = getManagementContext().getLocationManager().createLocation(locationSpec);
+
+        return machine;
+    }
+
     @Override
     public void release(MachineLocation machine) {
         Entity entity = validateCallerContext(machine);
         if (isKubernetesResource(entity)) {
-            deleteKubernetesResourceLocation(entity);
+            if (machine instanceof KubernetesEmptyMachineLocation && KubernetesPod.EMPTY.equals(machine.config().get(KubernetesMachineLocation.KUBERNETES_RESOURCE_TYPE))) {
+                // Nothing to do, the location does not represent a Kubernetes resource
+            } else {
+                deleteKubernetesResourceLocation(entity);
+            }
         } else {
             deleteKubernetesContainerLocation(entity, machine);
         }
@@ -346,25 +373,27 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
         entity.sensors().set(KubernetesResource.RESOURCE_NAME, resourceName);
         entity.sensors().set(KubernetesResource.RESOURCE_TYPE, resourceType);
 
-        LocationSpec<SshMachineLocation> locationSpec = LocationSpec.create(SshMachineLocation.class)
-                        .configure(CALLER_CONTEXT, setup.get(CALLER_CONTEXT));
+        LocationSpec<? extends KubernetesMachineLocation> locationSpec = LocationSpec.create(KubernetesSshMachineLocation.class);
         if (!findResourceAddress(locationSpec, entity, metadata, resourceType, resourceName, namespace)) {
             LOG.info("Resource {} with type {} has no associated address", resourceName, resourceType);
-            locationSpec.configure("address", "0.0.0.0");
+            locationSpec = LocationSpec.create(KubernetesEmptyMachineLocation.class);
         }
+        locationSpec.configure(CALLER_CONTEXT, setup.get(CALLER_CONTEXT))
+                .configure(KubernetesMachineLocation.KUBERNETES_NAMESPACE, namespace)
+                .configure(KubernetesMachineLocation.KUBERNETES_RESOURCE_NAME, resourceName)
+                .configure(KubernetesMachineLocation.KUBERNETES_RESOURCE_TYPE, resourceType);
 
-        SshMachineLocation machine = getManagementContext().getLocationManager().createLocation(locationSpec);
+        KubernetesMachineLocation machine = getManagementContext().getLocationManager().createLocation(locationSpec);
 
-        if (resourceType.equals(KubernetesResource.SERVICE)) {
+        if (resourceType.equals(KubernetesResource.SERVICE) && machine instanceof KubernetesSshMachineLocation) {
             Service service = getService(namespace, resourceName);
-            registerPortMappings(machine, entity, service);
-
+            registerPortMappings((KubernetesSshMachineLocation) machine, entity, service);
         }
 
         return machine;
     }
 
-    protected boolean findResourceAddress(LocationSpec<SshMachineLocation> locationSpec, Entity entity, HasMetadata metadata, String resourceType, String resourceName, String namespace) {
+    protected boolean findResourceAddress(LocationSpec<? extends KubernetesMachineLocation> locationSpec, Entity entity, HasMetadata metadata, String resourceType, String resourceName, String namespace) {
         if (resourceType.equals(KubernetesResource.DEPLOYMENT) || resourceType.equals(KubernetesResource.REPLICATION_CONTROLLER) || resourceType.equals(KubernetesResource.POD)) {
             Map<String, String> labels = MutableMap.of();
             if (resourceType.equals(KubernetesResource.DEPLOYMENT)) {
@@ -443,8 +472,12 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
         entity.sensors().set(KubernetesPod.KUBERNETES_POD, pod.getMetadata().getName());
         entity.sensors().set(KubernetesPod.KUBERNETES_SERVICE, service.getMetadata().getName());
 
-        LocationSpec<SshMachineLocation> locationSpec = prepareLocationSpec(entity, setup, namespace, deploymentName, service, pod);
-        SshMachineLocation machine = getManagementContext().getLocationManager().createLocation(locationSpec);
+        LocationSpec<KubernetesSshMachineLocation> locationSpec = prepareSshableLocationSpec(entity, setup, namespace, deploymentName, service, pod)
+                .configure(KubernetesMachineLocation.KUBERNETES_NAMESPACE, namespace.getMetadata().getName())
+                .configure(KubernetesMachineLocation.KUBERNETES_RESOURCE_NAME, deploymentName)
+                .configure(KubernetesMachineLocation.KUBERNETES_RESOURCE_TYPE, KubernetesResource.DEPLOYMENT);
+
+        KubernetesSshMachineLocation machine = getManagementContext().getLocationManager().createLocation(locationSpec);
         registerPortMappings(machine, entity, service);
         if (!isDockerContainer(entity)) {
             waitForSshable(machine, Duration.FIVE_MINUTES);
@@ -482,11 +515,11 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
         }
     }
 
-    protected void registerPortMappings(SshMachineLocation machine, Entity entity, Service service) {
+    protected void registerPortMappings(KubernetesSshMachineLocation machine, Entity entity, Service service) {
         PortForwardManager portForwardManager = (PortForwardManager) getManagementContext().getLocationRegistry()
                 .getLocationManaged(PortForwardManagerLocationResolver.PFM_GLOBAL_SPEC);
         List<ServicePort> ports = service.getSpec().getPorts();
-        String publicHostText = machine.getSshHostAndPort().getHostText();
+        String publicHostText = ((SshMachineLocation) machine).getSshHostAndPort().getHostText();
         LOG.debug("Recording port-mappings for container {} of {}: {}", new Object[] { machine, this, ports });
 
         for (ServicePort port : ports) {
@@ -741,10 +774,10 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
         return client.services().inNamespace(namespace).withName(serviceName).get();
     }
 
-    protected LocationSpec<SshMachineLocation> prepareLocationSpec(Entity entity, ConfigBag setup, Namespace namespace, String deploymentName, Service service, Pod pod) {
+    protected LocationSpec<KubernetesSshMachineLocation> prepareSshableLocationSpec(Entity entity, ConfigBag setup, Namespace namespace, String deploymentName, Service service, Pod pod) {
         InetAddress node = Networking.getInetAddressWithFixedName(pod.getSpec().getNodeName());
         String podAddress = pod.getStatus().getPodIP();
-        LocationSpec<SshMachineLocation> locationSpec = LocationSpec.create(SshMachineLocation.class)
+        LocationSpec<KubernetesSshMachineLocation> locationSpec = LocationSpec.create(KubernetesSshMachineLocation.class)
                 .configure("address", node)
                 .configure(SshMachineLocation.PRIVATE_ADDRESSES, ImmutableSet.of(podAddress))
                 .configure(CALLER_CONTEXT, setup.get(CALLER_CONTEXT));
@@ -775,13 +808,13 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
         for (final String persistentVolume : volumes) {
             PersistentVolume volume = new PersistentVolumeBuilder()
                     .withNewMetadata()
-                    .withName(persistentVolume)
-                    .withLabels(ImmutableMap.of("type", "local")) // TODO make it configurable
+                        .withName(persistentVolume)
+                        .withLabels(ImmutableMap.of("type", "local")) // TODO make it configurable
                     .endMetadata()
                     .withNewSpec()
-                    .addToCapacity("storage", new QuantityBuilder().withAmount("20").build()) // TODO make it configurable
-                    .addToAccessModes("ReadWriteOnce") // TODO make it configurable
-                    .withNewHostPath().withPath("/tmp/pv-1").endHostPath() // TODO make it configurable
+                        .addToCapacity("storage", new QuantityBuilder().withAmount("20").build()) // TODO make it configurable
+                        .addToAccessModes("ReadWriteOnce") // TODO make it configurable
+                        .withNewHostPath().withPath("/tmp/pv-1").endHostPath() // TODO make it configurable
                     .endSpec()
                     .build();
             client.persistentVolumes().create(volume);
@@ -790,7 +823,7 @@ public class KubernetesLocation extends AbstractLocation implements MachineProvi
                 public Boolean call() {
                     PersistentVolume pv = client.persistentVolumes().withName(persistentVolume).get();
                     return pv != null && pv.getStatus() != null
-                            && pv.getStatus().getPhase().equals("Available");
+                            && pv.getStatus().getPhase().equals(PHASE_AVAILABLE);
                 }
                 @Override
                 public String getFailureMessage() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fcb0db07/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesMachineLocation.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesMachineLocation.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesMachineLocation.java
new file mode 100644
index 0000000..9c620bb
--- /dev/null
+++ b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesMachineLocation.java
@@ -0,0 +1,27 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+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/fcb0db07/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesSshMachineLocation.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesSshMachineLocation.java b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesSshMachineLocation.java
new file mode 100644
index 0000000..97fabbb
--- /dev/null
+++ b/kubernetes-location/src/main/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesSshMachineLocation.java
@@ -0,0 +1,27 @@
+package io.cloudsoft.amp.containerservice.kubernetes.location;
+
+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/fcb0db07/kubernetes-location/src/test/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocationYamlLiveTest.java
----------------------------------------------------------------------
diff --git a/kubernetes-location/src/test/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocationYamlLiveTest.java b/kubernetes-location/src/test/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocationYamlLiveTest.java
index 9654d6d..f783630 100644
--- a/kubernetes-location/src/test/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocationYamlLiveTest.java
+++ b/kubernetes-location/src/test/java/io/cloudsoft/amp/containerservice/kubernetes/location/KubernetesLocationYamlLiveTest.java
@@ -259,9 +259,8 @@ public class KubernetesLocationYamlLiveTest extends AbstractYamlTest {
         return entity;
     }
 
-
     @Test(groups={"Live"})
-    public void testWordpressInContainers() throws Exception {
+    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(
@@ -297,6 +296,42 @@ public class KubernetesLocationYamlLiveTest extends AbstractYamlTest {
     }
 
     @Test(groups={"Live"})
+    public void testWordpressInContainersWithPodParent() 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(),
+                "    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.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 testWordpressInPods() throws Exception {
         // TODO docker.container.inboundPorts doesn't accept list of ints - need to use quotes
         String randomId = Identifiers.makeRandomLowercaseId(4);