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
The following commit(s) were added to refs/heads/main by this push:
new 0a22bed84 feat(trait): enable health trait by default
0a22bed84 is described below
commit 0a22bed84ccff83042f70e45e530c7057b1d9671
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Fri Apr 26 16:02:09 2024 +0200
feat(trait): enable health trait by default
Closes #5024
---
e2e/common/cli/get_test.go | 4 +-
e2e/common/misc/files/cron-fallback.yaml | 5 ++
e2e/common/misc/files/cron-quartz.yaml | 5 ++
e2e/common/misc/files/cron-timer.yaml | 5 ++
e2e/common/misc/files/cron-trait-yaml.yaml | 5 ++
e2e/common/misc/files/cron-yaml.yaml | 5 ++
e2e/common/misc/integration_fail_test.go | 15 ++--
e2e/common/traits/health_test.go | 32 +++++----
e2e/common/traits/master_test.go | 28 ++++----
pkg/apis/camel/v1/trait/health.go | 2 +-
pkg/cmd/debug.go | 7 +-
pkg/cmd/debug_test.go | 78 +++++++++++++++++++++
pkg/trait/health.go | 10 ++-
pkg/trait/health_test.go | 106 +++++++++++++++++++++++++++++
pkg/trait/jvm.go | 6 +-
pkg/trait/trait_test.go | 2 +-
16 files changed, 269 insertions(+), 46 deletions(-)
diff --git a/e2e/common/cli/get_test.go b/e2e/common/cli/get_test.go
index c9b0ee351..88dbb71eb 100644
--- a/e2e/common/cli/get_test.go
+++ b/e2e/common/cli/get_test.go
@@ -46,7 +46,7 @@ func TestKamelCLIGet(t *testing.T) {
kitName := IntegrationKit(t, ctx, ns, "yaml")()
kitNamespace := IntegrationKitNamespace(t, ctx, ns,
"yaml")()
regex :=
fmt.Sprintf("^NAME\tPHASE\tKIT\n\\s*yaml\tRunning\t(%s/%s|%s)", kitNamespace,
kitName, kitName)
- g.Expect(GetOutputString(Kamel(t, ctx, "get", "-n",
ns))).To(MatchRegexp(regex))
+ g.Eventually(GetOutputString(Kamel(t, ctx, "get", "-n",
ns))).Should(MatchRegexp(regex))
g.Expect(Kamel(t, ctx, "delete", "--all", "-n",
ns).Execute()).To(Succeed())
})
@@ -65,7 +65,7 @@ func TestKamelCLIGet(t *testing.T) {
kitNamespace2 := IntegrationKitNamespace(t, ctx, ns,
"yaml")()
regex :=
fmt.Sprintf("^NAME\tPHASE\tKIT\n\\s*java\tRunning\t"+
"(%s/%s|%s)\n\\s*yaml\tRunning\t(%s/%s|%s)\n",
kitNamespace1, kitName1, kitName1, kitNamespace2, kitName2, kitName2)
- g.Expect(GetOutputString(Kamel(t, ctx, "get", "-n",
ns))).To(MatchRegexp(regex))
+ g.Eventually(GetOutputString(Kamel(t, ctx, "get", "-n",
ns))).Should(MatchRegexp(regex))
g.Expect(Kamel(t, ctx, "delete", "--all", "-n",
ns).Execute()).To(Succeed())
})
diff --git a/e2e/common/misc/files/cron-fallback.yaml
b/e2e/common/misc/files/cron-fallback.yaml
index f20d0f21a..6ca1af958 100644
--- a/e2e/common/misc/files/cron-fallback.yaml
+++ b/e2e/common/misc/files/cron-fallback.yaml
@@ -25,6 +25,11 @@
constant: "string!"
- setBody:
simple: "Magic${header.m}"
+ # Simulate a job workload
+ - delay:
+ expression:
+ constant: 20000
+ asyncDelayed: false
- to:
uri: "log:info"
parameters:
diff --git a/e2e/common/misc/files/cron-quartz.yaml
b/e2e/common/misc/files/cron-quartz.yaml
index 074367a3c..c80da789c 100644
--- a/e2e/common/misc/files/cron-quartz.yaml
+++ b/e2e/common/misc/files/cron-quartz.yaml
@@ -27,6 +27,11 @@
constant: "string!"
- setBody:
simple: "Magic${header.m}"
+ # Simulate a job workload
+ - delay:
+ expression:
+ constant: 20000
+ asyncDelayed: false
- to:
uri: "log:info"
parameters:
diff --git a/e2e/common/misc/files/cron-timer.yaml
b/e2e/common/misc/files/cron-timer.yaml
index 4acd7a8c2..d486ef7fe 100644
--- a/e2e/common/misc/files/cron-timer.yaml
+++ b/e2e/common/misc/files/cron-timer.yaml
@@ -27,6 +27,11 @@
constant: "string!"
- setBody:
simple: "Magic${header.m}"
+ # Simulate a job workload
+ - delay:
+ expression:
+ constant: 20000
+ asyncDelayed: false
- to:
uri: "log:info"
parameters:
diff --git a/e2e/common/misc/files/cron-trait-yaml.yaml
b/e2e/common/misc/files/cron-trait-yaml.yaml
index 464579ee7..1016d624f 100644
--- a/e2e/common/misc/files/cron-trait-yaml.yaml
+++ b/e2e/common/misc/files/cron-trait-yaml.yaml
@@ -26,6 +26,11 @@
constant: "string!"
- setBody:
simple: "Magic${header.m}"
+ # Simulate a job workload
+ - delay:
+ expression:
+ constant: 20000
+ asyncDelayed: false
- to:
uri: "log:info"
parameters:
diff --git a/e2e/common/misc/files/cron-yaml.yaml
b/e2e/common/misc/files/cron-yaml.yaml
index 9b6735053..e238e2e02 100644
--- a/e2e/common/misc/files/cron-yaml.yaml
+++ b/e2e/common/misc/files/cron-yaml.yaml
@@ -25,6 +25,11 @@
constant: "string!"
- setBody:
simple: "Magic${header.m}"
+ # Simulate a job workload
+ - delay:
+ expression:
+ constant: 20000
+ asyncDelayed: false
- to:
uri: "log:info"
parameters:
diff --git a/e2e/common/misc/integration_fail_test.go
b/e2e/common/misc/integration_fail_test.go
index cdd731be4..1236faafa 100644
--- a/e2e/common/misc/integration_fail_test.go
+++ b/e2e/common/misc/integration_fail_test.go
@@ -48,7 +48,7 @@ func TestBadRouteIntegration(t *testing.T) {
t.Run("run bad java route", func(t *testing.T) {
name := RandomizedSuffixName("bad-route")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/BadRoute.java", "--name", name).Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/BadRoute.java", "--name", name, "-t",
"health.enabled=false").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutShort).Should(Equal(v1.IntegrationPhaseError))
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady), TestTimeoutShort).
@@ -73,7 +73,7 @@ func TestBadRouteIntegration(t *testing.T) {
t.Run("run missing dependency java route", func(t *testing.T) {
name := RandomizedSuffixName("java-route")
g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name,
- "-d",
"mvn:com.example:nonexistent:1.0").Execute()).To(Succeed())
+ "-d", "mvn:com.example:nonexistent:1.0", "-t",
"health.enabled=false").Execute()).To(Succeed())
// Integration in error
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(v1.IntegrationPhaseError))
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionKitAvailable),
TestTimeoutShort).Should(Equal(corev1.ConditionFalse))
@@ -106,7 +106,7 @@ func TestBadRouteIntegration(t *testing.T) {
t.Run("run invalid dependency java route", func(t *testing.T) {
name := RandomizedSuffixName("invalid-dependency")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name, "-d",
"camel:non-existent").Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name, "-d", "camel:non-existent", "-t",
"health.enabled=false").Execute()).To(Succeed())
// Integration in error with Initialization Failed
condition
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(v1.IntegrationPhaseError))
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady), TestTimeoutShort).
@@ -135,7 +135,7 @@ func TestBadRouteIntegration(t *testing.T) {
t.Run("run unresolvable component java route", func(t
*testing.T) {
name := RandomizedSuffixName("unresolvable-route")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Unresolvable.java", "--name", name).Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Unresolvable.java", "--name", name, "-t",
"health.enabled=false").Execute()).To(Succeed())
// Integration in error with Initialization Failed
condition
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutShort).Should(Equal(v1.IntegrationPhaseError))
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady), TestTimeoutShort).
@@ -148,7 +148,7 @@ func TestBadRouteIntegration(t *testing.T) {
g.Consistently(IntegrationKit(t, ctx, ns, name),
10*time.Second).Should(BeEmpty())
// Fixing the route should reconcile the Integration in
Initialization Failed condition to Running
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name).Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name, "-t",
"health.enabled=false").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady), TestTimeoutShort).
Should(Equal(corev1.ConditionTrue))
@@ -164,7 +164,8 @@ func TestBadRouteIntegration(t *testing.T) {
t.Run("run invalid java route", func(t *testing.T) {
name := RandomizedSuffixName("invalid-java-route")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/InvalidJava.java", "--name", name).Execute()).To(Succeed())
+ // Skip the health check so we can quickly read from log
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/InvalidJava.java", "--name", name, "-t",
"health.enabled=false").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutShort).Should(Equal(v1.IntegrationPhaseError))
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady), TestTimeoutShort).
@@ -177,7 +178,7 @@ func TestBadRouteIntegration(t *testing.T) {
g.Eventually(KitPhase(t, ctx, integrationKitNamespace,
kitName), TestTimeoutShort).Should(Equal(v1.IntegrationKitPhaseReady))
// Fixing the route should reconcile the Integration in
Initialization Failed condition to Running
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name).Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name, "-t",
"health.enabled=false").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady), TestTimeoutShort).
Should(Equal(corev1.ConditionTrue))
diff --git a/e2e/common/traits/health_test.go b/e2e/common/traits/health_test.go
index 31221cff7..7a26bb9f2 100644
--- a/e2e/common/traits/health_test.go
+++ b/e2e/common/traits/health_test.go
@@ -37,7 +37,6 @@ import (
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
. "github.com/apache/camel-k/v2/e2e/support"
v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -54,9 +53,23 @@ func TestHealthTrait(t *testing.T) {
g.Eventually(SelectedPlatformPhase(t, ctx, ns, operatorID),
TestTimeoutMedium).Should(Equal(v1.IntegrationPlatformPhaseReady))
+ t.Run("Disabled health trait", func(t *testing.T) {
+ name := RandomizedSuffixName("java")
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "-t", "health.enabled=false", "--name",
name).Execute()).To(Succeed())
+
+ g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+ g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
+ g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady), TestTimeoutShort).
+ Should(Equal(corev1.ConditionTrue))
+ g.Eventually(IntegrationLogs(t, ctx, ns, name),
TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+
+ // Clean-up
+ g.Expect(Kamel(t, ctx, "delete", "--all", "-n",
ns).Execute()).To(Succeed())
+ })
+
t.Run("Readiness condition with stopped route scaled", func(t
*testing.T) {
name := RandomizedSuffixName("java")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "-t", "health.enabled=true", "-t", "jolokia.enabled=true",
"-t", "jolokia.use-ssl-client-authentication=false", "-t",
"jolokia.protocol=http", "--name", name).Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "-t", "jolokia.enabled=true", "-t",
"jolokia.use-ssl-client-authentication=false", "-t", "jolokia.protocol=http",
"--name", name).Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
@@ -75,16 +88,7 @@ func TestHealthTrait(t *testing.T) {
// Finally check the readiness condition becomes truthy
back
g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady),
TestTimeoutMedium).Should(Equal(corev1.ConditionTrue))
- // check integration schema does not contains unwanted
default trait value.
- g.Eventually(UnstructuredIntegration(t, ctx, ns,
name)).ShouldNot(BeNil())
- unstructuredIntegration := UnstructuredIntegration(t,
ctx, ns, name)()
- healthTrait, _, _ :=
unstructured.NestedMap(unstructuredIntegration.Object, "spec", "traits",
"health")
- g.Expect(healthTrait).ToNot(BeNil())
- g.Expect(len(healthTrait)).To(Equal(1))
- g.Expect(healthTrait["enabled"]).To(Equal(true))
-
pods := IntegrationPods(t, ctx, ns, name)()
-
for i, pod := range pods {
// Stop the Camel route
request := map[string]string{
@@ -155,7 +159,7 @@ func TestHealthTrait(t *testing.T) {
t.Run("Readiness condition with stopped route", func(t
*testing.T) {
name := RandomizedSuffixName("java")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "-t", "health.enabled=true", "-t", "jolokia.enabled=true",
"-t", "jolokia.use-ssl-client-authentication=false", "-t",
"jolokia.protocol=http", "--name", name).Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "-t", "jolokia.enabled=true", "-t",
"jolokia.use-ssl-client-authentication=false", "-t", "jolokia.protocol=http",
"--name", name).Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
@@ -410,7 +414,7 @@ func TestHealthTrait(t *testing.T) {
t.Run("Startup condition with never ready route", func(t
*testing.T) {
name :=
RandomizedSuffixName("startup-probe-never-ready-route")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/NeverReady.java", "--name", name, "-t", "health.enabled=true", "-t",
"health.startup-probe-enabled=true", "-t",
"health.startup-timeout=60").Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/NeverReady.java", "--name", name, "-t",
"health.startup-probe-enabled=true", "-t",
"health.startup-timeout=60").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutMedium).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutMedium).Should(Equal(v1.IntegrationPhaseRunning))
@@ -467,7 +471,7 @@ func TestHealthTrait(t *testing.T) {
t.Run("Startup condition with ready route", func(t *testing.T) {
name :=
RandomizedSuffixName("startup-probe-ready-route")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name, "-t", "health.enabled=true", "-t",
"health.startup-probe-enabled=true", "-t",
"health.startup-timeout=60").Execute()).To(Succeed())
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Java.java", "--name", name, "-t", "health.startup-probe-enabled=true",
"-t", "health.startup-timeout=60").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutMedium).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPhase(t, ctx, ns, name),
TestTimeoutMedium).Should(Equal(v1.IntegrationPhaseRunning))
diff --git a/e2e/common/traits/master_test.go b/e2e/common/traits/master_test.go
index 96541a8cc..eb40fe039 100644
--- a/e2e/common/traits/master_test.go
+++ b/e2e/common/traits/master_test.go
@@ -24,13 +24,13 @@ package traits
import (
"context"
+ "fmt"
"testing"
"time"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
. "github.com/apache/camel-k/v2/e2e/support"
v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -56,24 +56,20 @@ func TestMasterTrait(t *testing.T) {
t.Run("only one integration with master runs", func(t
*testing.T) {
nameFirst := RandomizedSuffixName("first")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Master.java", "--name", nameFirst, "--label", "leader-group=same", "-t",
"master.label-key=leader-group", "-t", "master.label-value=same", "-t",
"owner.target-labels=leader-group").Execute()).To(Succeed())
- g.Eventually(IntegrationPodPhase(t, ctx, ns,
nameFirst), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Master.java", "--name", nameFirst,
+ "--label", "leader-group=same", "-t",
"master.label-key=leader-group", "-t", "master.label-value=same", "-t",
"owner.target-labels=leader-group",
+ ).Execute()).To(Succeed())
+ g.Eventually(IntegrationConditionStatus(t, ctx, ns,
nameFirst, v1.IntegrationConditionReady),
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
g.Eventually(IntegrationLogs(t, ctx, ns, nameFirst),
TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
- // Start a second integration with the same lock (it
should not start the route)
+ // Start a second integration with the same lock (it
should not start the route before 15 seconds)
nameSecond := RandomizedSuffixName("second")
- g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Master.java", "--name", nameSecond, "--label", "leader-group=same",
"-t", "master.label-key=leader-group", "-t", "master.label-value=same", "-t",
"master.resource-name=first-lock", "-t",
"owner.target-labels=leader-group").Execute()).To(Succeed())
- g.Eventually(IntegrationPodPhase(t, ctx, ns,
nameSecond), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+ g.Expect(KamelRunWithID(t, ctx, operatorID, ns,
"files/Master.java", "--name", nameSecond,
+ "--label", "leader-group=same", "-t",
"master.label-key=leader-group", "-t", "master.label-value=same", "-t",
"owner.target-labels=leader-group",
+ "-t",
fmt.Sprintf("master.resource-name=%s-lock", nameFirst),
+ ).Execute()).To(Succeed())
g.Eventually(IntegrationLogs(t, ctx, ns, nameSecond),
TestTimeoutShort).Should(ContainSubstring("started in"))
- g.Eventually(IntegrationLogs(t, ctx, ns, nameSecond),
30*time.Second).ShouldNot(ContainSubstring("Magicstring!"))
-
- // check integration schema does not contains unwanted
default trait value.
- g.Eventually(UnstructuredIntegration(t, ctx, ns,
nameFirst)).ShouldNot(BeNil())
- unstructuredIntegration := UnstructuredIntegration(t,
ctx, ns, nameFirst)()
- builderTrait, _, _ :=
unstructured.NestedMap(unstructuredIntegration.Object, "spec", "traits",
"addons", "master")
- g.Expect(builderTrait).ToNot(BeNil())
- g.Expect(len(builderTrait)).To(Equal(2))
-
g.Expect(builderTrait["labelKey"]).To(Equal("leader-group"))
- g.Expect(builderTrait["labelValue"]).To(Equal("same"))
+ g.Eventually(IntegrationLogs(t, ctx, ns, nameSecond),
15*time.Second).ShouldNot(ContainSubstring("Magicstring!"))
+ g.Eventually(IntegrationConditionStatus(t, ctx, ns,
nameSecond, v1.IntegrationConditionReady),
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
})
g.Expect(Kamel(t, ctx, "delete", "--all", "-n",
ns).Execute()).To(Succeed())
diff --git a/pkg/apis/camel/v1/trait/health.go
b/pkg/apis/camel/v1/trait/health.go
index 587249afe..a691afadf 100644
--- a/pkg/apis/camel/v1/trait/health.go
+++ b/pkg/apis/camel/v1/trait/health.go
@@ -19,7 +19,7 @@ package trait
// The health trait is responsible for configuring the health probes on the
integration container.
//
-// It's disabled by default.
+// NOTE: this trait is enabled by default.
//
// +camel-k:trait=health.
type HealthTrait struct {
diff --git a/pkg/cmd/debug.go b/pkg/cmd/debug.go
index 997ecb218..b6c38262c 100644
--- a/pkg/cmd/debug.go
+++ b/pkg/cmd/debug.go
@@ -134,6 +134,11 @@ func (o *debugCmdOptions) run(cmd *cobra.Command, args
[]string) error {
}
func (o *debugCmdOptions) toggleDebug(c camelv1.IntegrationsGetter, it
*v1.Integration, active bool) (*v1.Integration, error) {
+ it = o.toggle(it, active)
+ return c.Integrations(it.Namespace).Update(o.Context, it,
metav1.UpdateOptions{})
+}
+
+func (o *debugCmdOptions) toggle(it *v1.Integration, active bool)
*v1.Integration {
if it.Spec.Traits.JVM == nil {
it.Spec.Traits.JVM = &traitv1.JVMTrait{}
}
@@ -147,5 +152,5 @@ func (o *debugCmdOptions) toggleDebug(c
camelv1.IntegrationsGetter, it *v1.Integ
jvmTrait.DebugSuspend = nil
}
- return c.Integrations(it.Namespace).Update(o.Context, it,
metav1.UpdateOptions{})
+ return it
}
diff --git a/pkg/cmd/debug_test.go b/pkg/cmd/debug_test.go
new file mode 100644
index 000000000..67d5e23d0
--- /dev/null
+++ b/pkg/cmd/debug_test.go
@@ -0,0 +1,78 @@
+/*
+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 cmd
+
+import (
+ "testing"
+
+ v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+ "github.com/apache/camel-k/v2/pkg/util/test"
+ "github.com/spf13/cobra"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/utils/pointer"
+)
+
+const cmdDebug = "debug"
+
+// nolint: unparam
+func initializeDebugCmdOptions(t *testing.T, initObjs ...runtime.Object)
(*cobra.Command, *debugCmdOptions) {
+ t.Helper()
+ fakeClient, err := test.NewFakeClient(initObjs...)
+ require.NoError(t, err)
+ options, rootCmd := kamelTestPreAddCommandInitWithClient(fakeClient)
+ options.Namespace = "default"
+ debugCmdOptions := addTestDebugCmd(*options, rootCmd)
+ kamelTestPostAddCommandInit(t, rootCmd, options)
+
+ return rootCmd, debugCmdOptions
+}
+
+func addTestDebugCmd(options RootCmdOptions, rootCmd *cobra.Command)
*debugCmdOptions {
+ debugCmd, debugOptions := newCmdDebug(&options)
+ debugCmd.Args = test.ArbitraryArgs
+ rootCmd.AddCommand(debugCmd)
+ return debugOptions
+}
+
+func TestToggle(t *testing.T) {
+ defaultIntegration, defaultKit := nominalDebugIntegration("my-it-test")
+
+ _, debugCmdOptions := initializeDebugCmdOptions(t, &defaultIntegration,
&defaultKit)
+ // toggle on
+ it := debugCmdOptions.toggle(&defaultIntegration, true)
+ assert.Equal(t, pointer.Bool(true), it.Spec.Traits.JVM.Debug)
+ // toggle off
+ it = debugCmdOptions.toggle(&defaultIntegration, false)
+ assert.Nil(t, it.Spec.Traits.JVM.Debug)
+}
+
+func nominalDebugIntegration(name string) (v1.Integration, v1.IntegrationKit) {
+ it := v1.NewIntegration("default", name)
+ it.Status.Phase = v1.IntegrationPhaseRunning
+ it.Status.Image = "my-special-image"
+ ik := v1.NewIntegrationKit("default", name+"-kit")
+ it.Status.IntegrationKit = &corev1.ObjectReference{
+ Namespace: ik.Namespace,
+ Name: ik.Name,
+ Kind: ik.Kind,
+ }
+ return it, *ik
+}
diff --git a/pkg/trait/health.go b/pkg/trait/health.go
index 7f764fb7b..b2bd3558a 100644
--- a/pkg/trait/health.go
+++ b/pkg/trait/health.go
@@ -60,11 +60,15 @@ func (t *healthTrait) Configure(e *Environment) (bool,
*TraitCondition, error) {
!e.IntegrationInPhase(v1.IntegrationPhaseInitialization) &&
!e.IntegrationInRunningPhases() {
return false, nil, nil
}
- if !pointer.BoolDeref(t.Enabled, false) {
- return false, nil, nil
+
+ // The trait must be disabled if a debug operation is ongoing
+ if jt := e.Catalog.GetTrait(jvmTraitID); jt != nil {
+ if jvm, ok := jt.(*jvmTrait); ok &&
pointer.BoolDeref(jvm.Debug, false) {
+ return false,
NewIntegrationConditionPlatformDisabledWithMessage("Health", "debug operation
ongoing: incompatible with health checks"), nil
+ }
}
- return true, nil, nil
+ return pointer.BoolDeref(t.Enabled, true), nil, nil
}
func (t *healthTrait) Apply(e *Environment) error {
diff --git a/pkg/trait/health_test.go b/pkg/trait/health_test.go
index 1de406671..571908f7f 100644
--- a/pkg/trait/health_test.go
+++ b/pkg/trait/health_test.go
@@ -23,6 +23,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
@@ -116,5 +117,110 @@ func TestHealthTrait(t *testing.T) {
assert.Nil(t, d.Spec.Template.Spec.Containers[0].ReadinessProbe)
assert.NotNil(t, d.Spec.Template.Spec.Containers[0].StartupProbe)
assert.Equal(t, "/q/health/started",
d.Spec.Template.Spec.Containers[0].StartupProbe.HTTPGet.Path)
+}
+
+func TestConfigureHealthTraitDoesSucceed(t *testing.T) {
+ ht, environment := createNominalHealthTrait(t)
+ configured, condition, err := ht.Configure(environment)
+
+ assert.True(t, configured)
+ assert.Nil(t, err)
+ assert.Nil(t, condition)
+}
+
+func TestConfigureHealthTraitDisabled(t *testing.T) {
+ enabled := false
+ ht, environment := createNominalHealthTrait(t)
+ ht.Enabled = &enabled
+ configured, condition, err := ht.Configure(environment)
+
+ assert.False(t, configured)
+ assert.Nil(t, err)
+ assert.Nil(t, condition)
+}
+
+func TestApplyHealthTraitDefault(t *testing.T) {
+ ht, environment := createNominalHealthTrait(t)
+ configured, condition, err := ht.Configure(environment)
+ assert.True(t, configured)
+ assert.Nil(t, err)
+ assert.Nil(t, condition)
+
+ err = ht.Apply(environment)
+ assert.Nil(t, err)
+ assert.Equal(t, "/q/health/ready",
environment.GetIntegrationContainer().ReadinessProbe.HTTPGet.Path)
+ assert.Equal(t, corev1.URISchemeHTTP,
environment.GetIntegrationContainer().ReadinessProbe.HTTPGet.Scheme)
+ assert.Equal(t, "8080",
environment.GetIntegrationContainer().ReadinessProbe.HTTPGet.Port.String())
+}
+func TestApplyHealthTraitLivenessDefault(t *testing.T) {
+ enabled := true
+ ht, environment := createNominalHealthTrait(t)
+ ht.LivenessProbeEnabled = &enabled
+ configured, condition, err := ht.Configure(environment)
+ assert.True(t, configured)
+ assert.Nil(t, err)
+ assert.Nil(t, condition)
+
+ err = ht.Apply(environment)
+ assert.Nil(t, err)
+ assert.Equal(t, "/q/health/live",
environment.GetIntegrationContainer().LivenessProbe.HTTPGet.Path)
+ assert.Equal(t, corev1.URISchemeHTTP,
environment.GetIntegrationContainer().LivenessProbe.HTTPGet.Scheme)
+ assert.Equal(t, "8080",
environment.GetIntegrationContainer().LivenessProbe.HTTPGet.Port.String())
+}
+
+func TestApplyHealthTraitStartupDefault(t *testing.T) {
+ enabled := true
+ ht, environment := createNominalHealthTrait(t)
+ ht.StartupProbeEnabled = &enabled
+ configured, condition, err := ht.Configure(environment)
+ assert.True(t, configured)
+ assert.Nil(t, err)
+ assert.Nil(t, condition)
+
+ err = ht.Apply(environment)
+ assert.Nil(t, err)
+ assert.Equal(t, "/q/health/started",
environment.GetIntegrationContainer().StartupProbe.HTTPGet.Path)
+ assert.Equal(t, corev1.URISchemeHTTP,
environment.GetIntegrationContainer().StartupProbe.HTTPGet.Scheme)
+ assert.Equal(t, "8080",
environment.GetIntegrationContainer().StartupProbe.HTTPGet.Port.String())
+}
+
+func createNominalHealthTrait(t *testing.T) (*healthTrait, *Environment) {
+ t.Helper()
+ catalog, err := camel.DefaultCatalog()
+ assert.Nil(t, err)
+ trait, _ := newHealthTrait().(*healthTrait)
+
+ environment := &Environment{
+ CamelCatalog: catalog,
+ Catalog: NewCatalog(nil),
+ Integration: &v1.Integration{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "integration-name",
+ Generation: 1,
+ },
+ Status: v1.IntegrationStatus{
+ Phase: v1.IntegrationPhaseRunning,
+ },
+ },
+ Resources: kubernetes.NewCollection(),
+ }
+
+ deployment := appsv1.Deployment{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Deployment",
+ APIVersion: appsv1.SchemeGroupVersion.String(),
+ },
+ Spec: appsv1.DeploymentSpec{
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {Name: "integration"},
+ },
+ },
+ },
+ },
+ }
+ environment.Resources.Add(&deployment)
+ return trait, environment
}
diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go
index 57a59081a..06166a894 100644
--- a/pkg/trait/jvm.go
+++ b/pkg/trait/jvm.go
@@ -40,6 +40,10 @@ import (
"github.com/apache/camel-k/v2/pkg/util/sets"
)
+const (
+ jvmTraitID = "jvm"
+)
+
type jvmTrait struct {
BaseTrait
traitv1.JVMTrait `property:",squash"`
@@ -47,7 +51,7 @@ type jvmTrait struct {
func newJvmTrait() Trait {
return &jvmTrait{
- BaseTrait: NewBaseTrait("jvm", 2000),
+ BaseTrait: NewBaseTrait(jvmTraitID, 2000),
JVMTrait: traitv1.JVMTrait{
DebugAddress: "*:5005",
PrintCommand: pointer.Bool(true),
diff --git a/pkg/trait/trait_test.go b/pkg/trait/trait_test.go
index db1dc7cf8..f7fc02e12 100644
--- a/pkg/trait/trait_test.go
+++ b/pkg/trait/trait_test.go
@@ -561,7 +561,7 @@ func TestExecutedTraitsCondition(t *testing.T) {
v1.IntegrationConditionTraitInfo,
corev1.ConditionTrue,
"TraitConfiguration",
- "Applied traits:
camel,environment,logging,deployer,deployment,gc,container,mount,quarkus,jvm,owner",
+ "Applied traits:
camel,environment,logging,deployer,deployment,gc,container,mount,health,quarkus,jvm,owner",
)
assert.Contains(t, conditions, expectedCondition)
}