Repository: apache/camel-k
Pull request #3541 (2022-08-11 12:37:14)

Backport of #3263
<!-- Description -->




<!--
Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". 

You can (optionally) mark this PR with labels "kind/bug" or "kind/feature" to make sure
the text is added to the right section of the release notes. 
-->

**Release Note**
```release-note
NONE
```



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/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/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,
 					}),
 				},
 			},