diff --git a/tomcat/k8s/crd.yaml b/tomcat/k8s/crd.yaml index 44533a3..0ad6272 100644 --- a/tomcat/k8s/crd.yaml +++ b/tomcat/k8s/crd.yaml @@ -80,6 +80,14 @@ spec: properties: deployedArtifact: type: string + contextPath: + type: string + ready: + type: string + message: + type: string + updateTimestamp: + type: string required: [spec] # either Namespaced or Cluster scope: Namespaced diff --git a/tomcat/pom.xml b/tomcat/pom.xml index 5f3069d..f6227b0 100644 --- a/tomcat/pom.xml +++ b/tomcat/pom.xml @@ -19,14 +19,14 @@ 11 11 - 2.7.1 + 3. io.javaoperatorsdk operator-framework - 1.8.4 + 1.9.2 org.apache.logging.log4j diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEvent.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEvent.java index a213cac..d8e9190 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEvent.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEvent.java @@ -2,9 +2,9 @@ import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.Watcher; -import io.javaoperatorsdk.operator.processing.event.AbstractEvent; +import io.javaoperatorsdk.operator.processing.event.DefaultEvent; -public class DeploymentEvent extends AbstractEvent { +public class DeploymentEvent extends DefaultEvent { private final Watcher.Action action; private final Deployment deployment; diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEventSource.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEventSource.java index 30d97e5..e25f2a8 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEventSource.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEventSource.java @@ -3,6 +3,7 @@ import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID; import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.Watcher; diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java index 6652d8e..b0916bb 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java @@ -1,7 +1,6 @@ package io.javaoperatorsdk.operator.sample; -import io.fabric8.kubernetes.api.model.OwnerReference; -import io.fabric8.kubernetes.api.model.Service; +import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentStatus; import io.fabric8.kubernetes.client.KubernetesClient; @@ -9,6 +8,7 @@ import io.fabric8.kubernetes.client.dsl.ServiceResource; import io.fabric8.kubernetes.client.utils.Serialization; import io.javaoperatorsdk.operator.api.*; +import io.javaoperatorsdk.operator.api.Context; import io.javaoperatorsdk.operator.processing.event.EventSourceManager; import io.javaoperatorsdk.operator.processing.event.internal.CustomResourceEvent; import org.slf4j.Logger; @@ -16,6 +16,7 @@ import java.io.IOException; import java.io.InputStream; +import java.util.ListIterator; import java.util.Objects; import java.util.Optional; @@ -73,7 +74,7 @@ public DeleteControl deleteResource(Tomcat tomcat, Context context) { private Tomcat updateTomcatStatus(Tomcat tomcat, Deployment deployment) { DeploymentStatus deploymentStatus = Objects.requireNonNullElse(deployment.getStatus(), new DeploymentStatus()); - int readyReplicas = Objects.requireNonNullElse(deploymentStatus.getReadyReplicas(), 0); + int readyReplicas = Objects.requireNonNullElse(deploymentStatus.getUpdatedReplicas(), 0); TomcatStatus status = new TomcatStatus(); status.setReadyReplicas(readyReplicas); tomcat.setStatus(status); @@ -82,6 +83,27 @@ private Tomcat updateTomcatStatus(Tomcat tomcat, Deployment deployment) { private void createOrUpdateDeployment(Tomcat tomcat) { String ns = tomcat.getMetadata().getNamespace(); + + ConfigMap configMap = kubernetesClient + .configMaps().inNamespace(ns).withName(tomcat.getMetadata().getName()).get(); + + if(configMap == null){ + // create it + configMap = loadYaml(ConfigMap.class, "configmap.yaml"); + configMap.getMetadata().setName(tomcat.getMetadata().getName()); + configMap.getMetadata().setNamespace(ns); + configMap.getMetadata().getLabels().put("app.kubernetes.io/part-of", tomcat.getMetadata().getName()); + configMap.getMetadata().getLabels().put("app.kubernetes.io/managed-by", "tomcat-operator"); + // + // I wonder if that's ok that this is resource is created by TomcatController and updated by webapps + OwnerReference ownerReference = configMap.getMetadata().getOwnerReferences().get(0); + ownerReference.setName(tomcat.getMetadata().getName()); + ownerReference.setUid(tomcat.getMetadata().getUid()); + + log.info("Creating Init configmap {} in {}", configMap.getMetadata().getName(), ns); + kubernetesClient.configMaps().inNamespace(ns).create(configMap); + } + Deployment existingDeployment = kubernetesClient .apps() @@ -96,14 +118,6 @@ private void createOrUpdateDeployment(Tomcat tomcat) { deployment.getMetadata().getLabels().put("app.kubernetes.io/part-of", tomcat.getMetadata().getName()); deployment.getMetadata().getLabels().put("app.kubernetes.io/managed-by", "tomcat-operator"); // set tomcat version - deployment - .getSpec() - .getTemplate() - .getSpec() - .getContainers() - .get(0) - .setImage("tomcat:" + tomcat.getSpec().getVersion()); - deployment.getSpec().setReplicas(tomcat.getSpec().getReplicas()); // make sure label selector matches label (which has to be matched by service selector too) deployment @@ -121,22 +135,38 @@ private void createOrUpdateDeployment(Tomcat tomcat) { OwnerReference ownerReference = deployment.getMetadata().getOwnerReferences().get(0); ownerReference.setName(tomcat.getMetadata().getName()); ownerReference.setUid(tomcat.getMetadata().getUid()); - + setTomcatDeploymentReplicats(tomcat, ns, deployment, configMap); log.info("Creating or updating Deployment {} in {}", deployment.getMetadata().getName(), ns); kubernetesClient.apps().deployments().inNamespace(ns).create(deployment); } else { - existingDeployment - .getSpec() - .getTemplate() - .getSpec() - .getContainers() - .get(0) - .setImage("tomcat:" + tomcat.getSpec().getVersion()); - existingDeployment.getSpec().setReplicas(tomcat.getSpec().getReplicas()); - kubernetesClient.apps().deployments().inNamespace(ns).createOrReplace(existingDeployment); + setTomcatDeploymentReplicats(tomcat, ns, existingDeployment, configMap); } } + private void setTomcatDeploymentReplicats(Tomcat tomcat, String ns, Deployment existingDeployment, ConfigMap conf) { + ListIterator volumeListIterator = existingDeployment + .getSpec() + .getTemplate() + .getSpec().getVolumes().listIterator(); + + while (volumeListIterator.hasNext()){ + Volume volume = volumeListIterator.next(); + if (volume.getName().equals("webapps-war-list")) { + volume.getConfigMap().setName(conf.getMetadata().getName()); + } + } + + existingDeployment + .getSpec() + .getTemplate() + .getSpec() + .getContainers() + .get(0) + .setImage("tomcat:" + tomcat.getSpec().getVersion()); + existingDeployment.getSpec().setReplicas(tomcat.getSpec().getReplicas()); + kubernetesClient.apps().deployments().inNamespace(ns).createOrReplace(existingDeployment); + } + private void deleteDeployment(Tomcat tomcat) { log.info("Deleting Deployment {}", tomcat.getMetadata().getName()); RollableScalableResource deployment = diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java index c94dbb8..c21fbf0 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java @@ -1,15 +1,18 @@ package io.javaoperatorsdk.operator.sample; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.*; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; -import java.util.List; -import java.util.Objects; +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.*; @Controller public class WebappController implements ResourceController { @@ -24,15 +27,86 @@ public WebappController(KubernetesClient kubernetesClient) { @Override public UpdateControl createOrUpdateResource(Webapp webapp, Context context) { + log.info("UpdateControl"); if (webapp.getStatus() != null && Objects.equals(webapp.getSpec().getUrl(), webapp.getStatus().getDeployedArtifact())) { return UpdateControl.noUpdate(); } + if (webapp.getStatus() == null) { + webapp.setStatus(new WebappStatus()); + } + log.info(MessageFormat.format("looking for configMap {0}", webapp.getSpec().getTomcat())); + ConfigMap configMap = kubernetesClient + .configMaps() + .inNamespace(webapp.getMetadata().getNamespace()) + .withName(webapp.getSpec().getTomcat()).get(); - String[] command = new String[] {"wget", "-O", "/data/" + webapp.getSpec().getContextPath() + ".war", webapp.getSpec().getUrl()}; + if (configMap ==null){ + webapp.getStatus().setReady("False"); + webapp.getStatus().setMessage(MessageFormat.format("configMap {0} does not exist", webapp.getSpec().getTomcat())); + webapp.getStatus().setUpdateTimestamp(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date())); - executeCommandInAllPods(kubernetesClient, webapp, command); + log.info(MessageFormat.format("configMap {0} is not ready yet", webapp.getSpec().getTomcat())); + return UpdateControl.noUpdate();//.updateStatusSubResource(webapp); + } + + String warList = configMap.getData().get("war-list.txt"); + String newWebapp = MessageFormat.format("{0}={1}", webapp.getSpec().getContextPath(), webapp.getSpec().getUrl()); + String newWarList = ""; + + if(StringUtils.isNotBlank(webapp.getStatus().getDeployedArtifact()) && + StringUtils.isNotBlank(webapp.getStatus().getDeployedContextPath()) ) { + + String previousWebapp = MessageFormat.format("{0}={1}", webapp.getStatus().getDeployedContextPath(), webapp.getStatus().getDeployedArtifact()); + + log.info(MessageFormat.format("replace {0} with {1}", previousWebapp, newWebapp)); + newWarList = warList.replace(previousWebapp, newWebapp); + }else{ + StringBuilder sb = new StringBuilder(); + newWarList = sb.append(newWebapp).append("\n").append(warList).toString(); + } + configMap.getData().put("war-list.txt", newWarList); + kubernetesClient.configMaps() + .inNamespace(webapp.getMetadata().getNamespace()) + .createOrReplace(configMap); + + Deployment existingDeployment = + kubernetesClient + .apps() + .deployments() + .inNamespace(webapp.getMetadata().getNamespace()) + .withName(webapp.getSpec().getTomcat()) + .get(); + if (existingDeployment == null) { + webapp.getStatus().setReady("False"); + webapp.getStatus().setMessage(MessageFormat.format("Deployment {0} does not exist", webapp.getSpec().getTomcat())); + webapp.getStatus().setUpdateTimestamp(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date())); + log.info(MessageFormat.format("Deployment {0} Deployment", webapp.getSpec().getTomcat())); + return UpdateControl.updateStatusSubResource(webapp); + } + if (existingDeployment.getSpec() + .getTemplate() + .getMetadata() + .getAnnotations() !=null) { + existingDeployment.getSpec() + .getTemplate() + .getMetadata() + .getAnnotations() + .put("tomcat-operator-updated", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date())); + }else{ + Map annotations = new HashMap<>(); + annotations.put("tomcat-operator-updated", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date())); + existingDeployment.getSpec() + .getTemplate() + .getMetadata() + .setAnnotations(annotations); + } - //webapp.getStatus().setDeployedArtifact(webapp.getSpec().getUrl()); + webapp.getStatus().setDeployedArtifact(webapp.getSpec().getUrl()); + webapp.getStatus().setDeployedContextPath(webapp.getSpec().getContextPath()); + webapp.getStatus().setReady("True"); + webapp.getStatus().setMessage(MessageFormat.format("Deployment {0} Updated", webapp.getSpec().getTomcat())); + webapp.getStatus().setUpdateTimestamp(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date())); + kubernetesClient.apps().deployments().inNamespace(webapp.getMetadata().getNamespace()).createOrReplace(existingDeployment); return UpdateControl.updateStatusSubResource(webapp); } diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappStatus.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappStatus.java index 53e71fe..10079bf 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappStatus.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappStatus.java @@ -11,4 +11,28 @@ public String getDeployedArtifact() { public void setDeployedArtifact(String deployedArtifact) { this.deployedArtifact = deployedArtifact; } + + private String ready; + + public String getReady() { return ready; } + + public void setReady(String ready) { this.ready = ready; } + + private String message; + + public String getMessage() { return message; } + + public void setMessage(String message) { this.message = message; } + + private String updateTimestamp; + + public String getUpdateTimestamp() { return updateTimestamp; } + + public void setUpdateTimestamp(String updateTimestamp) { this.updateTimestamp = updateTimestamp; } + + private String contextPath; + + public void setDeployedContextPath(String contextPath) { this.contextPath = contextPath; } + + public String getDeployedContextPath(){ return contextPath; } } diff --git a/tomcat/src/main/resources/io/javaoperatorsdk/operator/sample/configmap.yaml b/tomcat/src/main/resources/io/javaoperatorsdk/operator/sample/configmap.yaml new file mode 100644 index 0000000..215b8fb --- /dev/null +++ b/tomcat/src/main/resources/io/javaoperatorsdk/operator/sample/configmap.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "" + labels: + app.kubernetes.io/part-of: "" + app.kubernetes.io/managed-by: "" # used for filtering of Deployments created by the controller + ownerReferences: # used for finding which Tomcat does this Deployment belong to + - apiVersion: apps/v1 + kind: Tomcat + name: "" + uid: "" +data: + CHECKSHA256: "false" + wgetscript.sh: | + #!/bin/sh + # + # + # + if [[ ! -f /etc/war-list/war-list.txt ]]; then + echo "war-list.txt is empty"; + exit; + fi + + for WAR in $(cat /etc/war-list/war-list.txt); do + CONTEXT=$(echo $WAR | cut -d '=' -f 1) + URL=$(echo ${WAR#"$CONTEXT="}) + wget -O /data/$CONTEXT.war $URL + # todo add a sha256 validation + # if [[ CHECKSHA256 -eq "true" ]] + # wget -O /data/$CONTEXT.war.sha256 $URL.sha256 + # + done + + # the format is contextPath=url + war-list.txt: "" + diff --git a/tomcat/src/main/resources/io/javaoperatorsdk/operator/sample/deployment.yaml b/tomcat/src/main/resources/io/javaoperatorsdk/operator/sample/deployment.yaml index 2f6f373..a205954 100644 --- a/tomcat/src/main/resources/io/javaoperatorsdk/operator/sample/deployment.yaml +++ b/tomcat/src/main/resources/io/javaoperatorsdk/operator/sample/deployment.yaml @@ -20,6 +20,15 @@ spec: labels: app: "" spec: + initContainers: + - name: war-downloader + image: busybox:1.28 + command: ['/bin/sh', '/etc/war-list/wgetscript.sh'] + volumeMounts: + - name: webapps-volume + mountPath: /data + - name: webapps-war-list + mountPath: /etc/war-list containers: - name: tomcat image: tomcat:8.0 @@ -28,12 +37,9 @@ spec: volumeMounts: - mountPath: /usr/local/tomcat/webapps name: webapps-volume - - name: war-downloader - image: busybox:1.28 - command: ['tail', '-f', '/dev/null'] - volumeMounts: - - name: webapps-volume - mountPath: /data volumes: - name: webapps-volume emptydir: {} + - name: webapps-war-list + configMap: + name: "blank" diff --git a/tomcat/src/test/java/sample/IntegrationTest.java b/tomcat/src/test/java/sample/IntegrationTest.java index 3af8cd0..28de84d 100644 --- a/tomcat/src/test/java/sample/IntegrationTest.java +++ b/tomcat/src/test/java/sample/IntegrationTest.java @@ -1,71 +1,126 @@ -package sample; +package io.javaoperatorsdk.operator.sample; -import io.fabric8.kubernetes.api.model.KubernetesResourceList; -import io.fabric8.kubernetes.api.model.Namespace; -import io.fabric8.kubernetes.api.model.NamespaceBuilder; -import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.*; 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.MixedOperation; -import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.utils.Serialization; +import io.fabric8.kubernetes.client.*; +import io.fabric8.kubernetes.client.extended.run.RunConfigBuilder; import io.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; -import io.javaoperatorsdk.operator.sample.Tomcat; -import io.javaoperatorsdk.operator.sample.TomcatController; -import io.javaoperatorsdk.operator.sample.WebappController; +import org.junit.AfterClass; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - +import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; public class IntegrationTest { + + final static String TEST_NS = "tomcat-test"; + + final static Logger log = LoggerFactory.getLogger(IntegrationTest.class); + @Test - public void test() throws InterruptedException { + public void test() { + int replicas = 3; //3 Config config = new ConfigBuilder().withNamespace(null).build(); KubernetesClient client = new DefaultKubernetesClient(config); - Operator operator = new Operator(client, DefaultConfigurationService.instance()); - - TomcatController tomcatController = new TomcatController(client); - operator.register(tomcatController); + Operator operator = new Operator(client, DefaultConfigurationService.instance()); + operator.register(new TomcatController(client)); operator.register(new WebappController(client)); - Tomcat tomcat = loadYaml(Tomcat.class, "tomcat-sample1.yaml"); - - tomcat.getSpec().setReplicas(3); - tomcat.getMetadata().setNamespace("tomcat-test"); - - MixedOperation, Resource> tomcatClient = client.customResources(Tomcat.class); - - Namespace tt_ns = new NamespaceBuilder().withMetadata(new ObjectMetaBuilder().withName("tomcat-test").build()).build(); + Tomcat tomcat = new Tomcat(); + tomcat.setMetadata(new ObjectMetaBuilder() + .withName("test-tomcat1") + .withNamespace(TEST_NS) + .build()); + tomcat.setSpec(new TomcatSpec()); + tomcat.getSpec().setReplicas(replicas); + tomcat.getSpec().setVersion(9); + + Webapp webapp1 = new Webapp(); + webapp1.setMetadata(new ObjectMetaBuilder() + .withName("test-webapp1") + .withNamespace(TEST_NS) + .build()); + webapp1.setSpec(new WebappSpec()); + webapp1.getSpec().setContextPath("webapp1"); + webapp1.getSpec().setTomcat(tomcat.getMetadata().getName()); + webapp1.getSpec().setUrl("http://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war"); + + var tomcatClient = client.customResources(Tomcat.class); + var webappClient = client.customResources(Webapp.class); + + Namespace testNs = new NamespaceBuilder().withMetadata( + new ObjectMetaBuilder().withName(TEST_NS).build()).build(); + + if (testNs != null && client.namespaces().withName(TEST_NS).isReady() == true ) { + // We perform a pre-run cleanup instead of a post-run cleanup. This is to help with debugging test results + // when running against a persistent cluster. The test namespace would stay after the test run so we can + // check what's there, but it would be cleaned up during the next test run. + log.info("Cleanup: deleting test namespace {}", TEST_NS); + client.namespaces().delete(testNs); + await().atMost(5, MINUTES).until(() -> client.namespaces().withName("tomcat-test").get() == null); + } - client.namespaces().delete(tt_ns); + log.info("Creating test namespace {}", TEST_NS); + client.namespaces().create(testNs); - await().atMost(300, SECONDS).until(() -> client.namespaces().withName("tomcat-test").get() == null); + log.info("Creating test resources"); + tomcatClient.inNamespace(TEST_NS).create(tomcat); - client.namespaces().createOrReplace(tt_ns); + log.info("Waiting 2 minutes for Tomcat CR statuses to be updated"); + await().atMost(2, MINUTES).untilAsserted(() -> { + Tomcat updatedTomcat = tomcatClient.inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).get(); + assertThat(updatedTomcat.getStatus(), is(notNullValue())); + //assertThat(updatedTomcat.getStatus().getReadyReplicas(), equalTo(3)); + }); - tomcatClient.inNamespace("tomcat-test").create(tomcat); + webappClient.inNamespace(TEST_NS).create(webapp1); + log.info("Waiting 2 minutes for Webapp CR statuses to be updated"); + await().atMost(2, MINUTES).untilAsserted(() -> { + Webapp updatedWebapp = webappClient.inNamespace(TEST_NS).withName(webapp1.getMetadata().getName()).get(); + assertThat(updatedWebapp.getStatus(), is(notNullValue())); + assertThat(updatedWebapp.getStatus().getDeployedArtifact(), is(notNullValue())); + Tomcat updatedTomcat = tomcatClient.inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).get(); + assertThat(updatedTomcat.getStatus(), is(notNullValue())); + assertThat(updatedTomcat.getStatus().getReadyReplicas(), equalTo(replicas)); + }); + log.info("Waiting 60 seconds for Tomcat to unpack the downloaded war"); + // this delays is du to allows the tomcat to unpack + // kubectl -n tomcat-test -c war-downloader logs -l app=test-tomcat1 + // Deployment of web application archive [/usr/local/tomcat/webapps/webapp1.war] has finished in [xxx] ms + try { + Thread.sleep(60*1000); + } catch (InterruptedException e) { + log.warn(e.getMessage(),e); + } - await().atMost(60, SECONDS).until(() -> { - Tomcat updatedTomcat = tomcatClient.inNamespace("tomcat-test").withName("test-tomcat1").get(); - return updatedTomcat.getStatus() != null && (int) updatedTomcat.getStatus().getReadyReplicas() == 3; + String url = "http://" + tomcat.getMetadata().getName() + "/" + webapp1.getSpec().getContextPath() + "/"; + log.info("Starting curl Pod and waiting 2 minutes for GET of {} to return 200", url); + Pod curlPod = client.run().inNamespace(TEST_NS) + .withRunConfig(new RunConfigBuilder() + .withArgs("-s", "-o", "/dev/null", "-w", "%{http_code}", url) + .withName("curl") + .withImage("curlimages/curl:7.78.0") + .withRestartPolicy("Never") + .build()).done(); + await().atMost(2, MINUTES).untilAsserted(() -> { + try { + //let's do som tries + String curlOutput = client.pods().inNamespace(TEST_NS).withName(curlPod.getMetadata().getName()).getLog(); + assertThat(curlOutput, equalTo("200")); + } catch (KubernetesClientException ex) { + throw new AssertionError(ex); + } }); } - private T loadYaml(Class clazz, String yaml) { - try (InputStream is = new FileInputStream("k8s/" + yaml)) { - return Serialization.unmarshal(is, clazz); - } catch (IOException ex) { - throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); - } - } -} +} \ No newline at end of file