From 302b789030f6fb5300921001a6f1c175bdfc1930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:00:55 +0200 Subject: [PATCH 01/33] update maven cache step --- .github/workflows/TomcatIntegrationTest.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 4221783..745e02c 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -28,13 +28,14 @@ jobs: - name: Set up Java and Maven uses: actions/setup-java@v1 with: - # java-version: ${{ matrix.java }} java-version: 15 - - uses: actions/cache@v2 + + - name: Cache Maven packages + uses: actions/cache@v2 with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Run unit tests run: mvn -B test --file tomcat/pom.xml \ No newline at end of file From e4fee9f4b6adb5fad751df800a434ef3937a9afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:02:02 +0200 Subject: [PATCH 02/33] try to remove unnecessary-looking steps --- .github/workflows/TomcatIntegrationTest.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 745e02c..e178b9b 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -9,15 +9,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - - name: Set up Helm - uses: azure/setup-helm@v1 - with: - version: v3.4.0 - - - uses: actions/setup-python@v2 - with: - python-version: 3.7 - name: Create kind cluster uses: helm/kind-action@v1.2.0 From fc9ec88e04218b7baf84bccd6fe229f3d8023050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:06:38 +0200 Subject: [PATCH 03/33] small improvements --- tomcat/src/test/java/sample/IntegrationTest.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tomcat/src/test/java/sample/IntegrationTest.java b/tomcat/src/test/java/sample/IntegrationTest.java index 3af8cd0..24e728b 100644 --- a/tomcat/src/test/java/sample/IntegrationTest.java +++ b/tomcat/src/test/java/sample/IntegrationTest.java @@ -28,7 +28,7 @@ public class IntegrationTest { @Test - public void test() throws InterruptedException { + public void test() { Config config = new ConfigBuilder().withNamespace(null).build(); KubernetesClient client = new DefaultKubernetesClient(config); Operator operator = new Operator(client, DefaultConfigurationService.instance()); @@ -45,19 +45,20 @@ public void test() throws InterruptedException { MixedOperation, Resource> tomcatClient = client.customResources(Tomcat.class); - Namespace tt_ns = new NamespaceBuilder().withMetadata(new ObjectMetaBuilder().withName("tomcat-test").build()).build(); + Namespace testNs = new NamespaceBuilder().withMetadata( + new ObjectMetaBuilder().withName("tomcat-test").build()).build(); - client.namespaces().delete(tt_ns); + client.namespaces().delete(testNs); await().atMost(300, SECONDS).until(() -> client.namespaces().withName("tomcat-test").get() == null); - client.namespaces().createOrReplace(tt_ns); + client.namespaces().createOrReplace(testNs); tomcatClient.inNamespace("tomcat-test").create(tomcat); await().atMost(60, SECONDS).until(() -> { Tomcat updatedTomcat = tomcatClient.inNamespace("tomcat-test").withName("test-tomcat1").get(); - return updatedTomcat.getStatus() != null && (int) updatedTomcat.getStatus().getReadyReplicas() == 3; + return updatedTomcat.getStatus() != null && updatedTomcat.getStatus().getReadyReplicas() == 3; }); } From b0025fcca77c97ee005b4eb2fa310e6d02bf22a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:12:11 +0200 Subject: [PATCH 04/33] add documentation and move into right package --- .../operator}/sample/IntegrationTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) rename tomcat/src/test/java/{ => io/javaoperatorsdk/operator}/sample/IntegrationTest.java (85%) diff --git a/tomcat/src/test/java/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java similarity index 85% rename from tomcat/src/test/java/sample/IntegrationTest.java rename to tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 24e728b..803f6c2 100644 --- a/tomcat/src/test/java/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -1,4 +1,4 @@ -package sample; +package io.javaoperatorsdk.operator.sample; import io.fabric8.kubernetes.api.model.KubernetesResourceList; import io.fabric8.kubernetes.api.model.Namespace; @@ -38,7 +38,7 @@ public void test() { operator.register(new WebappController(client)); - Tomcat tomcat = loadYaml(Tomcat.class, "tomcat-sample1.yaml"); + Tomcat tomcat = loadYaml(Tomcat.class, "k8s/tomcat-sample1.yaml"); tomcat.getSpec().setReplicas(3); tomcat.getMetadata().setNamespace("tomcat-test"); @@ -48,6 +48,9 @@ public void test() { Namespace testNs = new NamespaceBuilder().withMetadata( new ObjectMetaBuilder().withName("tomcat-test").build()).build(); + // 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. client.namespaces().delete(testNs); await().atMost(300, SECONDS).until(() -> client.namespaces().withName("tomcat-test").get() == null); @@ -63,7 +66,7 @@ public void test() { } private T loadYaml(Class clazz, String yaml) { - try (InputStream is = new FileInputStream("k8s/" + yaml)) { + try (InputStream is = new FileInputStream(yaml)) { return Serialization.unmarshal(is, clazz); } catch (IOException ex) { throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); From 192757f8fbafcbcc81cb3f18a7532d78b723c71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:12:34 +0200 Subject: [PATCH 05/33] remove unused imports --- .../io/javaoperatorsdk/operator/sample/IntegrationTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 803f6c2..50b6ec9 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -13,9 +13,6 @@ import io.fabric8.kubernetes.client.utils.Serialization; 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.Test; import java.io.FileInputStream; @@ -24,7 +21,6 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; public class IntegrationTest { @Test From 304ac2a368d53779d53864cfeee4ee065a370364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:42:27 +0200 Subject: [PATCH 06/33] improving the code (untilAsserted) --- .../operator/sample/IntegrationTest.java | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 50b6ec9..e11d460 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -1,28 +1,27 @@ 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.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; import org.junit.Test; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.hamcrest.CoreMatchers.*; -import static java.util.concurrent.TimeUnit.SECONDS; import static org.awaitility.Awaitility.await; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; public class IntegrationTest { + + final static String TEST_NS = "tomcat-test"; + @Test public void test() { Config config = new ConfigBuilder().withNamespace(null).build(); @@ -34,38 +33,35 @@ public void test() { operator.register(new WebappController(client)); - Tomcat tomcat = loadYaml(Tomcat.class, "k8s/tomcat-sample1.yaml"); - + Tomcat tomcat = new Tomcat(); + tomcat.setMetadata(new ObjectMetaBuilder() + .withName("test-tomcat1") + .withNamespace(TEST_NS) + .build()); + tomcat.setSpec(new TomcatSpec()); tomcat.getSpec().setReplicas(3); - tomcat.getMetadata().setNamespace("tomcat-test"); + tomcat.getSpec().setVersion(9); MixedOperation, Resource> tomcatClient = client.customResources(Tomcat.class); Namespace testNs = new NamespaceBuilder().withMetadata( - new ObjectMetaBuilder().withName("tomcat-test").build()).build(); + new ObjectMetaBuilder().withName(TEST_NS).build()).build(); // 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. client.namespaces().delete(testNs); - await().atMost(300, SECONDS).until(() -> client.namespaces().withName("tomcat-test").get() == null); + await().atMost(5, MINUTES).until(() -> client.namespaces().withName("tomcat-test").get() == null); client.namespaces().createOrReplace(testNs); tomcatClient.inNamespace("tomcat-test").create(tomcat); - await().atMost(60, SECONDS).until(() -> { + await().atMost(2, MINUTES).untilAsserted(() -> { Tomcat updatedTomcat = tomcatClient.inNamespace("tomcat-test").withName("test-tomcat1").get(); - return updatedTomcat.getStatus() != null && updatedTomcat.getStatus().getReadyReplicas() == 3; + assertThat(updatedTomcat.getStatus(), is(notNullValue())); + assertThat(updatedTomcat.getStatus().getReadyReplicas(), equalTo(3)); }); } - - private T loadYaml(Class clazz, String yaml) { - try (InputStream is = new FileInputStream(yaml)) { - return Serialization.unmarshal(is, clazz); - } catch (IOException ex) { - throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); - } - } } From 4c203c9df0ca55161630697c57930481834b5e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Wed, 18 Aug 2021 23:09:56 +0200 Subject: [PATCH 07/33] small code improvements --- .../io/javaoperatorsdk/operator/sample/IntegrationTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index e11d460..7521a3e 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -5,8 +5,6 @@ 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.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; import org.junit.Test; @@ -42,7 +40,7 @@ public void test() { tomcat.getSpec().setReplicas(3); tomcat.getSpec().setVersion(9); - MixedOperation, Resource> tomcatClient = client.customResources(Tomcat.class); + var tomcatClient = client.customResources(Tomcat.class); Namespace testNs = new NamespaceBuilder().withMetadata( new ObjectMetaBuilder().withName(TEST_NS).build()).build(); @@ -56,7 +54,7 @@ public void test() { client.namespaces().createOrReplace(testNs); - tomcatClient.inNamespace("tomcat-test").create(tomcat); + tomcatClient.inNamespace(TEST_NS).create(tomcat); await().atMost(2, MINUTES).untilAsserted(() -> { Tomcat updatedTomcat = tomcatClient.inNamespace("tomcat-test").withName("test-tomcat1").get(); From bd4622b6a9a1ec6204cabe531f1dc927ac390f53 Mon Sep 17 00:00:00 2001 From: Charles_Sabourdin Date: Fri, 20 Aug 2021 12:44:06 +0200 Subject: [PATCH 08/33] testing KIND_REGISTRY on github action --- .github/workflows/TomcatIntegrationTest.yml | 132 +++++++++++++++++- tomcat/k8s/operator.yaml | 21 ++- .../src/test/java/sample/IntegrationTest.java | 2 +- webserver/k8s/operator.yaml | 22 +++ 4 files changed, 172 insertions(+), 5 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 4221783..8c4b2e4 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -21,20 +21,146 @@ jobs: - name: Create kind cluster uses: helm/kind-action@v1.2.0 + with: + cluster_name: ${{ job }} - name: Apply CRDs run: kubectl apply -f tomcat/k8s/crd.yaml - name: Set up Java and Maven - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: # java-version: ${{ matrix.java }} java-version: 15 - - uses: actions/cache@v2 + distribution: adopt-hotspot + + - name: cache + uses: actions/cache@v2 + if: ${{ !env.ACT }} with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- + + - name: Set up Maven + uses: stCarolas/setup-maven@v4 + if: ${{ env.ACT }} + with: + maven-version: 3.8.1 + + - name: Run unit tests + if: ${{ env.ACT }} + run: mvn --version + - name: Run unit tests - run: mvn -B test --file tomcat/pom.xml \ No newline at end of file + run: mvn -B test -q --file tomcat/pom.xml + + tomcat_local_apply_setup_test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up Helm + uses: azure/setup-helm@v1 + with: + version: v3.4.0 + + - uses: actions/setup-python@v2 + with: + python-version: 3.7 + + - name: test + if: ${{ !env.ACT }} + run: | + mkdir -p /etc/docker + echo -n "{\"exec-opts\": [\"native.cgroupdriver=systemd\"],\"log-driver\": \"json-file\",\"log-opts\": {\"max-size\": \"100m\"},\"storage-driver\": \"overlay2\"}" > /etc/docker/daemon.json + cat /etc/docker/daemon.json + sudo service docker status + + - name: Create Kubernetes KinD Cluster + uses: container-tools/kind-action@v1.5.0 + with: + cluster_name: tomcat-local-apply + registry: true + + # - name: Create kind cluster + # uses: helm/kind-action@v1.2.0 + # with: + # cluster_name: tomcat-local-apply #${{ job.name }} + # registry: true + # # docker stop tomcat-local-apply-control-plane ; docker rm tomcat-local-apply-control-plane ; sleep 1 + + - name: Apply CRDs + run: kubectl apply -f tomcat/k8s/crd.yaml + + - name: Set up Java and Maven + uses: actions/setup-java@v2 + with: + # java-version: ${{ matrix.java }} + java-version: 15 + distribution: adopt-hotspot + + - name: cache + uses: actions/cache@v2 + if: ${{ !env.ACT }} + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Set up Maven + uses: stCarolas/setup-maven@v4 + if: ${{ env.ACT }} + with: + maven-version: 3.8.1 + + - name: check that kube is empty + run: kubectl get tomcats,webapps,po + + - name: test local registry + run: | + # Checking env variable + if [[ "$KIND_REGISTRY" != "localhost:5000" ]]; then + echo "Wrong KIND_REGISTRY env variable: $KIND_REGISTRY" + exit 1 + fi + docker pull busybox + docker tag busybox localhost:5000/localbusybox + docker push localhost:5000/localbusybox + + - name: build jib + run: mvn install jib:dockerBuild jib:build -Djib.to.image=localhost:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests + + - name: build jib + run: docker images + + - name: install tomcat operator + run: kubectl apply -f tomcat/k8s/operator.yaml + + - name: install sample operators + run: kubectl create ns tomcatoperator-sample + + - name: install sample operators + run: for sample in $(ls tomcat/k8s/*sample*); do echo kubectl -n tomcatoperator-sample apply -f $sample; done + + - name: wait for sample operators + run: | + LOOP=0 &&\ + while [[ $(kubectl get pods -n tomcat-operator -l app=tomcat-operator -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" ]]; do \ + echo "waiting for pod" &&\ + kubectl logs -n tomcat-operator -l app=tomcat-operator &&\ + (( LOOP++ )) &&\ + if [[ $LOOP -gt 10 ]]; then break; fi &&\ + echo "loop number $LOOP" &&\ + sleep 5; \ + done + + - name: check operators + run: kubectl get deploy,tomcats,webapps,po -n tomcatoperator-sample + + + - name: check operators + run: kubectl get deploy,tomcats,webapps,po -n tomcat-operator diff --git a/tomcat/k8s/operator.yaml b/tomcat/k8s/operator.yaml index c3e5776..3248851 100644 --- a/tomcat/k8s/operator.yaml +++ b/tomcat/k8s/operator.yaml @@ -28,7 +28,8 @@ spec: serviceAccountName: tomcat-operator containers: - name: operator - image: tomcat-operator + image: localhost:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT + #image: tomcat-operator imagePullPolicy: IfNotPresent ports: - containerPort: 80 @@ -65,8 +66,26 @@ metadata: rules: - apiGroups: - "" + - "extensions" + - "apps" resources: - deployments - services + - pods verbs: - '*' +- apiGroups: + - "apiextensions.k8s.io" + resources: + - customresourcedefinitions + verbs: + - '*' +- apiGroups: + - "tomcatoperator.io" + resources: + - tomcats + - tomcats/status + - webapps + - webapps/status + verbs: + - '*' \ No newline at end of file diff --git a/tomcat/src/test/java/sample/IntegrationTest.java b/tomcat/src/test/java/sample/IntegrationTest.java index 3af8cd0..32c17d2 100644 --- a/tomcat/src/test/java/sample/IntegrationTest.java +++ b/tomcat/src/test/java/sample/IntegrationTest.java @@ -55,7 +55,7 @@ public void test() throws InterruptedException { tomcatClient.inNamespace("tomcat-test").create(tomcat); - await().atMost(60, SECONDS).until(() -> { + await().atMost(120, SECONDS).until(() -> { Tomcat updatedTomcat = tomcatClient.inNamespace("tomcat-test").withName("test-tomcat1").get(); return updatedTomcat.getStatus() != null && (int) updatedTomcat.getStatus().getReadyReplicas() == 3; }); diff --git a/webserver/k8s/operator.yaml b/webserver/k8s/operator.yaml index a6e56ef..926b2c3 100644 --- a/webserver/k8s/operator.yaml +++ b/webserver/k8s/operator.yaml @@ -72,5 +72,27 @@ rules: - deployments - services - configmaps + - pods + verbs: + - '*' +- apiGroups: + - "apps" + resources: + - deployments + - services + - configmaps + verbs: + - '*' +- apiGroups: + - "apiextensions.k8s.io" + resources: + - customresourcedefinitions + verbs: + - '*' +- apiGroups: + - "sample.javaoperatorsdk" + resources: + - webservers + - webservers/status verbs: - '*' From 9868d4bba3387a8fce971705d635b137152a79a8 Mon Sep 17 00:00:00 2001 From: Charles_Sabourdin Date: Fri, 20 Aug 2021 12:46:46 +0200 Subject: [PATCH 09/33] correct cluster name --- .github/workflows/TomcatIntegrationTest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 8c4b2e4..12c9450 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -22,7 +22,7 @@ jobs: - name: Create kind cluster uses: helm/kind-action@v1.2.0 with: - cluster_name: ${{ job }} + cluster_name: tomcat-integration - name: Apply CRDs run: kubectl apply -f tomcat/k8s/crd.yaml From 7917f89f37e85a40da0c262b7e80d4053eaf3cb8 Mon Sep 17 00:00:00 2001 From: Charles_Sabourdin Date: Fri, 20 Aug 2021 12:48:04 +0200 Subject: [PATCH 10/33] correct cluster name --- .github/workflows/TomcatIntegrationTest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 12c9450..43dcdf1 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -72,7 +72,7 @@ jobs: python-version: 3.7 - name: test - if: ${{ !env.ACT }} + if: ${{ env.ACT }} run: | mkdir -p /etc/docker echo -n "{\"exec-opts\": [\"native.cgroupdriver=systemd\"],\"log-driver\": \"json-file\",\"log-opts\": {\"max-size\": \"100m\"},\"storage-driver\": \"overlay2\"}" > /etc/docker/daemon.json From f0a70365b9a2e30d512b9d946c23a4093e2fc3af Mon Sep 17 00:00:00 2001 From: Charles_Sabourdin Date: Fri, 20 Aug 2021 12:58:05 +0200 Subject: [PATCH 11/33] set --- .github/workflows/TomcatIntegrationTest.yml | 4 ++-- tomcat/k8s/operator.yaml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 43dcdf1..720a3e2 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -111,7 +111,7 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - - name: Set up Maven + - name: Set up Maven for local ACT uses: stCarolas/setup-maven@v4 if: ${{ env.ACT }} with: @@ -132,7 +132,7 @@ jobs: docker push localhost:5000/localbusybox - name: build jib - run: mvn install jib:dockerBuild jib:build -Djib.to.image=localhost:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests + run: mvn install jib:dockerBuild jib:build -Djib.to.image=$KIND_REGISTRY/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests - name: build jib run: docker images diff --git a/tomcat/k8s/operator.yaml b/tomcat/k8s/operator.yaml index 3248851..2d3d69a 100644 --- a/tomcat/k8s/operator.yaml +++ b/tomcat/k8s/operator.yaml @@ -28,7 +28,8 @@ spec: serviceAccountName: tomcat-operator containers: - name: operator - image: localhost:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT + #image: localhost:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT + image: kind-registry:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT #image: tomcat-operator imagePullPolicy: IfNotPresent ports: From e0a71ea899680619cb6a877196fec52404577b3c Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Fri, 20 Aug 2021 13:14:24 +0200 Subject: [PATCH 12/33] set $KIND_REGISTRY --- .github/workflows/TomcatIntegrationTest.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 720a3e2..6911509 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -125,7 +125,6 @@ jobs: # Checking env variable if [[ "$KIND_REGISTRY" != "localhost:5000" ]]; then echo "Wrong KIND_REGISTRY env variable: $KIND_REGISTRY" - exit 1 fi docker pull busybox docker tag busybox localhost:5000/localbusybox From 886096dd52995e3d56614a191a7c7d8954ad5f6d Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Fri, 20 Aug 2021 13:19:55 +0200 Subject: [PATCH 13/33] set -Djib.allowInsecureRegistries=true --- .github/workflows/TomcatIntegrationTest.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 6911509..90eafc5 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -126,12 +126,9 @@ jobs: if [[ "$KIND_REGISTRY" != "localhost:5000" ]]; then echo "Wrong KIND_REGISTRY env variable: $KIND_REGISTRY" fi - docker pull busybox - docker tag busybox localhost:5000/localbusybox - docker push localhost:5000/localbusybox - name: build jib - run: mvn install jib:dockerBuild jib:build -Djib.to.image=$KIND_REGISTRY/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests + run: mvn -B install jib:dockerBuild jib:build -Djib.allowInsecureRegistries=true -Djib.to.image=$KIND_REGISTRY/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests - name: build jib run: docker images From cc4042b3ab1afed1d28644d19bb880864ec0c011 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Fri, 20 Aug 2021 13:51:34 +0200 Subject: [PATCH 14/33] renamed and clean actions --- .github/workflows/TomcatIntegrationTest.yml | 38 +++++++++++++-------- tomcat/k8s/operator.yaml | 1 + 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 90eafc5..b5a3158 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -92,9 +92,6 @@ jobs: # registry: true # # docker stop tomcat-local-apply-control-plane ; docker rm tomcat-local-apply-control-plane ; sleep 1 - - name: Apply CRDs - run: kubectl apply -f tomcat/k8s/crd.yaml - - name: Set up Java and Maven uses: actions/setup-java@v2 with: @@ -118,9 +115,12 @@ jobs: maven-version: 3.8.1 - name: check that kube is empty + if: ${{ env.ACT }} run: kubectl get tomcats,webapps,po + - name: test local registry + if: ${{ env.ACT }} run: | # Checking env variable if [[ "$KIND_REGISTRY" != "localhost:5000" ]]; then @@ -130,19 +130,16 @@ jobs: - name: build jib run: mvn -B install jib:dockerBuild jib:build -Djib.allowInsecureRegistries=true -Djib.to.image=$KIND_REGISTRY/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests - - name: build jib - run: docker images + - name: Apply CRDs + run: kubectl apply -f tomcat/k8s/crd.yaml - name: install tomcat operator run: kubectl apply -f tomcat/k8s/operator.yaml - - name: install sample operators + - name: create ns tomcatoperator-sample run: kubectl create ns tomcatoperator-sample - - name: install sample operators - run: for sample in $(ls tomcat/k8s/*sample*); do echo kubectl -n tomcatoperator-sample apply -f $sample; done - - - name: wait for sample operators + - name: wait for operators ready run: | LOOP=0 &&\ while [[ $(kubectl get pods -n tomcat-operator -l app=tomcat-operator -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" ]]; do \ @@ -154,9 +151,22 @@ jobs: sleep 5; \ done - - name: check operators - run: kubectl get deploy,tomcats,webapps,po -n tomcatoperator-sample + - name: install sample operators + run: | + for sample in $(ls tomcat/k8s/*sample*); do + kubectl -n tomcatoperator-sample apply -f $sample; + done - - name: check operators - run: kubectl get deploy,tomcats,webapps,po -n tomcat-operator + - name: check pod correctly started + run: | + LOOP=0 &&\ + while [[ $(kubectl get pods -n tomcatoperator-sample -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True True True True True True" ]]; do \ + echo "waiting for pod" &&\ + kubectl logs -n tomcat-operator -l app=tomcat-operator &&\ + (( LOOP++ )) &&\ + if [[ $LOOP -gt 10 ]]; then break; fi &&\ + echo "loop number $LOOP" &&\ + sleep 5; \ + done + \ No newline at end of file diff --git a/tomcat/k8s/operator.yaml b/tomcat/k8s/operator.yaml index 2d3d69a..0b61b2d 100644 --- a/tomcat/k8s/operator.yaml +++ b/tomcat/k8s/operator.yaml @@ -73,6 +73,7 @@ rules: - deployments - services - pods + - pods/exec verbs: - '*' - apiGroups: From 7c39b221a0b615b22ff7d339b1a5610d182a9ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:16:07 +0200 Subject: [PATCH 15/33] add test for webapp deployment --- .../operator/sample/IntegrationTest.java | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 7521a3e..622623e 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -1,14 +1,21 @@ package io.javaoperatorsdk.operator.sample; import io.fabric8.kubernetes.api.model.*; +import io.fabric8.kubernetes.client.*; 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.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; import org.junit.Test; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + import static java.util.concurrent.TimeUnit.MINUTES; import static org.hamcrest.CoreMatchers.*; @@ -26,9 +33,7 @@ public void test() { KubernetesClient client = new DefaultKubernetesClient(config); Operator operator = new Operator(client, DefaultConfigurationService.instance()); - TomcatController tomcatController = new TomcatController(client); - operator.register(tomcatController); - + operator.register(new TomcatController(client)); operator.register(new WebappController(client)); Tomcat tomcat = new Tomcat(); @@ -40,7 +45,18 @@ public void test() { tomcat.getSpec().setReplicas(3); 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(); @@ -55,11 +71,30 @@ public void test() { client.namespaces().createOrReplace(testNs); tomcatClient.inNamespace(TEST_NS).create(tomcat); + webappClient.inNamespace(TEST_NS).create(webapp1); + + await().atMost(1, MINUTES).until(() -> client.services().inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).get() != null); + LocalPortForward localPortForward = client.services().inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).portForward(80); await().atMost(2, MINUTES).untilAsserted(() -> { - Tomcat updatedTomcat = tomcatClient.inNamespace("tomcat-test").withName("test-tomcat1").get(); + Tomcat updatedTomcat = tomcatClient.inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).get(); + Webapp updatedWebapp = webappClient.inNamespace(TEST_NS).withName(webapp1.getMetadata().getName()).get(); assertThat(updatedTomcat.getStatus(), is(notNullValue())); assertThat(updatedTomcat.getStatus().getReadyReplicas(), equalTo(3)); + assertThat(updatedWebapp.getStatus(), is(notNullValue())); + assertThat(updatedWebapp.getStatus().getDeployedArtifact(), is(notNullValue())); + + URI uri = URI.create("http://localhost:" + localPortForward.getLocalPort() + "/" + webapp1.getSpec().getContextPath()); + try { + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(uri) + .build(); + int statusCode = httpClient.send(request, HttpResponse.BodyHandlers.ofString()).statusCode(); + assertThat("Failed to access " + uri, statusCode, equalTo(200)); + } catch (IOException ex) { + throw new AssertionError("Failed to access " + uri, ex); + } }); } } From 706b60a2348439677b755e56ed23c60cc44dfc21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Fri, 20 Aug 2021 18:16:21 +0200 Subject: [PATCH 16/33] improve logging configuration for tests --- tomcat/src/test/resources/log4j2.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tomcat/src/test/resources/log4j2.xml diff --git a/tomcat/src/test/resources/log4j2.xml b/tomcat/src/test/resources/log4j2.xml new file mode 100644 index 0000000..24576aa --- /dev/null +++ b/tomcat/src/test/resources/log4j2.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From c38821fa8ab5a0beac0c5f04ac4f0c32936c9fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Sat, 21 Aug 2021 16:15:53 +0200 Subject: [PATCH 17/33] WebappController now waits until Tomcat is fully up and running before starting download process --- .../operator/sample/TomcatEvent.java | 50 ++++++++++++ .../operator/sample/TomcatEventSource.java | 81 +++++++++++++++++++ .../operator/sample/WebappController.java | 37 ++++++++- 3 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java create mode 100644 tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java new file mode 100644 index 0000000..3f9480b --- /dev/null +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java @@ -0,0 +1,50 @@ +package io.javaoperatorsdk.operator.sample; + +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.client.Watcher; +import io.javaoperatorsdk.operator.processing.event.AbstractEvent; + +public class TomcatEvent extends AbstractEvent { + + private final Watcher.Action action; + private final Tomcat tomcat; + + public TomcatEvent( + Watcher.Action action, Tomcat resource, TomcatEventSource tomcatEventSource, String webappUid) { + super(webappUid, tomcatEventSource); + this.action = action; + this.tomcat = resource; + } + + public Watcher.Action getAction() { + return action; + } + + public String resourceUid() { + return getTomcat().getMetadata().getUid(); + } + + @Override + public String toString() { + return "CustomResourceEvent{" + + "action=" + + action + + ", resource=[ name=" + + getTomcat().getMetadata().getName() + + ", kind=" + + getTomcat().getKind() + + ", apiVersion=" + + getTomcat().getApiVersion() + + " ,resourceVersion=" + + getTomcat().getMetadata().getResourceVersion() + + ", markedForDeletion: " + + (getTomcat().getMetadata().getDeletionTimestamp() != null + && !getTomcat().getMetadata().getDeletionTimestamp().isEmpty()) + + " ]" + + '}'; + } + + public Tomcat getTomcat() { + return tomcat; + } +} diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java new file mode 100644 index 0000000..3649fb1 --- /dev/null +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java @@ -0,0 +1,81 @@ +package io.javaoperatorsdk.operator.sample; + +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.WatcherException; +import io.javaoperatorsdk.operator.processing.event.AbstractEventSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; + +import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID; +import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion; + +public class TomcatEventSource extends AbstractEventSource implements Watcher { + private static final Logger log = LoggerFactory.getLogger(TomcatEventSource.class); + + private final KubernetesClient client; + + public static TomcatEventSource createAndRegisterWatch(KubernetesClient client) { + TomcatEventSource tomcatEventSource = new TomcatEventSource(client); + tomcatEventSource.registerWatch(); + return tomcatEventSource; + } + + private TomcatEventSource(KubernetesClient client) { + this.client = client; + } + + private void registerWatch() { + var tomcatClient = client.customResources(Tomcat.class); + tomcatClient.inAnyNamespace().watch(this); + } + + @Override + public void eventReceived(Action action, Tomcat tomcat) { + log.info( + "Event received for action: {}, Tomcat: {} (rr={})", + action.name(), + tomcat.getMetadata().getName(), + tomcat.getStatus().getReadyReplicas()); + + if (action == Action.ERROR) { + log.warn( + "Skipping {} event for custom resource uid: {}, version: {}", + action, + getUID(tomcat), + getVersion(tomcat)); + return; + } + + var webappClient = client.customResources(Webapp.class); + Optional webapp = webappClient.inNamespace(tomcat.getMetadata().getNamespace()) + .list().getItems().stream() + .filter(wapp -> wapp.getSpec().getTomcat().equals(tomcat.getMetadata().getName())) + .findFirst(); + + if (webapp.isPresent()) { + eventHandler.handleEvent(new TomcatEvent(action, tomcat, this, + webapp.get().getMetadata().getUid())); + } else { + log.debug("Webapp not found for Tomcat {}", tomcat.getMetadata().getName()); + } + } + + @Override + public void onClose(WatcherException e) { + if (e == null) { + return; + } + if (e.isHttpGone()) { + log.warn("Received error for watch, will try to reconnect.", e); + registerWatch(); + } else { + // Note that this should not happen normally, since fabric8 client handles reconnect. + // In case it tries to reconnect this method is not called. + log.error("Unexpected error happened with watch. Will exit.", e); + System.exit(1); + } + } +} 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..0c06c71 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java @@ -4,6 +4,7 @@ import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.*; +import io.javaoperatorsdk.operator.processing.event.EventSourceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,18 +23,43 @@ public WebappController(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; } + @Override + public void init(EventSourceManager eventSourceManager) { + TomcatEventSource tomcatEventSource = TomcatEventSource.createAndRegisterWatch(kubernetesClient); + eventSourceManager.registerEventSource("tomcat-event-source", tomcatEventSource); + } + + /** + * This method will be called not only on changes to Webapp objects but also when Tomcat objects change. + */ @Override public UpdateControl createOrUpdateResource(Webapp webapp, Context context) { if (webapp.getStatus() != null && Objects.equals(webapp.getSpec().getUrl(), webapp.getStatus().getDeployedArtifact())) { return UpdateControl.noUpdate(); } - String[] command = new String[] {"wget", "-O", "/data/" + webapp.getSpec().getContextPath() + ".war", webapp.getSpec().getUrl()}; + var tomcatClient = kubernetesClient.customResources(Tomcat.class); + Tomcat tomcat = tomcatClient.inNamespace(webapp.getMetadata().getNamespace()).withName(webapp.getSpec().getTomcat()).get(); + if (tomcat == null) { + throw new IllegalStateException("Cannot find Tomcat " + webapp.getSpec().getTomcat() + " for Webapp " + webapp.getMetadata().getName() + " in namespace " + webapp.getMetadata().getNamespace()); + } - executeCommandInAllPods(kubernetesClient, webapp, command); + if (tomcat.getStatus() != null && Objects.equals(tomcat.getSpec().getReplicas(), tomcat.getStatus().getReadyReplicas())) { + log.info("Tomcat is ready and webapps not yet deployed. Commencing deployment of {} in Tomcat {}", webapp.getMetadata().getName(), tomcat.getMetadata().getName()); + String[] command = new String[]{"wget", "-O", "/data/" + webapp.getSpec().getContextPath() + ".war", webapp.getSpec().getUrl()}; - //webapp.getStatus().setDeployedArtifact(webapp.getSpec().getUrl()); - return UpdateControl.updateStatusSubResource(webapp); + executeCommandInAllPods(kubernetesClient, webapp, command); + + if (webapp.getStatus() == null) { + webapp.setStatus(new WebappStatus()); + } + webapp.getStatus().setDeployedArtifact(webapp.getSpec().getUrl()); + return UpdateControl.updateStatusSubResource(webapp); + } else { + log.info("WebappController invoked but Tomcat not ready yet ({}/{})", tomcat.getSpec().getReplicas(), + tomcat.getStatus() != null ? tomcat.getStatus().getReadyReplicas() : 0); + return UpdateControl.noUpdate(); + } } @Override @@ -41,6 +67,9 @@ public DeleteControl deleteResource(Webapp webapp, Context context) { String[] command = new String[] {"rm", "/data/" + webapp.getSpec().getContextPath() + ".war"}; executeCommandInAllPods(kubernetesClient, webapp, command); + if (webapp.getStatus() != null) { + webapp.getStatus().setDeployedArtifact(null); + } return DeleteControl.DEFAULT_DELETE; } From b5ca270025f4ed5c03e0cda2383544e2b61093b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Sat, 21 Aug 2021 16:16:35 +0200 Subject: [PATCH 18/33] IntegrationTest uses a curl Pod to verify if Webapp is correctly deployed into Tomcat --- .../operator/sample/IntegrationTest.java | 68 ++++++++++--------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 622623e..9bdf9ec 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -1,25 +1,20 @@ package io.javaoperatorsdk.operator.sample; import io.fabric8.kubernetes.api.model.*; -import io.fabric8.kubernetes.client.*; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; -import io.fabric8.kubernetes.client.dsl.MixedOperation; -import io.fabric8.kubernetes.client.dsl.Resource; +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 org.junit.Test; - -import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static java.util.concurrent.TimeUnit.MINUTES; -import static org.hamcrest.CoreMatchers.*; - import static org.awaitility.Awaitility.await; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.notNullValue; @@ -27,12 +22,14 @@ public class IntegrationTest { final static String TEST_NS = "tomcat-test"; + final static Logger log = LoggerFactory.getLogger(IntegrationTest.class); + @Test public void test() { Config config = new ConfigBuilder().withNamespace(null).build(); KubernetesClient client = new DefaultKubernetesClient(config); - Operator operator = new Operator(client, DefaultConfigurationService.instance()); + Operator operator = new Operator(client, DefaultConfigurationService.instance()); operator.register(new TomcatController(client)); operator.register(new WebappController(client)); @@ -61,21 +58,23 @@ public void test() { Namespace testNs = new NamespaceBuilder().withMetadata( new ObjectMetaBuilder().withName(TEST_NS).build()).build(); - // 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. - client.namespaces().delete(testNs); - - await().atMost(5, MINUTES).until(() -> client.namespaces().withName("tomcat-test").get() == null); + if (testNs != null) { + // 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().createOrReplace(testNs); + log.info("Creating test namespace {}", TEST_NS); + client.namespaces().create(testNs); + log.info("Creating test resources"); tomcatClient.inNamespace(TEST_NS).create(tomcat); webappClient.inNamespace(TEST_NS).create(webapp1); - await().atMost(1, MINUTES).until(() -> client.services().inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).get() != null); - LocalPortForward localPortForward = client.services().inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).portForward(80); - + log.info("Waiting 2 minutes for Tomcat and Webapp CR statuses to be updated"); await().atMost(2, MINUTES).untilAsserted(() -> { Tomcat updatedTomcat = tomcatClient.inNamespace(TEST_NS).withName(tomcat.getMetadata().getName()).get(); Webapp updatedWebapp = webappClient.inNamespace(TEST_NS).withName(webapp1.getMetadata().getName()).get(); @@ -83,18 +82,25 @@ public void test() { assertThat(updatedTomcat.getStatus().getReadyReplicas(), equalTo(3)); assertThat(updatedWebapp.getStatus(), is(notNullValue())); assertThat(updatedWebapp.getStatus().getDeployedArtifact(), is(notNullValue())); + }); - URI uri = URI.create("http://localhost:" + localPortForward.getLocalPort() + "/" + webapp1.getSpec().getContextPath()); + 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 { - HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest request = HttpRequest.newBuilder() - .uri(uri) - .build(); - int statusCode = httpClient.send(request, HttpResponse.BodyHandlers.ofString()).statusCode(); - assertThat("Failed to access " + uri, statusCode, equalTo(200)); - } catch (IOException ex) { - throw new AssertionError("Failed to access " + uri, ex); + String curlOutput = client.pods().inNamespace(TEST_NS).withName(curlPod.getMetadata().getName()).getLog(); + assertThat(curlOutput, equalTo("200")); + } catch (KubernetesClientException ex) { + throw new AssertionError(ex); } }); + } } From 7793ee901397bcc7e5cec8bf524f5d24b9fac537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Sat, 21 Aug 2021 17:01:51 +0200 Subject: [PATCH 19/33] logging configuration --- tomcat/src/main/resources/log4j2.xml | 2 +- tomcat/src/test/resources/log4j2.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tomcat/src/main/resources/log4j2.xml b/tomcat/src/main/resources/log4j2.xml index 0e6991e..a99aaf3 100644 --- a/tomcat/src/main/resources/log4j2.xml +++ b/tomcat/src/main/resources/log4j2.xml @@ -2,7 +2,7 @@ - + diff --git a/tomcat/src/test/resources/log4j2.xml b/tomcat/src/test/resources/log4j2.xml index 24576aa..a99aaf3 100644 --- a/tomcat/src/test/resources/log4j2.xml +++ b/tomcat/src/test/resources/log4j2.xml @@ -6,7 +6,6 @@ - From f671d7fcfb0cc5e5ce1180e99154dfe9880a6462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Sat, 21 Aug 2021 17:02:20 +0200 Subject: [PATCH 20/33] add documentation --- .../sample/DeploymentEventSource.java | 4 ++ .../operator/sample/TomcatController.java | 4 ++ .../operator/sample/TomcatEvent.java | 1 - .../operator/sample/TomcatEventSource.java | 9 ++--- .../operator/sample/WatchedResource.java | 40 ------------------- .../operator/sample/Webapp.java | 3 ++ 6 files changed, 15 insertions(+), 46 deletions(-) delete mode 100644 tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WatchedResource.java 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..55a85c8 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEventSource.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentEventSource.java @@ -11,6 +11,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Used by the TomcatController to watch changes on Deployment objects. As the Pods of the Deployment start up + * the TomcatController updates the status.readyReplicas field. + */ public class DeploymentEventSource extends AbstractEventSource implements Watcher { private static final Logger log = LoggerFactory.getLogger(DeploymentEventSource.class); 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..12f1a1e 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatController.java @@ -19,6 +19,10 @@ import java.util.Objects; import java.util.Optional; +/** + * Runs a specified number of Tomcat app server Pods. It uses a Deployment to create the Pods. Also creates a + * Service over which the Pods can be accessed. + */ @Controller public class TomcatController implements ResourceController { diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java index 3f9480b..f9bfca9 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java @@ -1,6 +1,5 @@ package io.javaoperatorsdk.operator.sample; -import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.Watcher; import io.javaoperatorsdk.operator.processing.event.AbstractEvent; diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java index 3649fb1..fe9bf6f 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEventSource.java @@ -12,6 +12,9 @@ import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID; import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion; +/** + * Used by the WebappController to watch changes on Tomcat objects + */ public class TomcatEventSource extends AbstractEventSource implements Watcher { private static final Logger log = LoggerFactory.getLogger(TomcatEventSource.class); @@ -34,11 +37,7 @@ private void registerWatch() { @Override public void eventReceived(Action action, Tomcat tomcat) { - log.info( - "Event received for action: {}, Tomcat: {} (rr={})", - action.name(), - tomcat.getMetadata().getName(), - tomcat.getStatus().getReadyReplicas()); + log.info("Event received for action: {}, Tomcat: {}", action.name(), tomcat.getMetadata().getName()); if (action == Action.ERROR) { log.warn( diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WatchedResource.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WatchedResource.java deleted file mode 100644 index cdebcbf..0000000 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WatchedResource.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.javaoperatorsdk.operator.sample; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import java.util.Objects; -import org.apache.commons.lang3.builder.EqualsBuilder; - -class WatchedResource { - private final String type; - private final String name; - - public WatchedResource(String type, String name) { - this.type = type; - this.name = name; - } - - public static WatchedResource fromResource(HasMetadata resource) { - return new WatchedResource(resource.getKind(), resource.getMetadata().getName()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - - if (o == null || getClass() != o.getClass()) return false; - - WatchedResource that = (WatchedResource) o; - - return new EqualsBuilder().append(type, that.type).append(name, that.name).isEquals(); - } - - @Override - public int hashCode() { - return Objects.hash(type, name); - } - - @Override - public String toString() { - return "WatchedResource{" + "type='" + type + '\'' + ", name='" + name + '\'' + '}'; - } -} diff --git a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java index 75e7a64..1238264 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/Webapp.java @@ -5,6 +5,9 @@ import io.fabric8.kubernetes.model.annotation.Group; import io.fabric8.kubernetes.model.annotation.Version; +/** + * Represents a web application deployed in a Tomcat deployment + */ @Group("tomcatoperator.io") @Version("v1") public class Webapp extends CustomResource implements Namespaced {} From a860b2ca69a58b9e677d55c0068e964dd219e49b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20S=C3=A1ndor?= <10675791+adam-sandor@users.noreply.github.com> Date: Sat, 21 Aug 2021 17:18:57 +0200 Subject: [PATCH 21/33] upgrade to jdk v 1.9.2 --- tomcat/pom.xml | 2 +- .../io/javaoperatorsdk/operator/sample/DeploymentEvent.java | 4 ++-- .../java/io/javaoperatorsdk/operator/sample/TomcatEvent.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tomcat/pom.xml b/tomcat/pom.xml index 5f3069d..781154b 100644 --- a/tomcat/pom.xml +++ b/tomcat/pom.xml @@ -26,7 +26,7 @@ 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/TomcatEvent.java b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java index f9bfca9..b10f56d 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/TomcatEvent.java @@ -1,9 +1,9 @@ package io.javaoperatorsdk.operator.sample; import io.fabric8.kubernetes.client.Watcher; -import io.javaoperatorsdk.operator.processing.event.AbstractEvent; +import io.javaoperatorsdk.operator.processing.event.DefaultEvent; -public class TomcatEvent extends AbstractEvent { +public class TomcatEvent extends DefaultEvent { private final Watcher.Action action; private final Tomcat tomcat; From 6315926c969bbc27b2a5493e5b1d0ebf8d40afc3 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Mon, 23 Aug 2021 10:00:52 +0200 Subject: [PATCH 22/33] put a cleanner break --- .github/workflows/TomcatIntegrationTest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index b5a3158..f0c119b 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -165,7 +165,7 @@ jobs: echo "waiting for pod" &&\ kubectl logs -n tomcat-operator -l app=tomcat-operator &&\ (( LOOP++ )) &&\ - if [[ $LOOP -gt 10 ]]; then break; fi &&\ + if [[ $LOOP -gt 10 ]]; then exit 1; fi &&\ echo "loop number $LOOP" &&\ sleep 5; \ done From 06a873afe3a1fafdaa7fccef6abcb2babdd00c39 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Mon, 23 Aug 2021 12:55:24 +0200 Subject: [PATCH 23/33] clean ressource after test --- .../io/javaoperatorsdk/operator/sample/IntegrationTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 9bdf9ec..d944e94 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -7,6 +7,7 @@ import io.fabric8.kubernetes.client.extended.run.RunConfigBuilder; import io.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; +import org.junit.AfterClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -102,5 +103,9 @@ public void test() { } }); + webappClient.inNamespace(TEST_NS).delete(webapp1); + tomcatClient.inNamespace(TEST_NS).delete(tomcat); + client.pods().inNamespace(TEST_NS).withName(curlPod.getMetadata().getName()).delete(); } + } From cceb2fa31076dc82582eea9897ecb61c00060101 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Mon, 23 Aug 2021 14:06:09 +0200 Subject: [PATCH 24/33] increase time out --- .../io/javaoperatorsdk/operator/sample/IntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index d944e94..52720d0 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -94,7 +94,7 @@ public void test() { .withImage("curlimages/curl:7.78.0") .withRestartPolicy("Never") .build()).done(); - await().atMost(2, MINUTES).untilAsserted(() -> { + await().atMost(5, MINUTES).untilAsserted(() -> { try { String curlOutput = client.pods().inNamespace(TEST_NS).withName(curlPod.getMetadata().getName()).getLog(); assertThat(curlOutput, equalTo("200")); From c164a913a43e89998ca6421a953d85615b17c4ca Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 24 Aug 2021 15:30:50 +0200 Subject: [PATCH 25/33] change webapps path --- tomcat/k8s/webapp-sample2.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/k8s/webapp-sample2.yaml b/tomcat/k8s/webapp-sample2.yaml index a548451..e0415f9 100644 --- a/tomcat/k8s/webapp-sample2.yaml +++ b/tomcat/k8s/webapp-sample2.yaml @@ -5,4 +5,4 @@ metadata: spec: tomcat: test-tomcat2 url: charlottemach.com/assets/jax.war - contextPath: mysample + contextPath: othercontext From 5ee5527a620f867edf17a6f168bd9aae47fbe709 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 24 Aug 2021 15:32:23 +0200 Subject: [PATCH 26/33] reverte to default image (deploy change in the github action) --- tomcat/k8s/operator.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tomcat/k8s/operator.yaml b/tomcat/k8s/operator.yaml index 0b61b2d..a88b651 100644 --- a/tomcat/k8s/operator.yaml +++ b/tomcat/k8s/operator.yaml @@ -28,9 +28,7 @@ spec: serviceAccountName: tomcat-operator containers: - name: operator - #image: localhost:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT - image: kind-registry:5000/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT - #image: tomcat-operator + image: tomcat-operator imagePullPolicy: IfNotPresent ports: - containerPort: 80 From 716b96277a2b5c20c6b1a69170154a05389ee470 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 24 Aug 2021 15:33:58 +0200 Subject: [PATCH 27/33] improve feedback on webapps download --- tomcat/k8s/crd.yaml | 4 + .../operator/sample/WebappController.java | 87 ++++++++++++++++--- .../operator/sample/WebappStatus.java | 10 +++ .../operator/sample/IntegrationTest.java | 11 +-- 4 files changed, 93 insertions(+), 19 deletions(-) diff --git a/tomcat/k8s/crd.yaml b/tomcat/k8s/crd.yaml index 44533a3..509c77b 100644 --- a/tomcat/k8s/crd.yaml +++ b/tomcat/k8s/crd.yaml @@ -80,6 +80,10 @@ spec: properties: deployedArtifact: type: string + deploymentStatus: + type: array + items: + type: string required: [spec] # either Namespaced or Cluster scope: Namespaced 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 0c06c71..682ca2a 100644 --- a/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java +++ b/tomcat/src/main/java/io/javaoperatorsdk/operator/sample/WebappController.java @@ -3,14 +3,23 @@ import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.ExecListener; +import io.fabric8.kubernetes.client.dsl.ExecWatch; import io.javaoperatorsdk.operator.api.*; import io.javaoperatorsdk.operator.processing.event.EventSourceManager; +import okhttp3.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.charset.Charset; import java.util.List; import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; @Controller public class WebappController implements ResourceController { @@ -47,17 +56,21 @@ public UpdateControl createOrUpdateResource(Webapp webapp, Context createOrUpdateResource(Webapp webapp, Context context) { String[] command = new String[] {"rm", "/data/" + webapp.getSpec().getContextPath() + ".war"}; - executeCommandInAllPods(kubernetesClient, webapp, command); + String[] commandStatusInAllPods = executeCommandInAllPods(kubernetesClient, webapp, command); if (webapp.getStatus() != null) { webapp.getStatus().setDeployedArtifact(null); + webapp.getStatus().setDeploymentStatus(commandStatusInAllPods); } return DeleteControl.DEFAULT_DELETE; } - private void executeCommandInAllPods( + private String[] executeCommandInAllPods( KubernetesClient kubernetesClient, Webapp webapp, String[] command) { + String[] status = new String[0]; + Deployment deployment = kubernetesClient .apps() @@ -91,20 +107,67 @@ private void executeCommandInAllPods( .withLabels(deployment.getSpec().getSelector().getMatchLabels()) .list() .getItems(); - for (Pod pod : pods) { + status = new String[pods.size()]; + for (int i=0; i data = new CompletableFuture<>(); + try (ExecWatch execWatch = execCmd(pod, data, command)) { + status[i] = ""+pod.getMetadata().getName()+":"+data.get(30, TimeUnit.SECONDS);; + } catch (ExecutionException e) { + status[i] = ""+pod.getMetadata().getName()+": ExecutionException - "+e.getMessage(); + } catch (InterruptedException e) { + status[i] = ""+pod.getMetadata().getName()+": InterruptedException - "+e.getMessage(); + } catch (TimeoutException e) { + status[i] = ""+pod.getMetadata().getName()+": TimeoutException - "+e.getMessage(); + } + } + } + return status; + } + + private ExecWatch execCmd(Pod pod, CompletableFuture data, String... command) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + return kubernetesClient.pods() + .inNamespace(pod.getMetadata().getNamespace()) .withName(pod.getMetadata().getName()) .inContainer("war-downloader") - .writingOutput(new ByteArrayOutputStream()) - .writingError(new ByteArrayOutputStream()) + .writingOutput(baos) + .writingError(baos) + .usingListener(new SimpleListener(data, baos)) .exec(command); - } + } + + static class SimpleListener implements ExecListener { + + private CompletableFuture data; + private ByteArrayOutputStream baos; + private final Logger log = LoggerFactory.getLogger(getClass()); + public SimpleListener(CompletableFuture data, ByteArrayOutputStream baos) { + this.data = data; + this.baos = baos; + } + + @Override + public void onOpen(Response response) { + log.debug("Reading data... " + response.message()); + } + + @Override + public void onFailure(Throwable t, Response response) { + log.debug(t.getMessage() + " " + response.message()); + data.completeExceptionally(t); + } + + @Override + public void onClose(int code, String reason) { + log.debug("Exit with: " + code + " and with reason: " + reason); + data.complete(baos.toString()); } } + } 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..8267abe 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,14 @@ public String getDeployedArtifact() { public void setDeployedArtifact(String deployedArtifact) { this.deployedArtifact = deployedArtifact; } + + private String[] deploymentStatus; + + public String[] getDeploymentStatus() { + return deploymentStatus; + } + + public void setDeploymentStatus(String[] deploymentStatus) { + this.deploymentStatus = deploymentStatus; + } } diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 52720d0..a9651a0 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -59,7 +59,7 @@ public void test() { Namespace testNs = new NamespaceBuilder().withMetadata( new ObjectMetaBuilder().withName(TEST_NS).build()).build(); - if (testNs != null) { + 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. @@ -84,7 +84,7 @@ public void test() { assertThat(updatedWebapp.getStatus(), is(notNullValue())); assertThat(updatedWebapp.getStatus().getDeployedArtifact(), is(notNullValue())); }); - + 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) @@ -94,18 +94,15 @@ public void test() { .withImage("curlimages/curl:7.78.0") .withRestartPolicy("Never") .build()).done(); - await().atMost(5, MINUTES).untilAsserted(() -> { + 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); } }); - - webappClient.inNamespace(TEST_NS).delete(webapp1); - tomcatClient.inNamespace(TEST_NS).delete(tomcat); - client.pods().inNamespace(TEST_NS).withName(curlPod.getMetadata().getName()).delete(); } } From d5b9048f80f778b2ee73afbaf5690a33bd5caf33 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 24 Aug 2021 16:32:06 +0200 Subject: [PATCH 28/33] add Waiting 5 seconds for Tomcat to unpack the downloaded war --- .github/workflows/TomcatIntegrationTest.yml | 57 +++++++++++++------ .../operator/sample/IntegrationTest.java | 13 ++++- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 0669169..bf7e1ba 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -46,6 +46,12 @@ jobs: - name: Run unit tests run: mvn -B test -q --file tomcat/pom.xml + - name: Get webapps + if: ${{ failure() }} + run: | + kubectl get tomcats,webapps -A -o yaml | tee -a debug + kubectl logs + tomcat_local_apply_setup_test: runs-on: ubuntu-latest steps: @@ -63,20 +69,22 @@ jobs: mkdir -p /etc/docker echo -n "{\"exec-opts\": [\"native.cgroupdriver=systemd\"],\"log-driver\": \"json-file\",\"log-opts\": {\"max-size\": \"100m\"},\"storage-driver\": \"overlay2\"}" > /etc/docker/daemon.json cat /etc/docker/daemon.json - sudo service docker status + #sudo service docker status - name: Create Kubernetes KinD Cluster uses: container-tools/kind-action@v1.5.0 + if: ${{ !env.ACT }} with: cluster_name: tomcat-local-apply registry: true - # - name: Create kind cluster - # uses: helm/kind-action@v1.2.0 - # with: - # cluster_name: tomcat-local-apply #${{ job.name }} - # registry: true - # # docker stop tomcat-local-apply-control-plane ; docker rm tomcat-local-apply-control-plane ; sleep 1 + - name: Create kind cluster without registry + uses: helm/kind-action@v1.2.0 + if: ${{ env.ACT }} + with: + cluster_name: tomcat-local-apply #${{ job.name }} + registry: false + # for DIMG in "tomcat-local-apply-control-plane kind-registry tomcat_local_apply_setup_test "; do docker stop $DIMG ; docker rm $DIMG ; done ; sleep 1 - name: Set up Java and Maven uses: actions/setup-java@v2 @@ -99,11 +107,6 @@ jobs: if: ${{ env.ACT }} with: maven-version: 3.8.1 - - - name: check that kube is empty - if: ${{ env.ACT }} - run: kubectl get tomcats,webapps,po - - name: test local registry if: ${{ env.ACT }} @@ -114,20 +117,42 @@ jobs: fi - name: build jib + if: ${{ !env.ACT }} run: | mvn -B install jib:dockerBuild jib:build -Djib.allowInsecureRegistries=true \ -Djib.to.image=$KIND_REGISTRY/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT \ --file tomcat/pom.xml -DskipTests + - name: build jib + if: ${{ env.ACT }} + run: | + mvn -B install jib:dockerBuild \ + -Djib.to.image=sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests + kind load docker-image sample:1.7.1-SNAPSHOT --name=tomcat-local-apply + - name: Apply CRDs run: kubectl apply -f tomcat/k8s/crd.yaml - name: install tomcat operator - run: kubectl apply -f tomcat/k8s/operator.yaml + if: ${{ !env.ACT }} + run: | + sed 's@image\: tomcat-operator@image\: kind-registry\:5000/io.javaoperatorsdk/sample\:1.7.1-SNAPSHOT@g' tomcat/k8s/operator.yaml > tomcat/target/operator.yaml + kubectl apply -f tomcat/target/operator.yaml + + - name: install tomcat operator + if: ${{ env.ACT }} + run: | + sed 's@image\: tomcat-operator@image\: sample\:1.7.1-SNAPSHOT@g' tomcat/k8s/operator.yaml > tomcat/target/operator.yaml + kubectl apply -f tomcat/target/operator.yaml - name: create ns tomcatoperator-sample run: kubectl create ns tomcatoperator-sample + - name: debug local kind + if: ${{ env.ACT }} + run: | + kubectl get pods -n tomcat-operator -l app=tomcat-operator -o yaml | tee -a debug.log + - name: wait for operators ready run: | LOOP=0 &&\ @@ -135,7 +160,7 @@ jobs: echo "waiting for pod" &&\ kubectl logs -n tomcat-operator -l app=tomcat-operator &&\ (( LOOP++ )) &&\ - if [[ $LOOP -gt 10 ]]; then break; fi &&\ + if [[ $LOOP -gt 10 ]]; then exit 1; fi &&\ echo "loop number $LOOP" &&\ sleep 5; \ done @@ -146,7 +171,6 @@ jobs: kubectl -n tomcatoperator-sample apply -f $sample; done - - name: check pod correctly started run: | LOOP=0 &&\ @@ -158,4 +182,5 @@ jobs: echo "loop number $LOOP" &&\ sleep 5; \ done - \ No newline at end of file + + \ No newline at end of file diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index a9651a0..14fb136 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory; import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; @@ -84,7 +85,17 @@ public void test() { assertThat(updatedWebapp.getStatus(), is(notNullValue())); assertThat(updatedWebapp.getStatus().getDeployedArtifact(), is(notNullValue())); }); - + + log.info("Waiting 5 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(5*1000); + } catch (InterruptedException e) { + log.warn(e.getMessage(),e); + } + 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) From efedf39535faec0760892fa2d4f8682acc4b3859 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 24 Aug 2021 17:10:14 +0200 Subject: [PATCH 29/33] testing full --- .github/workflows/TomcatIntegrationTest.yml | 28 ++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index bf7e1ba..bd8f436 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -47,10 +47,10 @@ jobs: run: mvn -B test -q --file tomcat/pom.xml - name: Get webapps - if: ${{ failure() }} + #if: ${{ failure() }} run: | kubectl get tomcats,webapps -A -o yaml | tee -a debug - kubectl logs + kubectl -n tomcat-test -c tomcat logs -l app=test-tomcat1 | grep startup tomcat_local_apply_setup_test: runs-on: ubuntu-latest @@ -182,5 +182,27 @@ jobs: echo "loop number $LOOP" &&\ sleep 5; \ done + #Waiting 5 seconds for Tomcat to unpack the downloaded war + sleep 5; - \ No newline at end of file + - name: Get webapps + #if: ${{ failure() }} + run: | + kubectl get tomcats,webapps -A -o yaml | tee -a debug + kubectl -n tomcat-test -c tomcat logs -l app=test-tomcat1 | grep startup + + - name: check code + run: | + kubectl -n tomcatoperator-sample run sample1 --labels=app=curl --image=curlimages/curl:7.78.0 --restart=Never --timeout=30s --command -- curl -s -v http://test-tomcat1/mysample/; + kubectl -n tomcatoperator-sample run sample2 --labels=app=curl --image=curlimages/curl:7.78.0 --restart=Never --timeout=30s --command -- curl -s -v http://test-tomcat2/othercontext/; + LOOP=0 &&\ + while [[ $(kubectl get pods -n tomcatoperator-sample -l app=curl -o 'jsonpath={..status.phase}') != "Succeeded Succeeded" ]]; do \ + echo "waiting for pod" &&\ + kubectl logs -n tomcatoperator-sample -l app=curl &&\ + (( LOOP++ )) &&\ + if [[ $LOOP -gt 5 ]]; then exit 1; fi &&\ + echo "loop number $LOOP" &&\ + sleep 5; \ + done + if [[ $(kubectl logs -n tomcatoperator-sample sample1 --tail=500 | grep tomcat.gif | wc -l) -ne 1 ]]; then exit 1; fi + if [[ $(kubectl logs -n tomcatoperator-sample sample2 --tail=500 | grep dog.jpeg | wc -l) -ne 1 ]]; then exit 1; fi From a02000139bc60494e091fc9f563046103632fb6e Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 24 Aug 2021 17:20:40 +0200 Subject: [PATCH 30/33] correct callimg the wrong namespace --- .github/workflows/TomcatIntegrationTest.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index bd8f436..2629c53 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -46,12 +46,6 @@ jobs: - name: Run unit tests run: mvn -B test -q --file tomcat/pom.xml - - name: Get webapps - #if: ${{ failure() }} - run: | - kubectl get tomcats,webapps -A -o yaml | tee -a debug - kubectl -n tomcat-test -c tomcat logs -l app=test-tomcat1 | grep startup - tomcat_local_apply_setup_test: runs-on: ubuntu-latest steps: @@ -189,7 +183,7 @@ jobs: #if: ${{ failure() }} run: | kubectl get tomcats,webapps -A -o yaml | tee -a debug - kubectl -n tomcat-test -c tomcat logs -l app=test-tomcat1 | grep startup + kubectl -n tomcatoperator-sample -c tomcat logs -l app=test-tomcat1 | grep startup - name: check code run: | From d49b13e68a43fccb86020659d6aed50487a247c2 Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 24 Aug 2021 17:29:16 +0200 Subject: [PATCH 31/33] improving sleeping time for webapp deployment --- .../io/javaoperatorsdk/operator/sample/IntegrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java index 14fb136..d085545 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java @@ -86,12 +86,12 @@ public void test() { assertThat(updatedWebapp.getStatus().getDeployedArtifact(), is(notNullValue())); }); - log.info("Waiting 5 seconds for Tomcat to unpack the downloaded war"); + 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(5*1000); + Thread.sleep(60*1000); } catch (InterruptedException e) { log.warn(e.getMessage(),e); } From f3c8e778f9626ad5f841ba187ec1fc03ff72cc2a Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Mon, 30 Aug 2021 22:23:13 +0200 Subject: [PATCH 32/33] set use of jib+kind for local run --- .github/workflows/TomcatIntegrationTest.yml | 61 +++------------------ tomcat/pom.xml | 2 +- 2 files changed, 10 insertions(+), 53 deletions(-) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 2629c53..297c23b 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -48,36 +48,18 @@ jobs: tomcat_local_apply_setup_test: runs-on: ubuntu-latest + env: + KIND_CL_NAME: tomcat-local-apply steps: - name: Checkout uses: actions/checkout@v2 - - - name: Set up Helm - uses: azure/setup-helm@v1 - with: - version: v3.4.0 - - - name: test - if: ${{ env.ACT }} - run: | - mkdir -p /etc/docker - echo -n "{\"exec-opts\": [\"native.cgroupdriver=systemd\"],\"log-driver\": \"json-file\",\"log-opts\": {\"max-size\": \"100m\"},\"storage-driver\": \"overlay2\"}" > /etc/docker/daemon.json - cat /etc/docker/daemon.json - #sudo service docker status - name: Create Kubernetes KinD Cluster uses: container-tools/kind-action@v1.5.0 - if: ${{ !env.ACT }} with: cluster_name: tomcat-local-apply - registry: true - - - name: Create kind cluster without registry - uses: helm/kind-action@v1.2.0 - if: ${{ env.ACT }} - with: - cluster_name: tomcat-local-apply #${{ job.name }} - registry: false + registry: false + # for DIMG in "tomcat-local-apply-control-plane kind-registry tomcat_local_apply_setup_test "; do docker stop $DIMG ; docker rm $DIMG ; done ; sleep 1 - name: Set up Java and Maven @@ -101,43 +83,18 @@ jobs: if: ${{ env.ACT }} with: maven-version: 3.8.1 - - - name: test local registry - if: ${{ env.ACT }} - run: | - # Checking env variable - if [[ "$KIND_REGISTRY" != "localhost:5000" ]]; then - echo "Wrong KIND_REGISTRY env variable: $KIND_REGISTRY" - fi - - - name: build jib - if: ${{ !env.ACT }} - run: | - mvn -B install jib:dockerBuild jib:build -Djib.allowInsecureRegistries=true \ - -Djib.to.image=$KIND_REGISTRY/io.javaoperatorsdk/sample:1.7.1-SNAPSHOT \ - --file tomcat/pom.xml -DskipTests - name: build jib - if: ${{ env.ACT }} run: | - mvn -B install jib:dockerBuild \ - -Djib.to.image=sample:1.7.1-SNAPSHOT --file tomcat/pom.xml -DskipTests - kind load docker-image sample:1.7.1-SNAPSHOT --name=tomcat-local-apply + mvn -B package jib:dockerBuild jib:buildTar -Djib-maven-image=tomcat-operator --file tomcat/pom.xml -DskipTests + kind load image-archive tomcat/target/jib-image.tar --name=${{ env.KIND_CL_NAME }} - name: Apply CRDs run: kubectl apply -f tomcat/k8s/crd.yaml - name: install tomcat operator - if: ${{ !env.ACT }} - run: | - sed 's@image\: tomcat-operator@image\: kind-registry\:5000/io.javaoperatorsdk/sample\:1.7.1-SNAPSHOT@g' tomcat/k8s/operator.yaml > tomcat/target/operator.yaml - kubectl apply -f tomcat/target/operator.yaml - - - name: install tomcat operator - if: ${{ env.ACT }} run: | - sed 's@image\: tomcat-operator@image\: sample\:1.7.1-SNAPSHOT@g' tomcat/k8s/operator.yaml > tomcat/target/operator.yaml - kubectl apply -f tomcat/target/operator.yaml + kubectl apply -f tomcat/k8s/operator.yaml - name: create ns tomcatoperator-sample run: kubectl create ns tomcatoperator-sample @@ -171,16 +128,16 @@ jobs: while [[ $(kubectl get pods -n tomcatoperator-sample -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True True True True True True" ]]; do \ echo "waiting for pod" &&\ kubectl logs -n tomcat-operator -l app=tomcat-operator &&\ + kubectl get pods -n tomcatoperator-sample &&\ (( LOOP++ )) &&\ if [[ $LOOP -gt 10 ]]; then exit 1; fi &&\ echo "loop number $LOOP" &&\ - sleep 5; \ + sleep 10; \ done #Waiting 5 seconds for Tomcat to unpack the downloaded war sleep 5; - name: Get webapps - #if: ${{ failure() }} run: | kubectl get tomcats,webapps -A -o yaml | tee -a debug kubectl -n tomcatoperator-sample -c tomcat logs -l app=test-tomcat1 | grep startup diff --git a/tomcat/pom.xml b/tomcat/pom.xml index 781154b..586dca7 100644 --- a/tomcat/pom.xml +++ b/tomcat/pom.xml @@ -19,7 +19,7 @@ 11 11 - 2.7.1 + 3.1.4 From 11d7e0e91f8259acadad966d99e033c65bddaa9c Mon Sep 17 00:00:00 2001 From: Charles Sabourdin Date: Tue, 31 Aug 2021 16:41:49 +0200 Subject: [PATCH 33/33] put test that need a kubernetes cluster (kind) into failsafe:integration-test scope --- .github/workflows/TomcatIntegrationTest.yml | 26 ++++++++++++++++--- tomcat/pom.xml | 11 ++++++++ .../operator/sample/SimpleTest.java | 12 +++++++++ ...{IntegrationTest.java => SimpleWarIT.java} | 9 ++++--- 4 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 tomcat/src/test/java/io/javaoperatorsdk/operator/sample/SimpleTest.java rename tomcat/src/test/java/io/javaoperatorsdk/operator/sample/{IntegrationTest.java => SimpleWarIT.java} (95%) diff --git a/.github/workflows/TomcatIntegrationTest.yml b/.github/workflows/TomcatIntegrationTest.yml index 297c23b..0d1acd9 100644 --- a/.github/workflows/TomcatIntegrationTest.yml +++ b/.github/workflows/TomcatIntegrationTest.yml @@ -6,14 +6,25 @@ on: jobs: tomcat_integration_test: runs-on: ubuntu-latest + env: + KIND_CL_NAME: tomcat-integration steps: - name: Checkout uses: actions/checkout@v2 + - name: clean resident local docker + if: ${{ env.ACT }} + continue-on-error: true + run: | + for DIMG in "$KIND_CL_NAME-control-plane "; do + docker stop $DIMG ; docker rm $DIMG ; + done ; + sleep 1 + - name: Create kind cluster uses: helm/kind-action@v1.2.0 with: - cluster_name: tomcat-integration + cluster_name: ${{ env.KIND_CL_NAME }} - name: Apply CRDs run: kubectl apply -f tomcat/k8s/crd.yaml @@ -44,7 +55,7 @@ jobs: run: mvn --version - name: Run unit tests - run: mvn -B test -q --file tomcat/pom.xml + run: mvn -B failsafe:integration-test --file tomcat/pom.xml tomcat_local_apply_setup_test: runs-on: ubuntu-latest @@ -54,10 +65,19 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: clean resident local docker + if: ${{ env.ACT }} + continue-on-error: true + run: | + for DIMG in "$KIND_CL_NAME-control-plane "; do + docker stop $DIMG ; docker rm $DIMG ; + done ; + sleep 1 + - name: Create Kubernetes KinD Cluster uses: container-tools/kind-action@v1.5.0 with: - cluster_name: tomcat-local-apply + cluster_name: ${{ env.KIND_CL_NAME }} registry: false # for DIMG in "tomcat-local-apply-control-plane kind-registry tomcat_local_apply_setup_test "; do docker stop $DIMG ; docker rm $DIMG ; done ; sleep 1 diff --git a/tomcat/pom.xml b/tomcat/pom.xml index 586dca7..0e2a8c4 100644 --- a/tomcat/pom.xml +++ b/tomcat/pom.xml @@ -20,6 +20,7 @@ 11 11 3.1.4 + @@ -72,6 +73,16 @@ maven-compiler-plugin 3.8.1 + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0-M5 + diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/SimpleTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/SimpleTest.java new file mode 100644 index 0000000..f3ecae0 --- /dev/null +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/SimpleTest.java @@ -0,0 +1,12 @@ +package io.javaoperatorsdk.operator.sample; + +import org.junit.Assert; +import org.junit.Test; +// this is for reference +// on target regular test should be set with io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; +public class SimpleTest { + @Test + public void test() { + Assert.assertSame("foo","foo"); + } +} diff --git a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/SimpleWarIT.java similarity index 95% rename from tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java rename to tomcat/src/test/java/io/javaoperatorsdk/operator/sample/SimpleWarIT.java index d085545..319889b 100644 --- a/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/IntegrationTest.java +++ b/tomcat/src/test/java/io/javaoperatorsdk/operator/sample/SimpleWarIT.java @@ -7,24 +7,25 @@ import io.fabric8.kubernetes.client.extended.run.RunConfigBuilder; import io.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; -import org.junit.AfterClass; +import io.javaoperatorsdk.operator.test.IntegrationTest; import org.junit.Test; +import org.junit.experimental.categories.Category; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.util.concurrent.TimeUnit.MINUTES; -import static java.util.concurrent.TimeUnit.SECONDS; import static org.awaitility.Awaitility.await; 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 { +@Category(IntegrationTest.class) +public class SimpleWarIT { final static String TEST_NS = "tomcat-test"; - final static Logger log = LoggerFactory.getLogger(IntegrationTest.class); + final static Logger log = LoggerFactory.getLogger(SimpleWarIT.class); @Test public void test() {