You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2021/11/10 07:52:45 UTC
[camel-k] branch main updated: feat: Health trait
This is an automated email from the ASF dual-hosted git repository.
astefanutti 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 38df070 feat: Health trait
38df070 is described below
commit 38df070ec3d95992caf9a563a138026c44d79654
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Tue Nov 9 13:16:10 2021 +0100
feat: Health trait
---
docs/modules/ROOT/nav.adoc | 1 +
docs/modules/traits/pages/container.adoc | 16 ++-
docs/modules/traits/pages/health.adoc | 88 +++++++++++++
e2e/knative/knative_platform_test.go | 2 +-
pkg/resources/resources.go | 6 +-
pkg/trait/container.go | 156 ++++++----------------
pkg/trait/container_probes_test.go | 213 ++++++++++++++-----------------
pkg/trait/container_test.go | 40 ++++--
pkg/trait/health.go | 195 ++++++++++++++++++++++++++++
pkg/trait/jolokia.go | 2 +-
pkg/trait/jvm.go | 2 +-
pkg/trait/jvm_test.go | 2 +-
pkg/trait/knative_service.go | 4 +-
pkg/trait/prometheus.go | 2 +-
pkg/trait/quarkus.go | 2 +-
pkg/trait/trait_register.go | 1 +
pkg/trait/trait_types.go | 4 +-
resources/traits.yaml | 116 +++++++++++++----
18 files changed, 568 insertions(+), 284 deletions(-)
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index 375ad93..223a98e 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -53,6 +53,7 @@
** xref:traits:environment.adoc[Environment]
** xref:traits:error-handler.adoc[Error Handler]
** xref:traits:gc.adoc[Gc]
+** xref:traits:health.adoc[Health]
** xref:traits:ingress.adoc[Ingress]
** xref:traits:istio.adoc[Istio]
** xref:traits:jolokia.adoc[Jolokia]
diff --git a/docs/modules/traits/pages/container.adoc b/docs/modules/traits/pages/container.adoc
index ac5124c..fa48ab3 100755
--- a/docs/modules/traits/pages/container.adoc
+++ b/docs/modules/traits/pages/container.adoc
@@ -5,7 +5,6 @@ The Container trait can be used to configure properties of the container where t
It also provides configuration for Services associated to the container.
-
This trait is available in the following profiles: **Kubernetes, Knative, OpenShift**.
WARNING: The container trait is a *platform trait*: disabling it may compromise the platform functionality.
@@ -83,59 +82,72 @@ The following configuration options are available:
| container.probes-enabled
| bool
-| ProbesEnabled enable/disable probes on the container (default `false`)
+| DeprecatedProbesEnabled enable/disable probes on the container (default `false`)
+Deprecated: replaced by the health trait.
| container.liveness-scheme
| string
| Scheme to use when connecting. Defaults to HTTP. Applies to the liveness probe.
+Deprecated: replaced by the health trait.
| container.liveness-initial-delay
| int32
| Number of seconds after the container has started before liveness probes are initiated.
+Deprecated: replaced by the health trait.
| container.liveness-timeout
| int32
| Number of seconds after which the probe times out. Applies to the liveness probe.
+Deprecated: replaced by the health trait.
| container.liveness-period
| int32
| How often to perform the probe. Applies to the liveness probe.
+Deprecated: replaced by the health trait.
| container.liveness-success-threshold
| int32
| Minimum consecutive successes for the probe to be considered successful after having failed.
Applies to the liveness probe.
+Deprecated: replaced by the health trait.
| container.liveness-failure-threshold
| int32
| Minimum consecutive failures for the probe to be considered failed after having succeeded.
Applies to the liveness probe.
+Deprecated: replaced by the health trait.
| container.readiness-scheme
| string
| Scheme to use when connecting. Defaults to HTTP. Applies to the readiness probe.
+Deprecated: replaced by the health trait.
| container.readiness-initial-delay
| int32
| Number of seconds after the container has started before readiness probes are initiated.
+Deprecated: replaced by the health trait.
| container.readiness-timeout
| int32
| Number of seconds after which the probe times out. Applies to the readiness probe.
+Deprecated: replaced by the health trait.
| container.readiness-period
| int32
| How often to perform the probe. Applies to the readiness probe.
+Deprecated: replaced by the health trait.
| container.readiness-success-threshold
| int32
| Minimum consecutive successes for the probe to be considered successful after having failed.
Applies to the readiness probe.
+Deprecated: replaced by the health trait.
| container.readiness-failure-threshold
| int32
| Minimum consecutive failures for the probe to be considered failed after having succeeded.
Applies to the readiness probe.
+Deprecated: replaced by the health trait.
|===
diff --git a/docs/modules/traits/pages/health.adoc b/docs/modules/traits/pages/health.adoc
new file mode 100755
index 0000000..6606de9
--- /dev/null
+++ b/docs/modules/traits/pages/health.adoc
@@ -0,0 +1,88 @@
+= Health Trait
+
+// Start of autogenerated code - DO NOT EDIT! (description)
+The health trait is responsible for configuring the health probes on the integration container.
+
+It's disabled by default.
+
+
+This trait is available in the following profiles: **Kubernetes, Knative, OpenShift**.
+
+// End of autogenerated code - DO NOT EDIT! (description)
+// Start of autogenerated code - DO NOT EDIT! (configuration)
+== Configuration
+
+Trait properties can be specified when running any integration with the CLI:
+[source,console]
+----
+$ kamel run --trait health.[key]=[value] --trait health.[key2]=[value2] integration.groovy
+----
+The following configuration options are available:
+
+[cols="2m,1m,5a"]
+|===
+|Property | Type | Description
+
+| health.enabled
+| bool
+| Can be used to enable or disable a trait. All traits share this common property.
+
+| health.liveness-probe-enabled
+| bool
+| Configures the liveness probe for the integration container (default `false`).
+
+| health.liveness-scheme
+| string
+| Scheme to use when connecting to the liveness probe (default `HTTP`).
+
+| health.liveness-initial-delay
+| int32
+| Number of seconds after the container has started before the liveness probe is initiated.
+
+| health.liveness-timeout
+| int32
+| Number of seconds after which the liveness probe times out.
+
+| health.liveness-period
+| int32
+| How often to perform the liveness probe.
+
+| health.liveness-success-threshold
+| int32
+| Minimum consecutive successes for the liveness probe to be considered successful after having failed.
+
+| health.liveness-failure-threshold
+| int32
+| Minimum consecutive failures for the liveness probe to be considered failed after having succeeded.
+
+| health.readiness-probe-enabled
+| bool
+| Configures the readiness probe for the integration container (default `true`).
+
+| health.readiness-scheme
+| string
+| Scheme to use when connecting to the readiness probe (default `HTTP`).
+
+| health.readiness-initial-delay
+| int32
+| Number of seconds after the container has started before the readiness probe is initiated.
+
+| health.readiness-timeout
+| int32
+| Number of seconds after which the readiness probe times out.
+
+| health.readiness-period
+| int32
+| How often to perform the readiness probe.
+
+| health.readiness-success-threshold
+| int32
+| Minimum consecutive successes for the readiness probe to be considered successful after having failed.
+
+| health.readiness-failure-threshold
+| int32
+| Minimum consecutive failures for the readiness probe to be considered failed after having succeeded.
+
+|===
+
+// End of autogenerated code - DO NOT EDIT! (configuration)
diff --git a/e2e/knative/knative_platform_test.go b/e2e/knative/knative_platform_test.go
index 8a6f280..f75a690 100644
--- a/e2e/knative/knative_platform_test.go
+++ b/e2e/knative/knative_platform_test.go
@@ -71,7 +71,7 @@ func TestKnativePlatform(t *testing.T) {
Eventually(IntegrationPhase(ns, "yaml")).Should(Equal(v1.IntegrationPhaseRunning))
Eventually(IntegrationLogs(ns, "yaml"), TestTimeoutShort).Should(ContainSubstring("Magicstring!!!"))
// It should keep the old profile saved in status
- Eventually(IntegrationProfile(ns, "yaml"), TestTimeoutMedium).Should(Equal(v1.TraitProfile(string(cluster))))
+ Eventually(IntegrationProfile(ns, "yaml"), TestTimeoutMedium).Should(Equal(v1.TraitProfile(cluster)))
Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
})
diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index 55dfc34..b8af443 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -534,14 +534,14 @@ var assets = func() http.FileSystem {
modTime: time.Time{},
uncompressedSize: 89871,
- compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x4b\x77\xdb\x38\xb6\xee\xdc\xbf\x82\xab\x32\x39\x67\xdd\x16\xba\x2a\xd5\xf7\xd4\x5d\x75\x47\xb6\x1c\x27\x76\x6c\xc7\x89\xdc\x49\xba\x27\xb5\x20\x12\x92\x60\x91\x04\x0d\x80\xb2\x9c\x5f\x7f\x16\x40\xf0\x29\x65\xf3\xe1\x0d\xb7\x06\xe2\x03\x1b\xdf\xc6\xfe\xf0\x20\xde\x78\x13\xcc\xf0\x7e\x27\x6f\x82\x6b\x1e\xb2\x54\xb1\x28\xd0\x22\xd0\x1b\x16\x9c\x66\x34\xdc\xb0\x60\x21\x56\xfa\x89\x4a\x16\x5c\x88\x3c\x8d\xa8\xe6\x [...]
+ compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x4b\x77\xdb\x38\xb6\xee\xdc\xbf\x82\xab\x32\x39\x67\xdd\x16\xba\x2a\xd5\xf7\xd4\x5d\x75\x47\xb6\x1c\x27\x76\x6c\xc7\x89\xdc\x49\xba\x27\xb5\x20\x12\x92\x60\x91\x04\x0d\x80\xb2\x9c\x5f\x7f\x16\x40\xf0\x29\x65\xf3\xe1\x0d\xb7\x06\xe2\x03\x1b\xdf\xc6\xfe\xf0\x20\xde\x78\x13\xcc\xf0\x7e\x27\x6f\x82\x6b\x1e\xb2\x54\xb1\x28\xd0\x22\xd0\x1b\x16\x9c\x66\x34\xdc\xb0\x60\x21\x56\xfa\x89\x4a\x16\x5c\x88\x3c\x8d\xa8\xe6\x [...]
},
"/traits.yaml": &vfsgen۰CompressedFileInfo{
name: "traits.yaml",
modTime: time.Time{},
- uncompressedSize: 43798,
+ uncompressedSize: 46832,
- compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\x7d\x73\x1c\xb7\xd1\x20\xfe\xbf\x3e\x05\x8a\xcf\xaf\x4a\x24\x6b\x77\x49\x3b\x4f\x12\xff\x78\xa7\x4b\xd1\x92\x9c\xd0\xd6\x0b\x4f\x92\x9d\x4b\xf9\x5c\x59\xec\x4c\xef\x2e\xb4\x33\xc0\x04\xc0\x90\xda\xdc\x73\xdf\xfd\x0a\xdd\x8d\x97\xd9\x5d\x92\x4b\x59\xf4\x85\x57\x4f\xf2\x87\x45\x72\x00\x34\x1a\x8d\x7e\xef\x86\xb7\x52\x79\x77\xf6\x64\x2c\xb4\x6c\xe1\x4c\xc8\xf9\x5c\x69\xe5\xd7\x4f\x84\xe8\x1a\xe9\xe7\xc6\xb6\x67\x [...]
+ compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7d\xfd\x73\x1c\xb7\xb1\xe0\xef\xfe\x2b\x50\x7c\x57\x25\x92\xb5\xbb\x94\x9d\x97\x3c\x1f\xef\x74\x29\x5a\x92\x13\xda\xfa\xe0\x49\xb2\x73\x29\x9f\x2b\x8b\x9d\xe9\xdd\x85\x38\x0b\x4c\x00\x0c\xa9\xcd\xbd\xfb\xdf\xaf\xd0\xdd\xf8\x98\xd9\x5d\x72\x29\x91\x7e\xe1\xd5\x4b\x7e\xb0\x48\x0e\x80\x46\xa3\xd1\xdf\xdd\xf0\x56\x2a\xef\x4e\xbf\x1a\x0b\x2d\x57\x70\x2a\xe4\x7c\xae\xb4\xf2\xeb\xaf\x84\x68\x1b\xe9\xe7\xc6\xae\x4e\xc5\x [...]
},
}
fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index 26f2b99..a12b261 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -20,9 +20,7 @@ package trait
import (
"fmt"
"path"
- "sort"
- "github.com/apache/camel-k/pkg/util/defaults"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
@@ -33,6 +31,7 @@ import (
v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
"github.com/apache/camel-k/pkg/util"
+ "github.com/apache/camel-k/pkg/util/defaults"
"github.com/apache/camel-k/pkg/util/envvar"
"github.com/apache/camel-k/pkg/util/kubernetes"
)
@@ -42,7 +41,6 @@ const (
defaultContainerPort = 8080
defaultContainerPortName = "http"
defaultServicePort = 80
- defaultProbePath = "/q/health"
containerTraitID = "container"
)
@@ -82,48 +80,62 @@ type containerTrait struct {
Image string `property:"image" json:"image,omitempty"`
// The pull policy: Always|Never|IfNotPresent
ImagePullPolicy corev1.PullPolicy `property:"image-pull-policy" json:"imagePullPolicy,omitempty"`
- // ProbesEnabled enable/disable probes on the container (default `false`)
- ProbesEnabled *bool `property:"probes-enabled" json:"probesEnabled,omitempty"`
+
+ // DeprecatedProbesEnabled enable/disable probes on the container (default `false`)
+ // Deprecated: replaced by the health trait.
+ DeprecatedProbesEnabled *bool `property:"probes-enabled" json:"probesEnabled,omitempty"`
// Scheme to use when connecting. Defaults to HTTP. Applies to the liveness probe.
- LivenessScheme string `property:"liveness-scheme" json:"livenessScheme,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedLivenessScheme string `property:"liveness-scheme" json:"livenessScheme,omitempty"`
// Number of seconds after the container has started before liveness probes are initiated.
- LivenessInitialDelay int32 `property:"liveness-initial-delay" json:"livenessInitialDelay,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedLivenessInitialDelay int32 `property:"liveness-initial-delay" json:"livenessInitialDelay,omitempty"`
// Number of seconds after which the probe times out. Applies to the liveness probe.
- LivenessTimeout int32 `property:"liveness-timeout" json:"livenessTimeout,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedLivenessTimeout int32 `property:"liveness-timeout" json:"livenessTimeout,omitempty"`
// How often to perform the probe. Applies to the liveness probe.
- LivenessPeriod int32 `property:"liveness-period" json:"livenessPeriod,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedLivenessPeriod int32 `property:"liveness-period" json:"livenessPeriod,omitempty"`
// Minimum consecutive successes for the probe to be considered successful after having failed.
// Applies to the liveness probe.
- LivenessSuccessThreshold int32 `property:"liveness-success-threshold" json:"livenessSuccessThreshold,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedLivenessSuccessThreshold int32 `property:"liveness-success-threshold" json:"livenessSuccessThreshold,omitempty"`
// Minimum consecutive failures for the probe to be considered failed after having succeeded.
// Applies to the liveness probe.
- LivenessFailureThreshold int32 `property:"liveness-failure-threshold" json:"livenessFailureThreshold,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedLivenessFailureThreshold int32 `property:"liveness-failure-threshold" json:"livenessFailureThreshold,omitempty"`
// Scheme to use when connecting. Defaults to HTTP. Applies to the readiness probe.
- ReadinessScheme string `property:"readiness-scheme" json:"readinessScheme,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedReadinessScheme string `property:"readiness-scheme" json:"readinessScheme,omitempty"`
// Number of seconds after the container has started before readiness probes are initiated.
- ReadinessInitialDelay int32 `property:"readiness-initial-delay" json:"readinessInitialDelay,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedReadinessInitialDelay int32 `property:"readiness-initial-delay" json:"readinessInitialDelay,omitempty"`
// Number of seconds after which the probe times out. Applies to the readiness probe.
- ReadinessTimeout int32 `property:"readiness-timeout" json:"readinessTimeout,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedReadinessTimeout int32 `property:"readiness-timeout" json:"readinessTimeout,omitempty"`
// How often to perform the probe. Applies to the readiness probe.
- ReadinessPeriod int32 `property:"readiness-period" json:"readinessPeriod,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedReadinessPeriod int32 `property:"readiness-period" json:"readinessPeriod,omitempty"`
// Minimum consecutive successes for the probe to be considered successful after having failed.
// Applies to the readiness probe.
- ReadinessSuccessThreshold int32 `property:"readiness-success-threshold" json:"readinessSuccessThreshold,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedReadinessSuccessThreshold int32 `property:"readiness-success-threshold" json:"readinessSuccessThreshold,omitempty"`
// Minimum consecutive failures for the probe to be considered failed after having succeeded.
// Applies to the readiness probe.
- ReadinessFailureThreshold int32 `property:"readiness-failure-threshold" json:"readinessFailureThreshold,omitempty"`
+ // Deprecated: replaced by the health trait.
+ DeprecatedReadinessFailureThreshold int32 `property:"readiness-failure-threshold" json:"readinessFailureThreshold,omitempty"`
}
func newContainerTrait() Trait {
return &containerTrait{
- BaseTrait: NewBaseTrait(containerTraitID, 1600),
- Port: defaultContainerPort,
- ServicePort: defaultServicePort,
- ServicePortName: defaultContainerPortName,
- Name: defaultContainerName,
- ProbesEnabled: BoolP(false),
- LivenessScheme: string(corev1.URISchemeHTTP),
- ReadinessScheme: string(corev1.URISchemeHTTP),
+ BaseTrait: NewBaseTrait(containerTraitID, 1600),
+ Port: defaultContainerPort,
+ ServicePort: defaultServicePort,
+ ServicePortName: defaultContainerPortName,
+ Name: defaultContainerName,
+ DeprecatedProbesEnabled: BoolP(false),
+ DeprecatedLivenessScheme: string(corev1.URISchemeHTTP),
+ DeprecatedReadinessScheme: string(corev1.URISchemeHTTP),
}
}
@@ -156,18 +168,9 @@ func isValidPullPolicy(policy corev1.PullPolicy) bool {
func (t *containerTrait) Apply(e *Environment) error {
if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
- if err := t.configureDependencies(e); err != nil {
- return err
- }
- } else {
- return t.configureContainer(e)
+ return t.configureImageIntegrationKit(e)
}
-
- if err := t.configureImageIntegrationKit(e); err != nil {
- return err
- }
-
- return nil
+ return t.configureContainer(e)
}
// IsPlatformTrait overrides base class method
@@ -175,21 +178,6 @@ func (t *containerTrait) IsPlatformTrait() bool {
return true
}
-func (t *containerTrait) configureDependencies(e *Environment) error {
- if IsTrue(t.ProbesEnabled) {
- if capability, ok := e.CamelCatalog.Runtime.Capabilities[v1.CapabilityHealth]; ok {
- for _, dependency := range capability.Dependencies {
- util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, dependency.GetDependencyID())
- }
-
- // sort the dependencies to get always the same list if they don't change
- sort.Strings(e.Integration.Status.Dependencies)
- }
- }
-
- return nil
-}
-
func (t *containerTrait) configureImageIntegrationKit(e *Environment) error {
if t.Image != "" {
if e.Integration.Spec.IntegrationKit != nil {
@@ -269,16 +257,8 @@ func (t *containerTrait) configureContainer(e *Environment) error {
}
t.configureCapabilities(e)
- portName := t.PortName
- if portName == "" {
- portName = defaultContainerPortName
- }
// Deployment
if err := e.Resources.VisitDeploymentE(func(deployment *appsv1.Deployment) error {
- if IsTrue(t.ProbesEnabled) && portName == defaultContainerPortName {
- t.configureProbes(&container, t.Port, defaultProbePath)
- }
-
for _, envVar := range e.EnvVars {
envvar.SetVar(&container.Env, envVar)
}
@@ -302,11 +282,6 @@ func (t *containerTrait) configureContainer(e *Environment) error {
// Knative Service
if err := e.Resources.VisitKnativeServiceE(func(service *serving.Service) error {
- if IsTrue(t.ProbesEnabled) && portName == defaultContainerPortName {
- // don't set the port on Knative service as it is not allowed.
- t.configureProbes(&container, 0, defaultProbePath)
- }
-
for _, env := range e.EnvVars {
switch {
case env.ValueFrom == nil:
@@ -341,10 +316,6 @@ func (t *containerTrait) configureContainer(e *Environment) error {
// CronJob
if err := e.Resources.VisitCronJobE(func(cron *v1beta1.CronJob) error {
- if IsTrue(t.ProbesEnabled) && portName == defaultContainerPortName {
- t.configureProbes(&container, t.Port, defaultProbePath)
- }
-
for _, envVar := range e.EnvVars {
envvar.SetVar(&container.Env, envVar)
}
@@ -462,52 +433,3 @@ func (t *containerTrait) configureCapabilities(e *Environment) {
e.ApplicationProperties["camel.context.rest-configuration.component"] = "platform-http"
}
}
-
-func (t *containerTrait) configureProbes(container *corev1.Container, port int, path string) {
- container.LivenessProbe = t.newLivenessProbe(port, path)
- container.ReadinessProbe = t.newReadinessProbe(port, path)
-}
-
-func (t *containerTrait) newLivenessProbe(port int, path string) *corev1.Probe {
- action := corev1.HTTPGetAction{}
- action.Path = path
- action.Scheme = corev1.URIScheme(t.LivenessScheme)
-
- if port > 0 {
- action.Port = intstr.FromInt(port)
- }
-
- p := corev1.Probe{
- Handler: corev1.Handler{
- HTTPGet: &action,
- },
- }
-
- p.InitialDelaySeconds = t.LivenessInitialDelay
- p.TimeoutSeconds = t.LivenessTimeout
- p.PeriodSeconds = t.LivenessPeriod
- p.SuccessThreshold = t.LivenessSuccessThreshold
- p.FailureThreshold = t.LivenessFailureThreshold
-
- return &p
-}
-
-func (t *containerTrait) newReadinessProbe(port int, path string) *corev1.Probe {
- p := corev1.Probe{
- Handler: corev1.Handler{
- HTTPGet: &corev1.HTTPGetAction{
- Port: intstr.FromInt(port),
- Path: path,
- Scheme: corev1.URIScheme(t.ReadinessScheme),
- },
- },
- }
-
- p.InitialDelaySeconds = t.ReadinessInitialDelay
- p.TimeoutSeconds = t.ReadinessTimeout
- p.PeriodSeconds = t.ReadinessPeriod
- p.SuccessThreshold = t.ReadinessSuccessThreshold
- p.FailureThreshold = t.ReadinessFailureThreshold
-
- return &p
-}
diff --git a/pkg/trait/container_probes_test.go b/pkg/trait/container_probes_test.go
index cf9ba13..0d4ccbd 100644
--- a/pkg/trait/container_probes_test.go
+++ b/pkg/trait/container_probes_test.go
@@ -22,170 +22,149 @@ import (
"github.com/stretchr/testify/assert"
- serving "knative.dev/serving/pkg/apis/serving/v1"
-
- appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
"github.com/apache/camel-k/pkg/util/camel"
"github.com/apache/camel-k/pkg/util/kubernetes"
+ "github.com/apache/camel-k/pkg/util/test"
)
-// nolint: unparam
-func newTestProbesEnv(t *testing.T, provider v1.RuntimeProvider) Environment {
+func newTestProbesEnv(t *testing.T, integration *v1.Integration) Environment {
t.Helper()
- var catalog *camel.RuntimeCatalog
- var err error
-
- switch provider {
- case v1.RuntimeProviderQuarkus:
- catalog, err = camel.QuarkusCatalog()
- default:
- panic("unknown provider " + provider)
- }
-
+ catalog, err := camel.DefaultCatalog()
assert.Nil(t, err)
assert.NotNil(t, catalog)
+ traitCatalog := NewCatalog(nil)
+
return Environment{
- CamelCatalog: catalog,
- Integration: &v1.Integration{
- Status: v1.IntegrationStatus{},
- },
+ Catalog: traitCatalog,
+ CamelCatalog: catalog,
+ Platform: &v1.IntegrationPlatform{},
+ Integration: integration,
Resources: kubernetes.NewCollection(),
ApplicationProperties: make(map[string]string),
}
}
-func newTestContainerTrait() *containerTrait {
- tr, _ := newContainerTrait().(*containerTrait)
- tr.ProbesEnabled = BoolP(true)
-
- return tr
-}
+func TestProbesDependencies(t *testing.T) {
+ integration := &v1.Integration{
+ Spec: v1.IntegrationSpec{
+ Traits: map[string]v1.TraitSpec{
+ "container": test.TraitSpecFromMap(t, map[string]interface{}{
+ "probesEnabled": true,
+ }),
+ },
+ },
+ }
-func TestProbesDepsQuarkus(t *testing.T) {
- env := newTestProbesEnv(t, v1.RuntimeProviderQuarkus)
+ env := newTestProbesEnv(t, integration)
env.Integration.Status.Phase = v1.IntegrationPhaseInitialization
- ctr := newTestContainerTrait()
-
- ok, err := ctr.Configure(&env)
+ err := env.Catalog.apply(&env)
assert.Nil(t, err)
- assert.True(t, ok)
- err = ctr.Apply(&env)
- assert.Nil(t, err)
assert.Contains(t, env.Integration.Status.Dependencies, "mvn:org.apache.camel.quarkus:camel-quarkus-microprofile-health")
}
func TestProbesOnDeployment(t *testing.T) {
- target := appsv1.Deployment{}
+ integration := &v1.Integration{
+ Spec: v1.IntegrationSpec{
+ Traits: map[string]v1.TraitSpec{
+ "container": test.TraitSpecFromMap(t, map[string]interface{}{
+ "probesEnabled": true,
+ "expose": true,
+ "LivenessTimeout": 1234,
+ }),
+ },
+ },
+ }
- env := newTestProbesEnv(t, v1.RuntimeProviderQuarkus)
+ env := newTestProbesEnv(t, integration)
env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
- env.Resources.Add(&target)
-
- ctr := newTestContainerTrait()
- ctr.Expose = BoolP(true)
- ctr.LivenessTimeout = 1234
- err := ctr.Apply(&env)
+ err := env.Catalog.apply(&env)
assert.Nil(t, err)
- assert.Equal(t, "", target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Host)
- assert.Equal(t, int32(defaultContainerPort), target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Port.IntVal)
- assert.Equal(t, defaultProbePath, target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Path)
- assert.Equal(t, corev1.URISchemeHTTP, target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Scheme)
- assert.Equal(t, "", target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Host)
- assert.Equal(t, int32(defaultContainerPort), target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Port.IntVal)
- assert.Equal(t, defaultProbePath, target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Path)
- assert.Equal(t, corev1.URISchemeHTTP, target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Scheme)
- assert.Equal(t, int32(1234), target.Spec.Template.Spec.Containers[0].LivenessProbe.TimeoutSeconds)
+ container := env.GetIntegrationContainer()
+
+ assert.Equal(t, "", container.LivenessProbe.HTTPGet.Host)
+ assert.Equal(t, int32(defaultContainerPort), container.LivenessProbe.HTTPGet.Port.IntVal)
+ assert.Equal(t, defaultLivenessProbePath, container.LivenessProbe.HTTPGet.Path)
+ assert.Equal(t, corev1.URISchemeHTTP, container.ReadinessProbe.HTTPGet.Scheme)
+ assert.Equal(t, "", container.ReadinessProbe.HTTPGet.Host)
+ assert.Equal(t, int32(defaultContainerPort), container.ReadinessProbe.HTTPGet.Port.IntVal)
+ assert.Equal(t, defaultReadinessProbePath, container.ReadinessProbe.HTTPGet.Path)
+ assert.Equal(t, corev1.URISchemeHTTP, container.LivenessProbe.HTTPGet.Scheme)
+ assert.Equal(t, int32(1234), container.LivenessProbe.TimeoutSeconds)
}
func TestProbesOnDeploymentWithCustomScheme(t *testing.T) {
- target := appsv1.Deployment{}
+ integration := &v1.Integration{
+ Spec: v1.IntegrationSpec{
+ Traits: map[string]v1.TraitSpec{
+ "container": test.TraitSpecFromMap(t, map[string]interface{}{
+ "probesEnabled": true,
+ "expose": true,
+ "livenessTimeout": 1234,
+ "livenessScheme": "HTTPS",
+ "readinessScheme": "HTTPS",
+ }),
+ },
+ },
+ }
- env := newTestProbesEnv(t, v1.RuntimeProviderQuarkus)
+ env := newTestProbesEnv(t, integration)
env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
- env.Resources.Add(&target)
- ctr := newTestContainerTrait()
- ctr.Expose = BoolP(true)
- ctr.LivenessTimeout = 1234
- ctr.LivenessScheme = "HTTPS"
- ctr.ReadinessScheme = "HTTPS"
-
- err := ctr.Apply(&env)
+ err := env.Catalog.apply(&env)
assert.Nil(t, err)
- assert.Equal(t, "", target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Host)
- assert.Equal(t, int32(defaultContainerPort), target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Port.IntVal)
- assert.Equal(t, defaultProbePath, target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Path)
- assert.Equal(t, corev1.URISchemeHTTPS, target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Scheme)
- assert.Equal(t, "", target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Host)
- assert.Equal(t, int32(defaultContainerPort), target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Port.IntVal)
- assert.Equal(t, defaultProbePath, target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Path)
- assert.Equal(t, corev1.URISchemeHTTPS, target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Scheme)
- assert.Equal(t, int32(1234), target.Spec.Template.Spec.Containers[0].LivenessProbe.TimeoutSeconds)
-}
-
-func TestProbesOnDeploymentWithNoHttpPort(t *testing.T) {
- target := appsv1.Deployment{}
-
- env := newTestProbesEnv(t, v1.RuntimeProviderQuarkus)
- env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
- env.Resources.Add(&target)
-
- ctr := newTestContainerTrait()
- ctr.PortName = "custom"
- ctr.LivenessTimeout = 1234
-
- err := ctr.Apply(&env)
- assert.Nil(t, err)
- assert.Nil(t, target.Spec.Template.Spec.Containers[0].LivenessProbe)
- assert.Nil(t, target.Spec.Template.Spec.Containers[0].ReadinessProbe)
+ container := env.GetIntegrationContainer()
+
+ assert.Equal(t, "", container.LivenessProbe.HTTPGet.Host)
+ assert.Equal(t, int32(defaultContainerPort), container.LivenessProbe.HTTPGet.Port.IntVal)
+ assert.Equal(t, defaultLivenessProbePath, container.LivenessProbe.HTTPGet.Path)
+ assert.Equal(t, corev1.URISchemeHTTPS, container.ReadinessProbe.HTTPGet.Scheme)
+ assert.Equal(t, "", container.ReadinessProbe.HTTPGet.Host)
+ assert.Equal(t, int32(defaultContainerPort), container.ReadinessProbe.HTTPGet.Port.IntVal)
+ assert.Equal(t, defaultReadinessProbePath, container.ReadinessProbe.HTTPGet.Path)
+ assert.Equal(t, corev1.URISchemeHTTPS, container.LivenessProbe.HTTPGet.Scheme)
+ assert.Equal(t, int32(1234), container.LivenessProbe.TimeoutSeconds)
}
func TestProbesOnKnativeService(t *testing.T) {
- target := serving.Service{}
+ integration := &v1.Integration{
+ Spec: v1.IntegrationSpec{
+ Profile: v1.TraitProfileKnative,
+ Traits: map[string]v1.TraitSpec{
+ "knative-service": test.TraitSpecFromMap(t, map[string]interface{}{
+ "enabled": true,
+ }),
+ "container": test.TraitSpecFromMap(t, map[string]interface{}{
+ "probesEnabled": true,
+ "expose": true,
+ "livenessTimeout": 1234,
+ }),
+ },
+ },
+ }
- env := newTestProbesEnv(t, v1.RuntimeProviderQuarkus)
+ env := newTestProbesEnv(t, integration)
env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
- env.Resources.Add(&target)
-
- ctr := newTestContainerTrait()
- ctr.Expose = BoolP(true)
- ctr.LivenessTimeout = 1234
- err := ctr.Apply(&env)
+ err := env.Catalog.apply(&env)
assert.Nil(t, err)
- assert.Equal(t, "", target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Host)
- assert.Equal(t, int32(0), target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Port.IntVal)
- assert.Equal(t, defaultProbePath, target.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Path)
- assert.Equal(t, "", target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Host)
- assert.Equal(t, int32(0), target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Port.IntVal)
- assert.Equal(t, defaultProbePath, target.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Path)
- assert.Equal(t, int32(1234), target.Spec.Template.Spec.Containers[0].LivenessProbe.TimeoutSeconds)
-}
-
-func TestProbesOnKnativeServiceWithNoHttpPort(t *testing.T) {
- target := serving.Service{}
+ container := env.GetIntegrationContainer()
- env := newTestProbesEnv(t, v1.RuntimeProviderQuarkus)
- env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
- env.Resources.Add(&target)
-
- ctr := newTestContainerTrait()
- ctr.PortName = "custom"
- ctr.LivenessTimeout = 1234
-
- err := ctr.Apply(&env)
- assert.Nil(t, err)
- assert.Nil(t, target.Spec.Template.Spec.Containers[0].LivenessProbe)
- assert.Nil(t, target.Spec.Template.Spec.Containers[0].ReadinessProbe)
+ assert.Equal(t, "", container.LivenessProbe.HTTPGet.Host)
+ assert.Equal(t, int32(0), container.LivenessProbe.HTTPGet.Port.IntVal)
+ assert.Equal(t, defaultLivenessProbePath, container.LivenessProbe.HTTPGet.Path)
+ assert.Equal(t, "", container.ReadinessProbe.HTTPGet.Host)
+ assert.Equal(t, int32(0), container.ReadinessProbe.HTTPGet.Port.IntVal)
+ assert.Equal(t, defaultReadinessProbePath, container.ReadinessProbe.HTTPGet.Path)
+ assert.Equal(t, int32(1234), container.LivenessProbe.TimeoutSeconds)
}
diff --git a/pkg/trait/container_test.go b/pkg/trait/container_test.go
index f36a0db..c4deae4 100644
--- a/pkg/trait/container_test.go
+++ b/pkg/trait/container_test.go
@@ -24,7 +24,6 @@ import (
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
- appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -331,22 +330,37 @@ func TestContainerWithCustomImageAndDeprecatedIntegrationKit(t *testing.T) {
}
func TestContainerWithImagePullPolicy(t *testing.T) {
- target := appsv1.Deployment{}
+ catalog, err := camel.DefaultCatalog()
+ assert.Nil(t, err)
- env := newTestProbesEnv(t, v1.RuntimeProviderQuarkus)
- env.Integration.Status.Phase = v1.IntegrationPhaseDeploying
- env.Resources.Add(&target)
+ client, _ := test.NewFakeClient()
+ traitCatalog := NewCatalog(nil)
- ctr := newTestContainerTrait()
- ctr.ImagePullPolicy = "Always"
+ environment := Environment{
+ Ctx: context.TODO(),
+ Client: client,
+ CamelCatalog: catalog,
+ Catalog: traitCatalog,
+ Integration: &v1.Integration{
+ Spec: v1.IntegrationSpec{
+ Profile: v1.TraitProfileKubernetes,
+ Traits: map[string]v1.TraitSpec{
+ "container": test.TraitSpecFromMap(t, map[string]interface{}{
+ "imagePullPolicy": "Always",
+ }),
+ },
+ },
+ },
+ Platform: &v1.IntegrationPlatform{},
+ Resources: kubernetes.NewCollection(),
+ }
+ environment.Integration.Status.Phase = v1.IntegrationPhaseDeploying
+ environment.Platform.ResyncStatusFullConfig()
- err := ctr.Apply(&env)
+ err = traitCatalog.apply(&environment)
assert.Nil(t, err)
- assert.Equal(t, corev1.PullAlways, target.Spec.Template.Spec.Containers[0].ImagePullPolicy)
- ctr.ImagePullPolicy = "MustFail"
+ container := environment.GetIntegrationContainer()
- ok, err := ctr.Configure(&env)
- assert.False(t, ok)
- assert.NotNil(t, err)
+ assert.Equal(t, corev1.PullAlways, container.ImagePullPolicy)
}
diff --git a/pkg/trait/health.go b/pkg/trait/health.go
new file mode 100644
index 0000000..0d60ca4
--- /dev/null
+++ b/pkg/trait/health.go
@@ -0,0 +1,195 @@
+/*
+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 trait
+
+import (
+ "encoding/json"
+ "sort"
+
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/util/intstr"
+
+ v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+ "github.com/apache/camel-k/pkg/util"
+)
+
+const (
+ defaultLivenessProbePath = "/q/health/live"
+ defaultReadinessProbePath = "/q/health/ready"
+)
+
+// The health trait is responsible for configuring the health probes on the integration container.
+//
+// It's disabled by default.
+//
+// +camel-k:trait=health
+type healthTrait struct {
+ BaseTrait `property:",squash"`
+
+ // Configures the liveness probe for the integration container (default `false`).
+ LivenessProbeEnabled *bool `property:"liveness-probe-enabled" json:"livenessProbeEnabled,omitempty"`
+ // Scheme to use when connecting to the liveness probe (default `HTTP`).
+ LivenessScheme string `property:"liveness-scheme" json:"livenessScheme,omitempty"`
+ // Number of seconds after the container has started before the liveness probe is initiated.
+ LivenessInitialDelay int32 `property:"liveness-initial-delay" json:"livenessInitialDelay,omitempty"`
+ // Number of seconds after which the liveness probe times out.
+ LivenessTimeout int32 `property:"liveness-timeout" json:"livenessTimeout,omitempty"`
+ // How often to perform the liveness probe.
+ LivenessPeriod int32 `property:"liveness-period" json:"livenessPeriod,omitempty"`
+ // Minimum consecutive successes for the liveness probe to be considered successful after having failed.
+ LivenessSuccessThreshold int32 `property:"liveness-success-threshold" json:"livenessSuccessThreshold,omitempty"`
+ // Minimum consecutive failures for the liveness probe to be considered failed after having succeeded.
+ LivenessFailureThreshold int32 `property:"liveness-failure-threshold" json:"livenessFailureThreshold,omitempty"`
+
+ // Configures the readiness probe for the integration container (default `true`).
+ ReadinessProbeEnabled *bool `property:"readiness-probe-enabled" json:"readinessProbeEnabled,omitempty"`
+ // Scheme to use when connecting to the readiness probe (default `HTTP`).
+ ReadinessScheme string `property:"readiness-scheme" json:"readinessScheme,omitempty"`
+ // Number of seconds after the container has started before the readiness probe is initiated.
+ ReadinessInitialDelay int32 `property:"readiness-initial-delay" json:"readinessInitialDelay,omitempty"`
+ // Number of seconds after which the readiness probe times out.
+ ReadinessTimeout int32 `property:"readiness-timeout" json:"readinessTimeout,omitempty"`
+ // How often to perform the readiness probe.
+ ReadinessPeriod int32 `property:"readiness-period" json:"readinessPeriod,omitempty"`
+ // Minimum consecutive successes for the readiness probe to be considered successful after having failed.
+ ReadinessSuccessThreshold int32 `property:"readiness-success-threshold" json:"readinessSuccessThreshold,omitempty"`
+ // Minimum consecutive failures for the readiness probe to be considered failed after having succeeded.
+ ReadinessFailureThreshold int32 `property:"readiness-failure-threshold" json:"readinessFailureThreshold,omitempty"`
+}
+
+func newHealthTrait() Trait {
+ return &healthTrait{
+ BaseTrait: NewBaseTrait("health", 1700),
+ LivenessScheme: string(corev1.URISchemeHTTP),
+ ReadinessScheme: string(corev1.URISchemeHTTP),
+ }
+}
+
+func (t *healthTrait) Configure(e *Environment) (bool, error) {
+ if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() {
+ return false, nil
+ }
+
+ if IsNilOrFalse(t.Enabled) {
+ // Source the configuration from the container trait to maintain backward compatibility.
+ // This can be removed once the deprecated properties related to health probes are actually
+ // removed from the container trait.
+ if trait := e.Catalog.GetTrait(containerTraitID); trait != nil {
+ if container, ok := trait.(*containerTrait); ok && IsNilOrTrue(container.Enabled) && IsTrue(container.DeprecatedProbesEnabled) {
+ config, err := json.Marshal(container)
+ if err != nil {
+ return false, err
+ }
+ err = json.Unmarshal(config, t)
+ if err != nil {
+ return false, err
+ }
+ t.Enabled = BoolP(true)
+ t.LivenessProbeEnabled = BoolP(true)
+ t.ReadinessProbeEnabled = BoolP(true)
+ return true, err
+ }
+ }
+ return false, nil
+ }
+
+ return true, nil
+}
+
+func (t *healthTrait) Apply(e *Environment) error {
+ if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
+ if capability, ok := e.CamelCatalog.Runtime.Capabilities[v1.CapabilityHealth]; ok {
+ for _, dependency := range capability.Dependencies {
+ util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, dependency.GetDependencyID())
+ }
+ // sort the dependencies to get always the same list if they don't change
+ sort.Strings(e.Integration.Status.Dependencies)
+ }
+ return nil
+ }
+
+ if IsNilOrFalse(t.LivenessProbeEnabled) && IsFalse(t.ReadinessProbeEnabled) {
+ return nil
+ }
+
+ container := e.GetIntegrationContainer()
+ var port *intstr.IntOrString
+ // Use the default named HTTP container port if it exists.
+ // For Knative, the Serving webhook is responsible for setting the user-land port,
+ // and associating the probes with the corresponding port.
+ if containerPort := e.getIntegrationContainerPort(); containerPort != nil && containerPort.Name == defaultContainerPortName {
+ p := intstr.FromString(defaultContainerPortName)
+ port = &p
+ } else if e.GetTrait(knativeServiceTraitID) == nil {
+ p := intstr.FromInt(defaultContainerPort)
+ port = &p
+ }
+
+ if IsTrue(t.LivenessProbeEnabled) {
+ container.LivenessProbe = t.newLivenessProbe(port, defaultLivenessProbePath)
+ }
+ if IsNilOrTrue(t.ReadinessProbeEnabled) {
+ container.ReadinessProbe = t.newReadinessProbe(port, defaultReadinessProbePath)
+ }
+
+ return nil
+}
+
+func (t *healthTrait) newLivenessProbe(port *intstr.IntOrString, path string) *corev1.Probe {
+ p := corev1.Probe{
+ Handler: corev1.Handler{
+ HTTPGet: &corev1.HTTPGetAction{
+ Path: path,
+ Scheme: corev1.URIScheme(t.LivenessScheme),
+ },
+ },
+ InitialDelaySeconds: t.LivenessInitialDelay,
+ TimeoutSeconds: t.LivenessTimeout,
+ PeriodSeconds: t.LivenessPeriod,
+ SuccessThreshold: t.LivenessSuccessThreshold,
+ FailureThreshold: t.LivenessFailureThreshold,
+ }
+
+ if port != nil {
+ p.Handler.HTTPGet.Port = *port
+ }
+
+ return &p
+}
+
+func (t *healthTrait) newReadinessProbe(port *intstr.IntOrString, path string) *corev1.Probe {
+ p := corev1.Probe{
+ Handler: corev1.Handler{
+ HTTPGet: &corev1.HTTPGetAction{
+ Path: path,
+ Scheme: corev1.URIScheme(t.ReadinessScheme),
+ },
+ },
+ InitialDelaySeconds: t.ReadinessInitialDelay,
+ TimeoutSeconds: t.ReadinessTimeout,
+ PeriodSeconds: t.ReadinessPeriod,
+ SuccessThreshold: t.ReadinessSuccessThreshold,
+ FailureThreshold: t.ReadinessFailureThreshold,
+ }
+
+ if port != nil {
+ p.Handler.HTTPGet.Port = *port
+ }
+
+ return &p
+}
diff --git a/pkg/trait/jolokia.go b/pkg/trait/jolokia.go
index 819f9de..b96a70d 100644
--- a/pkg/trait/jolokia.go
+++ b/pkg/trait/jolokia.go
@@ -99,7 +99,7 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) {
return nil
}
- container := e.getIntegrationContainer()
+ container := e.GetIntegrationContainer()
if container == nil {
e.Integration.Status.SetCondition(
v1.IntegrationConditionJolokiaAvailable,
diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go
index 7810cc7..7d1991a 100644
--- a/pkg/trait/jvm.go
+++ b/pkg/trait/jvm.go
@@ -132,7 +132,7 @@ func (t *jvmTrait) Apply(e *Environment) error {
)
}
- container := e.getIntegrationContainer()
+ container := e.GetIntegrationContainer()
if container == nil {
return nil
}
diff --git a/pkg/trait/jvm_test.go b/pkg/trait/jvm_test.go
index bc47aac..4360692 100644
--- a/pkg/trait/jvm_test.go
+++ b/pkg/trait/jvm_test.go
@@ -201,7 +201,7 @@ func TestApplyJvmTraitWithExternalKitType(t *testing.T) {
err := trait.Apply(environment)
assert.Nil(t, err)
- container := environment.getIntegrationContainer()
+ container := environment.GetIntegrationContainer()
assert.Equal(t, 3, len(container.Args))
assert.Equal(t, "-cp", container.Args[0])
diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go
index 7859e08..2b01dd1 100644
--- a/pkg/trait/knative_service.go
+++ b/pkg/trait/knative_service.go
@@ -33,6 +33,8 @@ import (
)
const (
+ knativeServiceTraitID = "knative-service"
+
// Auto-scaling annotations
knativeServingClassAnnotation = "autoscaling.knative.dev/class"
knativeServingMetricAnnotation = "autoscaling.knative.dev/metric"
@@ -89,7 +91,7 @@ var _ ControllerStrategySelector = &knativeServiceTrait{}
func newKnativeServiceTrait() Trait {
return &knativeServiceTrait{
- BaseTrait: NewBaseTrait("knative-service", 1400),
+ BaseTrait: NewBaseTrait(knativeServiceTraitID, 1400),
}
}
diff --git a/pkg/trait/prometheus.go b/pkg/trait/prometheus.go
index 6db5c51..9dae4c8 100644
--- a/pkg/trait/prometheus.go
+++ b/pkg/trait/prometheus.go
@@ -71,7 +71,7 @@ func (t *prometheusTrait) Apply(e *Environment) (err error) {
return nil
}
- container := e.getIntegrationContainer()
+ container := e.GetIntegrationContainer()
if container == nil {
e.Integration.Status.SetCondition(
v1.IntegrationConditionPrometheusAvailable,
diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go
index 4881d7d..c1c37b6 100644
--- a/pkg/trait/quarkus.go
+++ b/pkg/trait/quarkus.go
@@ -235,7 +235,7 @@ func (t *quarkusTrait) Apply(e *Environment) error {
case v1.IntegrationKitPhaseReady:
if e.IntegrationInRunningPhases() && t.isNativeIntegration(e) {
- container := e.getIntegrationContainer()
+ container := e.GetIntegrationContainer()
if container == nil {
return fmt.Errorf("unable to find integration container: %s", e.Integration.Name)
}
diff --git a/pkg/trait/trait_register.go b/pkg/trait/trait_register.go
index 64e8a39..68d2997 100644
--- a/pkg/trait/trait_register.go
+++ b/pkg/trait/trait_register.go
@@ -31,6 +31,7 @@ func init() {
AddToTraits(newEnvironmentTrait)
AddToTraits(newErrorHandlerTrait)
AddToTraits(newGarbageCollectorTrait)
+ AddToTraits(newHealthTrait)
AddToTraits(newIngressTrait)
AddToTraits(newIstioTrait)
AddToTraits(newJolokiaTrait)
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index b0b0241..d4993b9 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -747,7 +747,7 @@ func (e *Environment) collectConfigurations(configurationType string) []map[stri
return collectConfigurations(configurationType, e.Platform, e.IntegrationKit, e.Integration)
}
-func (e *Environment) getIntegrationContainer() *corev1.Container {
+func (e *Environment) GetIntegrationContainer() *corev1.Container {
containerName := defaultContainerName
dt := e.Catalog.GetTrait(containerTraitID)
if dt != nil {
@@ -758,7 +758,7 @@ func (e *Environment) getIntegrationContainer() *corev1.Container {
}
func (e *Environment) getIntegrationContainerPort() *corev1.ContainerPort {
- container := e.getIntegrationContainer()
+ container := e.GetIntegrationContainer()
if container == nil {
return nil
}
diff --git a/resources/traits.yaml b/resources/traits.yaml
index f314b60..47ffab4 100755
--- a/resources/traits.yaml
+++ b/resources/traits.yaml
@@ -134,53 +134,60 @@ traits:
description: 'The pull policy: Always|Never|IfNotPresent'
- name: probes-enabled
type: bool
- description: ProbesEnabled enable/disable probes on the container (default `false`)
+ description: 'DeprecatedProbesEnabled enable/disable probes on the container (default
+ `false`)Deprecated: replaced by the health trait.'
- name: liveness-scheme
type: string
- description: Scheme to use when connecting. Defaults to HTTP. Applies to the liveness
- probe.
+ description: 'Scheme to use when connecting. Defaults to HTTP. Applies to the
+ liveness probe.Deprecated: replaced by the health trait.'
- name: liveness-initial-delay
type: int32
- description: Number of seconds after the container has started before liveness
- probes are initiated.
+ description: 'Number of seconds after the container has started before liveness
+ probes are initiated.Deprecated: replaced by the health trait.'
- name: liveness-timeout
type: int32
- description: Number of seconds after which the probe times out. Applies to the
- liveness probe.
+ description: 'Number of seconds after which the probe times out. Applies to the
+ liveness probe.Deprecated: replaced by the health trait.'
- name: liveness-period
type: int32
- description: How often to perform the probe. Applies to the liveness probe.
+ description: 'How often to perform the probe. Applies to the liveness probe.Deprecated:
+ replaced by the health trait.'
- name: liveness-success-threshold
type: int32
- description: Minimum consecutive successes for the probe to be considered successful
- after having failed.Applies to the liveness probe.
+ description: 'Minimum consecutive successes for the probe to be considered successful
+ after having failed.Applies to the liveness probe.Deprecated: replaced by the
+ health trait.'
- name: liveness-failure-threshold
type: int32
- description: Minimum consecutive failures for the probe to be considered failed
- after having succeeded.Applies to the liveness probe.
+ description: 'Minimum consecutive failures for the probe to be considered failed
+ after having succeeded.Applies to the liveness probe.Deprecated: replaced by
+ the health trait.'
- name: readiness-scheme
type: string
- description: Scheme to use when connecting. Defaults to HTTP. Applies to the readiness
- probe.
+ description: 'Scheme to use when connecting. Defaults to HTTP. Applies to the
+ readiness probe.Deprecated: replaced by the health trait.'
- name: readiness-initial-delay
type: int32
- description: Number of seconds after the container has started before readiness
- probes are initiated.
+ description: 'Number of seconds after the container has started before readiness
+ probes are initiated.Deprecated: replaced by the health trait.'
- name: readiness-timeout
type: int32
- description: Number of seconds after which the probe times out. Applies to the
- readiness probe.
+ description: 'Number of seconds after which the probe times out. Applies to the
+ readiness probe.Deprecated: replaced by the health trait.'
- name: readiness-period
type: int32
- description: How often to perform the probe. Applies to the readiness probe.
+ description: 'How often to perform the probe. Applies to the readiness probe.Deprecated:
+ replaced by the health trait.'
- name: readiness-success-threshold
type: int32
- description: Minimum consecutive successes for the probe to be considered successful
- after having failed.Applies to the readiness probe.
+ description: 'Minimum consecutive successes for the probe to be considered successful
+ after having failed.Applies to the readiness probe.Deprecated: replaced by the
+ health trait.'
- name: readiness-failure-threshold
type: int32
- description: Minimum consecutive failures for the probe to be considered failed
- after having succeeded.Applies to the readiness probe.
+ description: 'Minimum consecutive failures for the probe to be considered failed
+ after having succeeded.Applies to the readiness probe.Deprecated: replaced by
+ the health trait.'
- name: cron
platform: false
profiles:
@@ -345,6 +352,69 @@ traits:
type: ./pkg/trait.discoveryCacheType
description: Discovery client cache to be used, either `disabled`, `disk` or `memory`
(default `memory`)
+- name: health
+ platform: false
+ profiles:
+ - Kubernetes
+ - Knative
+ - OpenShift
+ description: The health trait is responsible for configuring the health probes on
+ the integration container. It's disabled by default.
+ properties:
+ - name: enabled
+ type: bool
+ description: Can be used to enable or disable a trait. All traits share this common
+ property.
+ - name: liveness-probe-enabled
+ type: bool
+ description: Configures the liveness probe for the integration container (default
+ `false`).
+ - name: liveness-scheme
+ type: string
+ description: Scheme to use when connecting to the liveness probe (default `HTTP`).
+ - name: liveness-initial-delay
+ type: int32
+ description: Number of seconds after the container has started before the liveness
+ probe is initiated.
+ - name: liveness-timeout
+ type: int32
+ description: Number of seconds after which the liveness probe times out.
+ - name: liveness-period
+ type: int32
+ description: How often to perform the liveness probe.
+ - name: liveness-success-threshold
+ type: int32
+ description: Minimum consecutive successes for the liveness probe to be considered
+ successful after having failed.
+ - name: liveness-failure-threshold
+ type: int32
+ description: Minimum consecutive failures for the liveness probe to be considered
+ failed after having succeeded.
+ - name: readiness-probe-enabled
+ type: bool
+ description: Configures the readiness probe for the integration container (default
+ `true`).
+ - name: readiness-scheme
+ type: string
+ description: Scheme to use when connecting to the readiness probe (default `HTTP`).
+ - name: readiness-initial-delay
+ type: int32
+ description: Number of seconds after the container has started before the readiness
+ probe is initiated.
+ - name: readiness-timeout
+ type: int32
+ description: Number of seconds after which the readiness probe times out.
+ - name: readiness-period
+ type: int32
+ description: How often to perform the readiness probe.
+ - name: readiness-success-threshold
+ type: int32
+ description: Minimum consecutive successes for the readiness probe to be considered
+ successful after having failed.
+ - name: readiness-failure-threshold
+ type: int32
+ description: Minimum consecutive failures for the readiness probe to be considered
+ failed after having succeeded.
- name: ingress
platform: false
profiles: