Skip to content

Commit

Permalink
feat(trait): enable health trait by default
Browse files Browse the repository at this point in the history
Closes #5024
  • Loading branch information
squakez committed Apr 30, 2024
1 parent 698b470 commit 1cde321
Show file tree
Hide file tree
Showing 16 changed files with 255 additions and 28 deletions.
4 changes: 2 additions & 2 deletions e2e/common/cli/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
})
Expand All @@ -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())
})
Expand Down
5 changes: 5 additions & 0 deletions e2e/common/misc/files/cron-fallback.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions e2e/common/misc/files/cron-quartz.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions e2e/common/misc/files/cron-timer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions e2e/common/misc/files/cron-trait-yaml.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions e2e/common/misc/files/cron-yaml.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion e2e/common/misc/integration_fail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
32 changes: 18 additions & 14 deletions e2e/common/traits/health_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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))
Expand All @@ -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{
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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))
Expand Down
8 changes: 4 additions & 4 deletions e2e/common/traits/master_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ 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.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.Eventually(IntegrationLogs(t, ctx, ns, nameSecond), TestTimeoutShort).Should(ContainSubstring("started in"))
g.Eventually(IntegrationLogs(t, ctx, ns, nameSecond), 30*time.Second).ShouldNot(ContainSubstring("Magicstring!"))
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))

// check integration schema does not contains unwanted default trait value.
g.Eventually(UnstructuredIntegration(t, ctx, ns, nameFirst)).ShouldNot(BeNil())
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/camel/v1/trait/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 6 additions & 1 deletion pkg/cmd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
}
Expand All @@ -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
}
78 changes: 78 additions & 0 deletions pkg/cmd/debug_test.go
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 7 additions & 3 deletions pkg/trait/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 1cde321

Please sign in to comment.