Repository: apache/camel-k
Pull request #3537 (2022-08-11 07:06:20)

Olm image test 1.8.x
- stabilize upgrade test (Patch the Subscription to avoid conflicts with concurrent updates performed by OLM)
- test operator image installed by the OLM


Patch:
diff --git a/docs/modules/traits/pages/service.adoc b/docs/modules/traits/pages/service.adoc
index 7e474ad91..b79dcc728 100755
--- a/docs/modules/traits/pages/service.adoc
+++ b/docs/modules/traits/pages/service.adoc
@@ -34,7 +34,7 @@ The following configuration options are available:
 
 | service.node-port
 | bool
-| Enable Service to be exposed as NodePort
+| Enable Service to be exposed as NodePort (default `false`).
 
 |===
 
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index 9b6b6c5f0..9f362bb94 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -36,7 +36,7 @@ type serviceTrait struct {
 	BaseTrait `property:",squash"`
 	// To automatically detect from the code if a Service needs to be created.
 	Auto *bool `property:"auto" json:"auto,omitempty"`
-	// Enable Service to be exposed as NodePort
+	// Enable Service to be exposed as NodePort (default `false`).
 	NodePort *bool `property:"node-port" json:"nodePort,omitempty"`
 }
 
@@ -105,7 +105,7 @@ func (t *serviceTrait) Apply(e *Environment) error {
 	if svc == nil {
 		svc = getServiceFor(e)
 
-		if IsNilOrTrue(t.NodePort) {
+		if IsTrue(t.NodePort) {
 			svc.Spec.Type = corev1.ServiceTypeNodePort
 		}
 	}
diff --git a/pkg/util/defaults/defaults_support.go b/pkg/util/defaults/defaults_support.go
index 3eab69a58..71b890bb9 100644
--- a/pkg/util/defaults/defaults_support.go
+++ b/pkg/util/defaults/defaults_support.go
@@ -18,6 +18,7 @@ limitations under the License.
 package defaults
 
 import (
+	"fmt"
 	"os"
 	"strconv"
 
@@ -28,6 +29,10 @@ func BaseImage() string {
 	return envOrDefault(baseImage, "KAMEL_BASE_IMAGE", "RELATED_IMAGE_BASE")
 }
 
+func OperatorImage() string {
+	return envOrDefault(fmt.Sprintf("%s:%s", ImageName, Version), "KAMEL_OPERATOR_IMAGE", "KAMEL_K_TEST_OPERATOR_CURRENT_IMAGE")
+}
+
 func InstallDefaultKamelets() bool {
 	return boolEnvOrDefault(installDefaultKamelets, "KAMEL_INSTALL_DEFAULT_KAMELETS")
 }
diff --git a/resources/traits.yaml b/resources/traits.yaml
index 09dfeccf4..645d8a4ca 100755
--- a/resources/traits.yaml
+++ b/resources/traits.yaml
@@ -1143,7 +1143,7 @@ traits:
     description: To automatically detect from the code if a Service needs to be created.
   - name: node-port
     type: bool
-    description: Enable Service to be exposed as NodePort
+    description: Enable Service to be exposed as NodePort (default `false`).
 - name: 3scale
   platform: false
   profiles:


Test patch:
diff --git a/e2e/common/traits/files/Java.java b/e2e/common/traits/files/Java.java
index 66fef5fe8..30b1f459e 100644
--- a/e2e/common/traits/files/Java.java
+++ b/e2e/common/traits/files/Java.java
@@ -18,11 +18,11 @@
 import org.apache.camel.builder.RouteBuilder;
 
 public class Java extends RouteBuilder {
-  @Override
-  public void configure() throws Exception {
-	  from("timer:tick")
-	  .setHeader("m").constant("string!")
-	  .setBody().simple("Magic${header.m}")
-      .log("${body}");
-  }
+    @Override
+    public void configure() throws Exception {
+        from("timer:tick")
+            .setHeader("m").constant("string!")
+            .setBody().simple("Magic${header.m}")
+            .log("${body}");
+    }
 }
diff --git a/e2e/common/traits/files/Master.java b/e2e/common/traits/files/Master.java
index 84fdeeb05..6f3a8d1ed 100644
--- a/e2e/common/traits/files/Master.java
+++ b/e2e/common/traits/files/Master.java
@@ -18,11 +18,11 @@
 import org.apache.camel.builder.RouteBuilder;
 
 public class Master extends RouteBuilder {
-  @Override
-  public void configure() throws Exception {
-	  from("master:lock:timer:tick")
-	  .setHeader("m").constant("string!")
-	  .setBody().simple("Magic${header.m}")
-      .log("${body}");
-  }
+    @Override
+    public void configure() throws Exception {
+        from("master:lock:timer:tick")
+            .setHeader("m").constant("string!")
+            .setBody().simple("Magic${header.m}")
+            .log("${body}");
+    }
 }
diff --git a/e2e/common/traits/files/PlatformHttpServer.java b/e2e/common/traits/files/PlatformHttpServer.java
index 9e5251481..31d8d19f3 100644
--- a/e2e/common/traits/files/PlatformHttpServer.java
+++ b/e2e/common/traits/files/PlatformHttpServer.java
@@ -18,8 +18,9 @@
 import org.apache.camel.builder.RouteBuilder;
 
 public class PlatformHttpServer extends RouteBuilder {
-  @Override
-  public void configure() throws Exception {
-    from("platform-http:/hello?httpMethodRestrict=GET").setBody(simple("Hello ${header.name}"));
-  }
-}
\ No newline at end of file
+    @Override
+    public void configure() throws Exception {
+        from("platform-http:/hello?httpMethodRestrict=GET")
+            .setBody(simple("Hello ${header.name}"));
+    }
+}
diff --git a/e2e/common/traits/service_test.go b/e2e/common/traits/service_test.go
new file mode 100644
index 000000000..0ee3569c6
--- /dev/null
+++ b/e2e/common/traits/service_test.go
@@ -0,0 +1,62 @@
+//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 traits
+
+import (
+	"testing"
+
+	. "github.com/onsi/gomega"
+
+	corev1 "k8s.io/api/core/v1"
+
+	. "github.com/apache/camel-k/e2e/support"
+)
+
+func TestServiceTrait(t *testing.T) {
+	WithNewTestNamespace(t, func(ns string) {
+		Expect(Kamel("install", "-n", ns).Execute()).To(Succeed())
+
+		t.Run("Default service (ClusterIP)", func(t *testing.T) {
+			// Service trait is enabled by default
+			Expect(Kamel("run", "-n", ns, "files/PlatformHttpServer.java").Execute()).To(Succeed())
+			Eventually(IntegrationPodPhase(ns, "platform-http-server"), TestTimeoutMedium).Should(Equal(corev1.PodRunning))
+			service := Service(ns, "platform-http-server")
+			Eventually(service, TestTimeoutShort).ShouldNot(BeNil())
+			Expect(service().Spec.Type).Should(Equal(corev1.ServiceTypeClusterIP))
+
+			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+		})
+
+		t.Run("NodePort service", func(t *testing.T) {
+			Expect(Kamel("run", "-n", ns, "files/PlatformHttpServer.java",
+				"-t", "service.enabled=true",
+				"-t", "service.node-port=true").Execute()).To(Succeed())
+			Eventually(IntegrationPodPhase(ns, "platform-http-server"), TestTimeoutMedium).Should(Equal(corev1.PodRunning))
+			service := Service(ns, "platform-http-server")
+			Eventually(service, TestTimeoutShort).ShouldNot(BeNil())
+			Expect(service().Spec.Type).Should(Equal(corev1.ServiceTypeNodePort))
+
+			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+		})
+	})
+}
diff --git a/e2e/upgrade/olm_upgrade_test.go b/e2e/upgrade/olm_upgrade_test.go
index 4404c388f..cf84b4122 100644
--- a/e2e/upgrade/olm_upgrade_test.go
+++ b/e2e/upgrade/olm_upgrade_test.go
@@ -24,7 +24,9 @@ package common
 
 import (
 	"fmt"
+	"k8s.io/apimachinery/pkg/types"
 	"os"
+	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
 	"testing"
 	"time"
 
@@ -120,13 +122,14 @@ func TestOLMAutomaticUpgrade(t *testing.T) {
 
 			if crossChannelUpgrade {
 				t.Log("Updating Camel-K subscription OLM update channel.")
-				s := ckSubscription(ns)()
-				r, err := ctrlutil.CreateOrUpdate(TestContext, TestClient(), s, func() error {
-					s.Spec.Channel = newUpdateChannel
-					return nil
-				})
-				Expect(err).To(BeNil())
-				Expect(r).To(Equal(ctrlutil.OperationResultUpdated))
+				subscription := ckSubscription(ns)()
+				Expect(subscription).NotTo(BeNil())
+
+				// Patch the Subscription to avoid conflicts with concurrent updates performed by OLM
+				patch := fmt.Sprintf("{\"spec\":{\"channel\":%q}}", newUpdateChannel)
+				Expect(TestClient().Patch(TestContext, subscription, ctrl.RawPatch(types.MergePatchType, []byte(patch)))).To(Succeed())
+				// Assert the response back from the API server
+				Expect(subscription.Spec.Channel).To(Equal(newUpdateChannel))
 			}
 			// Check the previous CSV is being replaced
 			Eventually(clusterServiceVersionPhase(func(csv olm.ClusterServiceVersion) bool {
@@ -149,6 +152,7 @@ func TestOLMAutomaticUpgrade(t *testing.T) {
 			Expect(prevCSVVersion.Version.String()).NotTo(Equal(newCSVVersion.Version.String()))
 
 			Eventually(OperatorPodPhase(ns), TestTimeoutMedium).Should(Equal(corev1.PodRunning))
+			Eventually(OperatorImage(ns), TestTimeoutShort).Should(Equal(defaults.OperatorImage()))
 
 			// Check the IntegrationPlatform has been reconciled
 			Eventually(PlatformVersion(ns)).Should(ContainSubstring(newIPVersionPrefix))
diff --git a/pkg/trait/service_test.go b/pkg/trait/service_test.go
index aea727905..f97d6bc2c 100644
--- a/pkg/trait/service_test.go
+++ b/pkg/trait/service_test.go
@@ -125,6 +125,8 @@ func TestServiceWithDefaults(t *testing.T) {
 	assert.Len(t, d.Spec.Template.Spec.Containers[0].Ports, 1)
 	assert.Equal(t, int32(8080), d.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort)
 	assert.Equal(t, "http", d.Spec.Template.Spec.Containers[0].Ports[0].Name)
+
+	assert.Empty(t, s.Spec.Type) // empty means ClusterIP
 }
 
 func TestService(t *testing.T) {
@@ -329,9 +331,9 @@ func TestServiceWithNodePort(t *testing.T) {
 				},
 				Traits: map[string]v1.TraitSpec{
 					"service": test.TraitSpecFromMap(t, map[string]interface{}{
-						"enabled":   true,
-						"auto":      false,
-						"node-port": true,
+						"enabled":  true,
+						"auto":     false,
+						"nodePort": true,
 					}),
 				},
 			},