This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit 0bbafedf754d4c1acf812679bdc9bfdaa3e4419c Author: Duncan Grant <[email protected]> AuthorDate: Thu Jun 18 08:47:18 2020 +0100 Add kube sensors --- .../brooklyn/container/entity/helm/HelmDriver.java | 2 + .../brooklyn/container/entity/helm/HelmEntity.java | 3 ++ .../container/entity/helm/HelmEntityImpl.java | 33 +++++++++---- .../container/entity/helm/HelmSshDriver.java | 47 +++++++++++++++++- .../container/entity/helm/HelmEntityLiveTest.java | 55 ++++++++++++++++++---- 5 files changed, 121 insertions(+), 19 deletions(-) diff --git a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmDriver.java b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmDriver.java index 52dbbc8..4224f7a 100644 --- a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmDriver.java +++ b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmDriver.java @@ -22,4 +22,6 @@ import java.util.concurrent.Callable; public interface HelmDriver extends SoftwareProcessDriver { Callable getCallable(String command); + + Callable getKubeCallable(); } diff --git a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntity.java b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntity.java index e34499f..0daa865 100644 --- a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntity.java +++ b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntity.java @@ -46,4 +46,7 @@ public interface HelmEntity extends SoftwareProcess { AttributeSensor<String> STATUS = Sensors.newStringSensor("helm.status", "The results of a status call"); + + AttributeSensor<Boolean> DEPLOYMENT_READY = Sensors.newBooleanSensor("kube.deployment.status", + "The status of the deploymeny"); } diff --git a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntityImpl.java b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntityImpl.java index 72ed9f5..451d4c1 100644 --- a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntityImpl.java +++ b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmEntityImpl.java @@ -18,16 +18,12 @@ */ package org.apache.brooklyn.container.entity.helm; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.entity.brooklynnode.BrooklynClusterImpl; -import org.apache.brooklyn.entity.brooklynnode.BrooklynNode; -import org.apache.brooklyn.entity.software.base.SoftwareProcessDriver; +import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl; import org.apache.brooklyn.feed.function.FunctionFeed; import org.apache.brooklyn.feed.function.FunctionPollConfig; import org.apache.brooklyn.util.time.Duration; -import javax.annotation.Nullable; import java.util.concurrent.Callable; public class HelmEntityImpl extends SoftwareProcessImpl implements HelmEntity { @@ -46,10 +42,30 @@ public class HelmEntityImpl extends SoftwareProcessImpl implements HelmEntity { super.connectSensors(); connectServiceUpIsRunning(); + addHelmFeed("status", STATUS); + addKubernetesFeed(); + } + + private void addKubernetesFeed() { + HelmDriver driver = getDriver(); + Callable status = driver.getKubeCallable(); + FunctionPollConfig pollConfig = new FunctionPollConfig<String, Boolean>(DEPLOYMENT_READY) + .callable(status) + ; + + addFeed(FunctionFeed.builder() + .entity(this) + .poll(pollConfig) + .period(Duration.FIVE_SECONDS) + .build()); + } + + private void addHelmFeed(String command, AttributeSensor<String> sensor) { HelmDriver driver = getDriver(); - Callable status = driver.getCallable("status"); - FunctionPollConfig pollConfig = new FunctionPollConfig<Object, String>(STATUS) - .callable(status); + Callable status = driver.getCallable(command); + FunctionPollConfig pollConfig = new FunctionPollConfig<String, String>(sensor) + .callable(status) + ; addFeed(FunctionFeed.builder() .entity(this) @@ -58,6 +74,7 @@ public class HelmEntityImpl extends SoftwareProcessImpl implements HelmEntity { .build()); } + @Override protected void disconnectSensors() { super.disconnectSensors(); diff --git a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmSshDriver.java b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmSshDriver.java index c8c6728..931534f 100644 --- a/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmSshDriver.java +++ b/locations/container/src/main/java/org/apache/brooklyn/container/entity/helm/HelmSshDriver.java @@ -19,8 +19,16 @@ package org.apache.brooklyn.container.entity.helm; import com.google.common.collect.ImmutableList; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DoneableDeployment; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; +import io.fabric8.kubernetes.client.DefaultKubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.RollableScalableResource; import org.apache.brooklyn.api.entity.EntityLocal; import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.container.location.kubernetes.KubernetesLocation; import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver; import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessDriver; @@ -28,10 +36,15 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess; import org.apache.brooklyn.entity.software.base.SoftwareProcessDriver; import org.apache.brooklyn.location.ssh.SshMachineLocation; import org.apache.brooklyn.util.core.internal.ssh.process.ProcessTool; +import org.apache.brooklyn.util.exceptions.Exceptions; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Map; import java.util.concurrent.Callable; @@ -149,8 +162,40 @@ public class HelmSshDriver extends AbstractSoftwareProcessDriver implements Helm ImmutableList.<String>of(String.format("helm %s %s", command, helm_name_install_name)); OutputStream out = new ByteArrayOutputStream(); OutputStream err = new ByteArrayOutputStream(); - return ProcessTool.execProcesses(installHelmTemplateCommand, null, null, out, err,";", false, this); + ProcessTool.execProcesses(installHelmTemplateCommand, null, null, out, err,";", false, this); + return out.toString(); } }; } + + @Override + public Callable getKubeCallable() { + return new Callable() { + @Override + public Object call() throws Exception { + String helm_name_install_name = getEntity().getConfig(HelmEntity.HELM_TEMPLATE_INSTALL_NAME); + String config = getLocation().getConfig(KubernetesLocation.KUBECONFIG); + KubernetesClient client = getClient(config); + + Deployment deploy = client.apps().deployments().inNamespace("default").withName(helm_name_install_name).get(); + Integer availableReplicas = deploy.getStatus().getAvailableReplicas(); + Integer replicas = deploy.getStatus().getReplicas(); + Boolean ready = availableReplicas.equals(replicas); + return ready; + } ; + }; + } + + KubernetesClient getClient(String configFile) { + Path configPath = Paths.get(configFile); + try { + Config clientConfig = Config.fromKubeconfig(new String(Files.readAllBytes(configPath))); + ConfigBuilder configBuilder = new ConfigBuilder(clientConfig); + return new DefaultKubernetesClient(configBuilder.build()); + }catch (IOException ioe) { + Exceptions.propagate(ioe); + return null; + } + } + } diff --git a/locations/container/src/test/java/org/apache/brooklyn/container/entity/helm/HelmEntityLiveTest.java b/locations/container/src/test/java/org/apache/brooklyn/container/entity/helm/HelmEntityLiveTest.java index ffd021b..7d9a9b8 100644 --- a/locations/container/src/test/java/org/apache/brooklyn/container/entity/helm/HelmEntityLiveTest.java +++ b/locations/container/src/test/java/org/apache/brooklyn/container/entity/helm/HelmEntityLiveTest.java @@ -18,7 +18,9 @@ */ package org.apache.brooklyn.container.entity.helm; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.container.location.kubernetes.KubernetesLocation; @@ -26,11 +28,14 @@ import org.apache.brooklyn.core.entity.Attributes; import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.time.Duration; import org.testng.annotations.Test; +import javax.annotation.Nullable; import java.util.Map; import static org.apache.brooklyn.core.entity.EntityAsserts.assertAttributeEqualsEventually; +import static org.apache.brooklyn.core.entity.EntityAsserts.assertPredicateEventuallyTrue; import static org.testng.Assert.*; public class HelmEntityLiveTest extends BrooklynAppLiveTestSupport { @@ -43,20 +48,50 @@ public class HelmEntityLiveTest extends BrooklynAppLiveTestSupport { .configure(HelmEntity.HELM_TEMPLATE_INSTALL_NAME, "wordpress-test") .configure(HelmEntity.HELM_TEMPLATE, "bitnami/wordpress")); - app.start(ImmutableList.<Location>of(app.newLocalhostProvisioningLocation())); + app.start(newLocalhostLocation()); assertAttributeEqualsEventually(andManageChild, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + assertAttributeEqualsEventually(andManageChild, Attributes.SERVICE_UP, true); app.stop(); } - protected KubernetesLocation newKubernetesLocation(Map<String, ?> flags) throws Exception { - Map<String, ?> allFlags = MutableMap.<String, Object>builder() - .put("kubeconfig", "/Users/duncangrant/.kube/config") - .put("image", "cloudsoft/centos:7") - .put("loginUser", "root") - .put("loginUser.password", "p4ssw0rd") - .putAll(flags) - .build(); - return (KubernetesLocation) mgmt.getLocationRegistry().getLocationManaged("kubernetes", allFlags); + @Test + public void testCanSenseHelmStatus() { + HelmEntity andManageChild = app.createAndManageChild(EntitySpec.create(HelmEntity.class) + .configure(HelmEntity.REPO_NAME, "bitnami") + .configure(HelmEntity.REPO_URL, "https://charts.bitnami.com/bitnami") + .configure(HelmEntity.HELM_TEMPLATE_INSTALL_NAME, "wordpress-test") + .configure(HelmEntity.HELM_TEMPLATE, "bitnami/wordpress")); + + app.start(newLocalhostLocation()); + + assertPredicateEventuallyTrue(andManageChild, new Predicate<HelmEntity>() { + @Override + public boolean apply(@Nullable HelmEntity input) { + String status = input.getAttribute(HelmEntity.STATUS); + return status == null? false : status.contains("STATUS: deployed"); + } + }); + app.stop(); + } + + @Test + public void testCanSenseDeploymentStatus() { + HelmEntity andManageChild = app.createAndManageChild(EntitySpec.create(HelmEntity.class) + .configure(HelmEntity.REPO_NAME, "bitnami") + .configure(HelmEntity.REPO_URL, "https://charts.bitnami.com/bitnami") + .configure(HelmEntity.HELM_TEMPLATE_INSTALL_NAME, "nginx-test") + .configure(HelmEntity.HELM_TEMPLATE, "bitnami/nginx")); + + app.start(newLocalhostLocation()); + + assertAttributeEqualsEventually(andManageChild, HelmEntity.DEPLOYMENT_READY, true); + app.stop(); + } + + private ImmutableList<Location> newLocalhostLocation() { + return ImmutableList.<Location>of( + app.newLocalhostProvisioningLocation( + ImmutableMap.of(KubernetesLocation.KUBECONFIG, "/Users/duncangrant/.kube/config"))); } } \ No newline at end of file
