This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 5cedfed49f9e1f739c7bea314af97158b1152597 Author: Pasquale Congiusti <pasquale.congiu...@gmail.com> AuthorDate: Tue Dec 5 09:39:48 2023 +0100 chore(e2e): synthetic integrations --- e2e/common/synthetic/default.go | 26 +++++++ e2e/common/synthetic/files/deploy.yaml | 50 +++++++++++++ e2e/common/synthetic/synthetic_test.go | 93 +++++++++++++++++++++++++ e2e/support/test_support.go | 8 +++ pkg/controller/integration/monitor_synthetic.go | 19 ++++- script/Makefile | 1 + 6 files changed, 196 insertions(+), 1 deletion(-) diff --git a/e2e/common/synthetic/default.go b/e2e/common/synthetic/default.go new file mode 100644 index 000000000..a7e504e46 --- /dev/null +++ b/e2e/common/synthetic/default.go @@ -0,0 +1,26 @@ +//go:build integration +// +build integration + +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package synthetic + +import "github.com/apache/camel-k/v2/e2e/support" + +var ns = support.GetEnvOrDefault("CAMEL_K_TEST_NAMESPACE", support.GetCIProcessID()) +var operatorID = support.GetEnvOrDefault("CAMEL_K_OPERATOR_ID", support.GetCIProcessID()) diff --git a/e2e/common/synthetic/files/deploy.yaml b/e2e/common/synthetic/files/deploy.yaml new file mode 100644 index 000000000..89921a04a --- /dev/null +++ b/e2e/common/synthetic/files/deploy.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: v1 +data: + my-file.txt: hello +kind: ConfigMap +metadata: + name: my-cm +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: my-camel-sb-svc + name: my-camel-sb-svc +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: my-camel-sb-svc + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app: my-camel-sb-svc + spec: + containers: + - image: docker.io/squakez/my-camel-sb-svc:1.0.0 + imagePullPolicy: IfNotPresent + name: my-camel-sb-svc + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - name: my-cm + mountPath: /tmp/app/data + volumes: + - name: my-cm + configMap: + name: my-cm + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 diff --git a/e2e/common/synthetic/synthetic_test.go b/e2e/common/synthetic/synthetic_test.go new file mode 100644 index 000000000..f9f1532ce --- /dev/null +++ b/e2e/common/synthetic/synthetic_test.go @@ -0,0 +1,93 @@ +//go:build integration +// +build integration + +// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration" + +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package synthetic + +import ( + "testing" + + . "github.com/onsi/gomega" + + . "github.com/apache/camel-k/v2/e2e/support" + v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" + . "github.com/onsi/gomega/gstruct" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" +) + +func TestSyntheticIntegrationFromDeployment(t *testing.T) { + RegisterTestingT(t) + + // Run the external deployment + ExpectExecSucceed(t, Kubectl("apply", "-f", "files/deploy.yaml", "-n", ns)) + Eventually(DeploymentCondition(ns, "my-camel-sb-svc", appsv1.DeploymentProgressing), TestTimeoutShort). + Should(MatchFields(IgnoreExtras, Fields{ + "Status": Equal(corev1.ConditionTrue), + "Reason": Equal("NewReplicaSetAvailable"), + })) + + // Label the deployment --> Verify the Integration is created (cannot still monitor) + ExpectExecSucceed(t, Kubectl("label", "deploy", "my-camel-sb-svc", "camel.apache.org/integration=my-it", "-n", ns)) + Eventually(IntegrationPhase(ns, "my-it"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseCannotMonitor)) + Eventually(IntegrationConditionStatus(ns, "my-it", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + + // Label the deployment template --> Verify the Integration is monitored + ExpectExecSucceed(t, Kubectl("patch", "deployment", "my-camel-sb-svc", "--patch", `{"spec": {"template": {"metadata": {"labels": {"camel.apache.org/integration": "my-it"}}}}}`, "-n", ns)) + Eventually(IntegrationPhase(ns, "my-it"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning)) + Eventually(IntegrationConditionStatus(ns, "my-it", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + one := int32(1) + Eventually(IntegrationStatusReplicas(ns, "my-it"), TestTimeoutShort).Should(Equal(&one)) + + // Delete the deployment --> Verify the Integration is in missing status + ExpectExecSucceed(t, Kubectl("delete", "deploy", "my-camel-sb-svc", "-n", ns)) + Eventually(IntegrationPhase(ns, "my-it"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseImportMissing)) + Eventually(IntegrationConditionStatus(ns, "my-it", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionFalse)) + zero := int32(0) + Eventually(IntegrationStatusReplicas(ns, "my-it"), TestTimeoutShort).Should(Equal(&zero)) + + // Recreate the deployment and label --> Verify the Integration is monitored + ExpectExecSucceed(t, Kubectl("apply", "-f", "files/deploy.yaml", "-n", ns)) + ExpectExecSucceed(t, Kubectl("label", "deploy", "my-camel-sb-svc", "camel.apache.org/integration=my-it", "-n", ns)) + ExpectExecSucceed(t, Kubectl("patch", "deployment", "my-camel-sb-svc", "--patch", `{"spec": {"template": {"metadata": {"labels": {"camel.apache.org/integration": "my-it"}}}}}`, "-n", ns)) + Eventually(IntegrationPhase(ns, "my-it"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning)) + Eventually(IntegrationConditionStatus(ns, "my-it", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + Eventually(IntegrationStatusReplicas(ns, "my-it"), TestTimeoutShort).Should(Equal(&one)) + + // Remove label from the deployment --> Verify the Integration is deleted + ExpectExecSucceed(t, Kubectl("label", "deploy", "my-camel-sb-svc", "camel.apache.org/integration-", "-n", ns)) + Eventually(Integration(ns, "my-it"), TestTimeoutShort).Should(BeNil()) + + // Add label back to the deployment --> Verify the Integration is created + ExpectExecSucceed(t, Kubectl("label", "deploy", "my-camel-sb-svc", "camel.apache.org/integration=my-it", "-n", ns)) + Eventually(IntegrationPhase(ns, "my-it"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning)) + Eventually(IntegrationConditionStatus(ns, "my-it", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + Eventually(IntegrationStatusReplicas(ns, "my-it"), TestTimeoutShort).Should(Equal(&one)) + // Scale the deployment --> verify replicas are correctly set + ExpectExecSucceed(t, Kubectl("scale", "deploy", "my-camel-sb-svc", "--replicas", "2", "-n", ns)) + two := int32(2) + Eventually(IntegrationStatusReplicas(ns, "my-it"), TestTimeoutShort).Should(Equal(&two)) + + // Delete Integration and deployments --> verify no Integration exists any longer + Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed()) + ExpectExecSucceed(t, Kubectl("delete", "deploy", "my-camel-sb-svc", "-n", ns)) + Eventually(Integration(ns, "my-it"), TestTimeoutShort).Should(BeNil()) +} diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go index 4b67c6dc6..2743b050c 100644 --- a/e2e/support/test_support.go +++ b/e2e/support/test_support.go @@ -481,6 +481,14 @@ func MakeWithContext(ctx context.Context, rule string, args ...string) *exec.Cmd return exec.Command("make", args...) } +func Kubectl(args ...string) *exec.Cmd { + return KubectlWithContext(TestContext, args...) +} + +func KubectlWithContext(ctx context.Context, args ...string) *exec.Cmd { + return exec.Command("kubectl", args...) +} + // ============================================================================= // Curried utility functions for testing // ============================================================================= diff --git a/pkg/controller/integration/monitor_synthetic.go b/pkg/controller/integration/monitor_synthetic.go index a1aa86a43..cee622163 100644 --- a/pkg/controller/integration/monitor_synthetic.go +++ b/pkg/controller/integration/monitor_synthetic.go @@ -19,11 +19,13 @@ package integration import ( "context" + "fmt" corev1 "k8s.io/api/core/v1" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" "github.com/apache/camel-k/v2/pkg/trait" + k8serrors "k8s.io/apimachinery/pkg/api/errors" ) // NewMonitorSyntheticAction is an action used to monitor synthetic Integrations. @@ -42,7 +44,22 @@ func (action *monitorSyntheticAction) Name() string { func (action *monitorSyntheticAction) Handle(ctx context.Context, integration *v1.Integration) (*v1.Integration, error) { environment, err := trait.NewSyntheticEnvironment(ctx, action.client, integration, nil) if err != nil { - // report the error + // Importing application no longer available + if k8serrors.IsNotFound(err) { + // It could be a normal condition, don't report as an error + integration.Status.Phase = v1.IntegrationPhaseImportMissing + message := fmt.Sprintf( + "import %s %s no longer available", + integration.Annotations[v1.IntegrationImportedKindLabel], + integration.Annotations[v1.IntegrationImportedNameLabel], + ) + integration.SetReadyConditionError(message) + zero := int32(0) + integration.Status.Phase = v1.IntegrationPhaseImportMissing + integration.Status.Replicas = &zero + return integration, nil + } + // other reasons, likely some error to report integration.Status.Phase = v1.IntegrationPhaseError integration.SetReadyCondition(corev1.ConditionFalse, v1.IntegrationConditionImportingKindAvailableReason, err.Error()) return integration, err diff --git a/script/Makefile b/script/Makefile index be5391bd4..282357f8b 100644 --- a/script/Makefile +++ b/script/Makefile @@ -262,6 +262,7 @@ test-common: do-build go test -timeout 30m -v ./e2e/common/misc -tags=integration $(TEST_INTEGRATION_COMMON_LANG_RUN) $(GOTESTFMT) || FAILED=1; \ go test -timeout 60m -v ./e2e/common/traits -tags=integration $(TEST_INTEGRATION_COMMON_LANG_RUN) $(GOTESTFMT) || FAILED=1; \ go test -timeout 20m -v ./e2e/common/runtimes -tags=integration $(TEST_INTEGRATION_COMMON_LANG_RUN) $(GOTESTFMT) || FAILED=1; \ + go test -timeout 10m -v ./e2e/common/synthetic -tags=integration $(TEST_INTEGRATION_COMMON_LANG_RUN) $(GOTESTFMT) || FAILED=1; \ go test -timeout 10m -v ./e2e/common/support/teardown_test.go -tags=integration $(TEST_INTEGRATION_COMMON_LANG_RUN) $(GOTESTFMT) || FAILED=1; \ exit $${FAILED}