Repository: apache/camel-k
Pull request #3870 (2022-12-02 02:36:43)

fix(service): Create k8s service when knative-service trait is disabled (1.10.x)
https://github.com/apache/camel-k/issues/3849

When knative-service and k8s service traits are enabled, the priority is to use knative-service in knative profile

(cherry picked from commit 07563546a5d04c53dab122e90bc768e08514defe)

**Release Note**
```release-note
NONE
```


claudio4j: @christophd for review

Patch:
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index d4211fb39..b10933019 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -41,12 +41,6 @@ func newServiceTrait() Trait {
 	}
 }
 
-// IsAllowedInProfile overrides default.
-func (t *serviceTrait) IsAllowedInProfile(profile v1.TraitProfile) bool {
-	return profile.Equal(v1.TraitProfileKubernetes) ||
-		profile.Equal(v1.TraitProfileOpenShift)
-}
-
 func (t *serviceTrait) Configure(e *Environment) (bool, error) {
 	if e.Integration == nil || !pointer.BoolDeref(t.Enabled, true) {
 		if e.Integration != nil {
@@ -61,6 +55,15 @@ func (t *serviceTrait) Configure(e *Environment) (bool, error) {
 		return false, nil
 	}
 
+	// in case the knative-service and service trait are enabled, the knative-service has priority
+	// then this service is disabled
+	if e.GetTrait(knativeServiceTraitID) != nil {
+		knativeServiceTrait, _ := e.GetTrait(knativeServiceTraitID).(*knativeServiceTrait)
+		if pointer.BoolDeref(knativeServiceTrait.Enabled, true) {
+			return false, nil
+		}
+	}
+
 	if !e.IntegrationInRunningPhases() {
 		return false, nil
 	}


Test patch:
diff --git a/e2e/global/knative/files/http_out.groovy b/e2e/global/knative/files/http_out.groovy
new file mode 100644
index 000000000..40f75a639
--- /dev/null
+++ b/e2e/global/knative/files/http_out.groovy
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+from("rest:get:hello/")
+      .transform().simple("Hello");
\ No newline at end of file
diff --git a/e2e/global/knative/knative_test.go b/e2e/global/knative/knative_test.go
index 3dd55e660..1a9017b2c 100644
--- a/e2e/global/knative/knative_test.go
+++ b/e2e/global/knative/knative_test.go
@@ -107,6 +107,21 @@ func TestKnative(t *testing.T) {
 
 			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
 		})
+
+		t.Run("Knative-service disabled", func(t *testing.T) {
+			Expect(KamelRunWithID(operatorID, ns, "files/http_out.groovy", "-t", "knative-service.enabled=false").Execute()).To(Succeed())
+			Eventually(IntegrationPodPhase(ns, "http-out"), TestTimeoutLong).Should(Equal(v1.PodRunning))
+			Eventually(Service(ns, "http-out"), TestTimeoutShort).ShouldNot(BeNil())
+			Consistently(KnativeService(ns, "http-out"), TestTimeoutShort).Should(BeNil())
+			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+		})
+
+		t.Run("Knative-service priority", func(t *testing.T) {
+			Expect(KamelRunWithID(operatorID, ns, "files/http_out.groovy").Execute()).To(Succeed())
+			Eventually(IntegrationPodPhase(ns, "http-out"), TestTimeoutLong).Should(Equal(v1.PodRunning))
+			Eventually(KnativeService(ns, "http-out"), TestTimeoutShort).ShouldNot(BeNil())
+			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+		})
 	})
 }
 
diff --git a/pkg/trait/service_test.go b/pkg/trait/service_test.go
index 944c7cea2..081afec92 100644
--- a/pkg/trait/service_test.go
+++ b/pkg/trait/service_test.go
@@ -392,3 +392,209 @@ func TestServiceWithNodePort(t *testing.T) {
 
 	assert.Equal(t, corev1.ServiceTypeNodePort, s.Spec.Type)
 }
+
+// When service and knative-service are enabled at the integration scope in knative profile
+// knative-service has the priority and the k8s service is not run.
+func TestServiceWithKnativeServiceEnabled(t *testing.T) {
+	catalog, err := camel.DefaultCatalog()
+	assert.Nil(t, err)
+
+	traitCatalog := NewCatalog(nil)
+
+	compressedRoute, err := gzip.CompressBase64([]byte(`from("netty-http:test").log("hello")`))
+	assert.NoError(t, err)
+
+	environment := Environment{
+		CamelCatalog: catalog,
+		Catalog:      traitCatalog,
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      ServiceTestName,
+				Namespace: "ns",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+			Spec: v1.IntegrationSpec{
+				Profile: v1.TraitProfileKnative,
+				Sources: []v1.SourceSpec{
+					{
+						DataSpec: v1.DataSpec{
+							Name:        "routes.js",
+							Content:     string(compressedRoute),
+							Compression: true,
+						},
+						Language: v1.LanguageJavaScript,
+					},
+				},
+				Traits: v1.Traits{
+					Service: &traitv1.ServiceTrait{
+						Trait: traitv1.Trait{
+							Enabled: pointer.Bool(true),
+						},
+						Auto: pointer.Bool(false),
+					},
+					KnativeService: &traitv1.KnativeServiceTrait{
+						Trait: traitv1.Trait{
+							Enabled: pointer.Bool(true),
+						},
+					},
+				},
+			},
+		},
+		Platform: &v1.IntegrationPlatform{
+			Spec: v1.IntegrationPlatformSpec{
+				Cluster: v1.IntegrationPlatformClusterOpenShift,
+				Build: v1.IntegrationPlatformBuildSpec{
+					PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I,
+					Registry:        v1.RegistrySpec{Address: "registry"},
+					RuntimeVersion:  catalog.Runtime.Version,
+				},
+			},
+			Status: v1.IntegrationPlatformStatus{
+				Phase: v1.IntegrationPlatformPhaseReady,
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+	}
+	environment.Platform.ResyncStatusFullConfig()
+
+	err = traitCatalog.apply(&environment)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.Nil(t, environment.GetTrait(serviceTraitID))
+	assert.NotNil(t, environment.GetTrait(knativeServiceTraitID))
+}
+
+func TestServicesWithKnativeProfile(t *testing.T) {
+	catalog, err := camel.DefaultCatalog()
+	assert.Nil(t, err)
+
+	traitCatalog := NewCatalog(nil)
+
+	compressedRoute, err := gzip.CompressBase64([]byte(`from("netty-http:test").log("hello")`))
+	assert.NoError(t, err)
+
+	environment := Environment{
+		CamelCatalog: catalog,
+		Catalog:      traitCatalog,
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      ServiceTestName,
+				Namespace: "ns",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+			Spec: v1.IntegrationSpec{
+				Profile: v1.TraitProfileKnative,
+				Sources: []v1.SourceSpec{
+					{
+						DataSpec: v1.DataSpec{
+							Name:        "routes.js",
+							Content:     string(compressedRoute),
+							Compression: true,
+						},
+						Language: v1.LanguageJavaScript,
+					},
+				},
+			},
+		},
+		Platform: &v1.IntegrationPlatform{
+			Spec: v1.IntegrationPlatformSpec{
+				Cluster: v1.IntegrationPlatformClusterOpenShift,
+				Build: v1.IntegrationPlatformBuildSpec{
+					PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I,
+					Registry:        v1.RegistrySpec{Address: "registry"},
+					RuntimeVersion:  catalog.Runtime.Version,
+				},
+			},
+			Status: v1.IntegrationPlatformStatus{
+				Phase: v1.IntegrationPlatformPhaseReady,
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+	}
+	environment.Platform.ResyncStatusFullConfig()
+
+	err = traitCatalog.apply(&environment)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.Nil(t, environment.GetTrait(serviceTraitID))
+	assert.NotNil(t, environment.GetTrait(knativeServiceTraitID))
+}
+
+// When the knative-service is disabled at the IntegrationPlatform, the k8s service is enabled.
+func TestServiceWithKnativeServiceDisabledInIntegrationPlatform(t *testing.T) {
+	catalog, err := camel.DefaultCatalog()
+	assert.Nil(t, err)
+
+	traitCatalog := NewCatalog(nil)
+
+	compressedRoute, err := gzip.CompressBase64([]byte(`from("netty-http:test").log("hello")`))
+	assert.NoError(t, err)
+
+	environment := Environment{
+		CamelCatalog: catalog,
+		Catalog:      traitCatalog,
+		Integration: &v1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      ServiceTestName,
+				Namespace: "ns",
+			},
+			Status: v1.IntegrationStatus{
+				Phase: v1.IntegrationPhaseDeploying,
+			},
+			Spec: v1.IntegrationSpec{
+				Profile: v1.TraitProfileKnative,
+				Sources: []v1.SourceSpec{
+					{
+						DataSpec: v1.DataSpec{
+							Name:        "routes.js",
+							Content:     string(compressedRoute),
+							Compression: true,
+						},
+						Language: v1.LanguageJavaScript,
+					},
+				},
+			},
+		},
+		Platform: &v1.IntegrationPlatform{
+			Spec: v1.IntegrationPlatformSpec{
+				Cluster: v1.IntegrationPlatformClusterOpenShift,
+				Build: v1.IntegrationPlatformBuildSpec{
+					PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I,
+					Registry:        v1.RegistrySpec{Address: "registry"},
+					RuntimeVersion:  catalog.Runtime.Version,
+				},
+				Traits: v1.Traits{
+					KnativeService: &traitv1.KnativeServiceTrait{
+						Trait: traitv1.Trait{
+							Enabled: pointer.Bool(false),
+						},
+					},
+				},
+			},
+			Status: v1.IntegrationPlatformStatus{
+				Phase: v1.IntegrationPlatformPhaseReady,
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+	}
+	environment.Platform.ResyncStatusFullConfig()
+
+	err = traitCatalog.apply(&environment)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.NotNil(t, environment.GetTrait(serviceTraitID))
+	assert.Nil(t, environment.GetTrait(knativeServiceTraitID))
+}