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 e83150a102156f9cd952794ad12761d49e669bba Author: Duncan Grant <duncan.gr...@cloudsoft.io> AuthorDate: Tue Jul 7 20:49:03 2020 +0100 Use annotations to find helm managed entities --- .../brooklyn/container/entity/helm/HelmEntity.java | 5 ++ .../container/entity/helm/HelmEntityImpl.java | 93 +++++++++++++--------- .../container/entity/helm/HelmEntityLiveTest.java | 26 ++++-- 3 files changed, 82 insertions(+), 42 deletions(-) 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 4dba320..3144826 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 @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.container.entity.helm; +import com.google.common.reflect.TypeToken; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.ImplementedBy; import org.apache.brooklyn.api.sensor.AttributeSensor; @@ -30,6 +31,9 @@ import org.apache.brooklyn.core.entity.trait.Resizable; import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.entity.software.base.SoftwareProcess; +import org.w3c.dom.Attr; + +import java.util.List; @ImplementedBy(HelmEntityImpl.class) public interface HelmEntity extends Entity, Startable { @@ -66,6 +70,7 @@ public interface HelmEntity extends Entity, Startable { AttributeSensor<Integer> REPLICAS = Sensors.newIntegerSensor("kube.replicas", "The number of replicas"); + AttributeSensor<List<String>> DEPLOYMENTS = Sensors.newSensor(new TypeToken<List<String>>() {}, "kube.deployments"); @Effector(description="") Integer resize(@EffectorParam(name="deplymentName") String name, @EffectorParam(name="desiredSize") Integer desiredSize); 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 b3693bb..3d948fe 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 @@ -31,8 +31,10 @@ import org.apache.brooklyn.container.location.kubernetes.KubernetesLocation; import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.Attributes; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; +import org.apache.brooklyn.core.sensor.function.FunctionSensor; import org.apache.brooklyn.feed.function.FunctionFeed; import org.apache.brooklyn.feed.function.FunctionPollConfig; +import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.internal.ssh.process.ProcessTool; import org.apache.brooklyn.util.core.task.DynamicTasks; import org.apache.brooklyn.util.core.task.Tasks; @@ -51,6 +53,7 @@ import java.nio.file.Paths; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; +import java.util.stream.Collectors; public class HelmEntityImpl extends AbstractEntity implements HelmEntity { @@ -89,21 +92,27 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { } private void addKubernetesFeeds() { - Callable status = getKubeDeploymentsCallable(); -// FunctionSensor<Integer> initializer = new FunctionSensor<Integer>(ConfigBag.newInstance() -// .configure(FunctionSensor.SENSOR_PERIOD, Duration.millis(1000)) -// .configure(FunctionSensor.SENSOR_NAME, DEPLOYMENT_READY.getName()) -// .configure(FunctionSensor.SENSOR_TYPE, Boolean.class.getName()) -// .configure(FunctionSensor.FUNCTION, status)); -// initializer.apply(this); + Callable status = getKubeDeploymentsReady(); + FunctionSensor<Integer> initializer = new FunctionSensor<Integer>(ConfigBag.newInstance() + .configure(FunctionSensor.SENSOR_PERIOD, Duration.millis(1000)) + .configure(FunctionSensor.SENSOR_NAME, DEPLOYMENT_READY.getName()) + .configure(FunctionSensor.SENSOR_TYPE, Boolean.class.getName()) + .configure(FunctionSensor.FUNCTION, status)); + initializer.apply(this); addFeed(FunctionFeed.builder() .entity(this) - .poll(new FunctionPollConfig<String, Boolean>(DEPLOYMENT_READY) - .callable(status)) - .period(Duration.FIVE_SECONDS) + .poll(new FunctionPollConfig<String, List<String>>(DEPLOYMENTS).callable(getKubeDeploymentsCallable())) + .period(Duration.TEN_SECONDS) .build()); +// addFeed(FunctionFeed.builder() +// .entity(this) +// .poll(new FunctionPollConfig<String, Boolean>(DEPLOYMENT_READY) +// .callable(status)) +// .period(Duration.FIVE_SECONDS) +// .build()); + Callable replicas = getKubeReplicasCallable(); addFeed(FunctionFeed.builder() .entity(this) @@ -122,6 +131,7 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { } + private void addHelmFeed(String command, AttributeSensor<String> sensor) { Callable status = getCallable(command); FunctionPollConfig pollConfig = new FunctionPollConfig<String, String>(sensor) @@ -231,9 +241,9 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { } public boolean isRunning() { - String helm_name_install_name = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); + String helmNameInstallName = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); String namespace = getNamespace(); - ImmutableList<String> command = ImmutableList.<String>of(String.format("helm status %s --namespace %s", helm_name_install_name, namespace)); + ImmutableList<String> command = ImmutableList.<String>of(String.format("helm status %s --namespace %s", helmNameInstallName, namespace)); OutputStream out = new ByteArrayOutputStream(); OutputStream err = new ByteArrayOutputStream(); int exectionResponse = ProcessTool.execProcesses(command, null, null, out, err, ";", false, this); @@ -241,11 +251,26 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { } + private Callable<List<String>> getKubeDeploymentsCallable() { + String helmNameInstallName = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); + String config = getLocation().getConfig(KubernetesLocation.KUBECONFIG); + + return new Callable() { + @Override + public List<String> call() throws Exception { + KubernetesClient client = getClient(config); + List<Deployment> deployments = getDeployments(client, helmNameInstallName); + List<String> collect = deployments.stream().map(deployment -> deployment.getMetadata().getName()).collect(Collectors.toList()); + return collect; + } ; + }; + } + public Callable<String> getCallable(String command) { - String helm_name_install_name = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); + String helmNameInstallName = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); String namespace = getNamespace(); ImmutableList<String> installHelmTemplateCommand = - ImmutableList.<String>of(String.format("helm %s %s --namespace %s", command, helm_name_install_name, namespace)); + ImmutableList.<String>of(String.format("helm %s %s --namespace %s", command, helmNameInstallName, namespace)); return new Callable<String>() { @Override @@ -258,15 +283,15 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { }; } - public Callable getKubeDeploymentsCallable() { - String helm_name_install_name = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); + public Callable getKubeDeploymentsReady() { + String helmNameInstallName = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); String config = getLocation().getConfig(KubernetesLocation.KUBECONFIG); return new Callable() { @Override public Boolean call() throws Exception { KubernetesClient client = getClient(config); - List<Deployment> deployments = getDeployments(client, helm_name_install_name); + List<Deployment> deployments = getDeployments(client, helmNameInstallName); Integer availableReplicas = countAvailableReplicas(deployments); Integer replicas = countReplicas(deployments); return availableReplicas.equals(replicas); @@ -274,16 +299,10 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { }; } - private List<Deployment> getDeployments(KubernetesClient client, String helm_name_install_name) { - AppsAPIGroupDSL apps = client.apps(); - MixedOperation<Deployment, DeploymentList, DoneableDeployment, RollableScalableResource<Deployment, DoneableDeployment>> deployments1 = apps.deployments(); - String namespace = getNamespace(); - NonNamespaceOperation<Deployment, DeploymentList, DoneableDeployment, RollableScalableResource<Deployment, DoneableDeployment>> deploymentDeploymentListDoneableDeploymentRollableScalableResourceNonNamespaceOperation = deployments1.inNamespace(namespace); - FilterWatchListDeletable<Deployment, DeploymentList, Boolean, Watch, Watcher<Deployment>> release1 = deploymentDeploymentListDoneableDeploymentRollableScalableResourceNonNamespaceOperation.withLabel("app.kubernetes.io/instance", helm_name_install_name); - FilterWatchListDeletable<Deployment, DeploymentList, Boolean, Watch, Watcher<Deployment>> release = release1; - DeploymentList list = release.list(); - List<Deployment> deployments = list.getItems(); - return client.apps().deployments().inNamespace(getNamespace()).withLabel("app.kubernetes.io/instance", helm_name_install_name).list().getItems(); + private List<Deployment> getDeployments(KubernetesClient client, String helmNameInstallName) { + List<Deployment> items = client.apps().deployments().inNamespace(getNamespace()).list().getItems(); + items.stream().filter(deployment -> deployment.getMetadata().getAnnotations().get("meta.helm.sh/release-name").equals(helmNameInstallName)).collect(Collectors.toList()); + return items; } private Integer countReplicas(List<Deployment> deployments) { @@ -300,28 +319,28 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { //TODO get rid of this public Callable getKubeReplicasCallable() { - String helm_name_install_name = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); + String helmNameInstallName = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); String config = getLocation().getConfig(KubernetesLocation.KUBECONFIG); return new Callable() { @Override public Integer call() throws Exception { KubernetesClient client = getClient(config); - return countReplicas(getDeployments(client, helm_name_install_name)); + return countReplicas(getDeployments(client, helmNameInstallName)); } ; }; } //TODO get rid of this public Callable getKubeReplicasAvailableCallable() { - String helm_name_install_name = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); + String helmNameInstallName = getConfig(HelmEntity.HELM_DEPLOYMENT_NAME); String config = getLocation().getConfig(KubernetesLocation.KUBECONFIG); return new Callable() { @Override public Integer call() throws Exception { KubernetesClient client = getClient(config); - return countAvailableReplicas(getDeployments(client, helm_name_install_name)); + return countAvailableReplicas(getDeployments(client, helmNameInstallName)); } ; }; } @@ -345,19 +364,19 @@ public class HelmEntityImpl extends AbstractEntity implements HelmEntity { } private String buildAddRepoCommand(String repo_name, String repo_url) { - String install_command = String.format("helm repo add %s %s", repo_name, repo_url); - return install_command; + String installCommand = String.format("helm repo add %s %s", repo_name, repo_url); + return installCommand; } private String buildInstallCommand(String helmDeploymentName, String helmTemplate, String installValues, String namespace) { - String install_command = String.format("helm install %s %s", helmDeploymentName, helmTemplate); + String installCommand = String.format("helm install %s %s", helmDeploymentName, helmTemplate); if(Strings.isNonBlank(installValues)) { - install_command += String.format(" --values %s", installValues); + installCommand += String.format(" --values %s", installValues); } if(Strings.isNonBlank(namespace)) { - install_command += String.format(" --namespace %s", namespace); + installCommand += String.format(" --namespace %s", namespace); } - return install_command; + return installCommand; } } 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 d819547..d753175 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 @@ -33,6 +33,7 @@ import org.testng.annotations.Test; import javax.annotation.Nullable; import java.util.Collection; +import java.util.List; import java.util.Map; import static org.apache.brooklyn.core.entity.EntityAsserts.assertAttributeEqualsEventually; @@ -47,7 +48,7 @@ public class HelmEntityLiveTest extends BrooklynAppLiveTestSupport { super.tearDown(); } - @Test + @Test(groups = {"Live"}) public void testSimpleDeploy() throws Exception { HelmEntity andManageChild = newHelmSpec("nginx-test", "bitnami/nginx"); @@ -57,8 +58,23 @@ public class HelmEntityLiveTest extends BrooklynAppLiveTestSupport { assertAttributeEqualsEventually(andManageChild, HelmEntity.DEPLOYMENT_READY, true); } + @Test(groups = {"Live"}) + public void testMultiDeployment() { + HelmEntity andManageChild = newHelmSpec("prometheus", "/Users/duncangrant/workspace/charts/stable/prometheus"); + + app.start(newKubernetesLocation()); + + assertPredicateEventuallyTrue(andManageChild, new Predicate<HelmEntity>() { + @Override + public boolean apply(@Nullable HelmEntity input) { + List<String> status = input.getAttribute(HelmEntity.DEPLOYMENTS); + return status != null && status.contains("prometheus-alertmanager"); + } + }); + } + - @Test + @Test(groups = {"Live"}) public void testCanSenseHelmStatus() { HelmEntity andManageChild = newHelmSpec("nginx-test", "bitnami/nginx"); @@ -73,7 +89,7 @@ public class HelmEntityLiveTest extends BrooklynAppLiveTestSupport { }); } - @Test + @Test(groups = {"Live"}) public void testCanSenseDeploymentStatus() { HelmEntity andManageChild = newHelmSpec("nginx-test", "bitnami/nginx"); @@ -82,7 +98,7 @@ public class HelmEntityLiveTest extends BrooklynAppLiveTestSupport { assertAttributeEqualsEventually(andManageChild, HelmEntity.DEPLOYMENT_READY, true); } - @Test + @Test(groups = {"Live"}) public void testCanScaleCluster() { HelmEntity andManageChild = newHelmSpec("nginx-test", "bitnami/nginx"); @@ -99,7 +115,7 @@ public class HelmEntityLiveTest extends BrooklynAppLiveTestSupport { assertAttributeEqualsEventually(andManageChild, HelmEntity.DEPLOYMENT_READY, true); } - @Test + @Test(groups = {"Live"}) public void testCanScaleClusterPrometheus() { HelmEntity andManageChild = newHelmSpec("prometheus", "/Users/duncangrant/workspace/charts/stable/prometheus");