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 ed390df1e feat(trait): init containers
ed390df1e is described below
commit ed390df1e57917db9f3fdec7f9a5879b00260797
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Fri Aug 15 08:42:38 2025 +0200
feat(trait): init containers
A trait which simplify setting init and sidecar containers
---
docs/modules/ROOT/nav.adoc | 1 +
docs/modules/ROOT/partials/apis/camel-k-crds.adoc | 54 ++++
docs/modules/traits/pages/init-containers.adoc | 76 ++++++
e2e/common/traits/files/init-container.yaml | 27 ++
e2e/common/traits/init_container_test.go | 71 +++++
helm/camel-k/crds/camel-k-crds.yaml | 196 ++++++++++++++
pkg/apis/camel/v1/common_types.go | 2 +
pkg/apis/camel/v1/trait/init_containers.go | 31 +++
pkg/apis/camel/v1/trait/zz_generated.deepcopy.go | 31 +++
pkg/apis/camel/v1/zz_generated.deepcopy.go | 5 +
.../camel/applyconfiguration/camel/v1/traits.go | 9 +
.../camel.apache.org_integrationplatforms.yaml | 56 ++++
.../camel.apache.org_integrationprofiles.yaml | 56 ++++
.../crd/bases/camel.apache.org_integrations.yaml | 56 ++++
.../config/crd/bases/camel.apache.org_pipes.yaml | 28 ++
pkg/trait/init_containers.go | 146 +++++++++++
pkg/trait/init_containers_test.go | 287 +++++++++++++++++++++
pkg/trait/mount.go | 24 +-
pkg/trait/mount_test.go | 34 +++
pkg/trait/trait_register.go | 1 +
pkg/trait/trait_test.go | 2 +-
21 files changed, 1188 insertions(+), 5 deletions(-)
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index d7832331e..0a668f892 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -59,6 +59,7 @@
** xref:traits:hashicorp-vault.adoc[Hashicorp Vault]
** xref:traits:health.adoc[Health]
** xref:traits:ingress.adoc[Ingress]
+** xref:traits:init-containers.adoc[Init Containers]
** xref:traits:istio.adoc[Istio]
** xref:traits:jolokia.adoc[Jolokia]
** xref:traits:jvm.adoc[Jvm]
diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index fe77f3128..0eacd3960 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -5980,6 +5980,13 @@ The configuration of Health trait
The configuration of Ingress trait
+|`init-containers` +
+*xref:#_camel_apache_org_v1_trait_InitContainersTrait[InitContainersTrait]*
+|
+
+
+The configuration of Init Containers trait
+
|`istio` +
*xref:#_camel_apache_org_v1_trait_IstioTrait[IstioTrait]*
|
@@ -7433,6 +7440,52 @@ string
To configure tls secret name
+|===
+
+[#_camel_apache_org_v1_trait_InitContainersTrait]
+=== InitContainersTrait
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_Traits, Traits>>
+
+The InitContainersTrait trait can be used to configure `init containers` or
`sidecar containers`.
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`PlatformBaseTrait` +
+*xref:#_camel_apache_org_v1_trait_PlatformBaseTrait[PlatformBaseTrait]*
+|(Members of `PlatformBaseTrait` are embedded into this type.)
+
+
+
+
+|`auto` +
+bool
+|
+
+
+To automatically enable the trait
+
+|`initTasks` +
+[]string
+|
+
+
+A list of init tasks to be executed with format
`<name>;<container-image>;<container-command>`.
+
+|`sideCarTasks` +
+[]string
+|
+
+
+A list of sidecar tasks to be executed with format
`<name>;<container-image>;<container-command>`.
+
+
|===
[#_camel_apache_org_v1_trait_IstioTrait]
@@ -8318,6 +8371,7 @@ Only one of `max-unavailable` and `min-available` can be
specified.
* <<#_camel_apache_org_v1_trait_DeploymentTrait, DeploymentTrait>>
* <<#_camel_apache_org_v1_trait_EnvironmentTrait, EnvironmentTrait>>
* <<#_camel_apache_org_v1_trait_ErrorHandlerTrait, ErrorHandlerTrait>>
+* <<#_camel_apache_org_v1_trait_InitContainersTrait, InitContainersTrait>>
* <<#_camel_apache_org_v1_trait_MountTrait, MountTrait>>
* <<#_camel_apache_org_v1_trait_OpenAPITrait, OpenAPITrait>>
* <<#_camel_apache_org_v1_trait_PlatformTrait, PlatformTrait>>
diff --git a/docs/modules/traits/pages/init-containers.adoc
b/docs/modules/traits/pages/init-containers.adoc
new file mode 100644
index 000000000..8a4fb4e6b
--- /dev/null
+++ b/docs/modules/traits/pages/init-containers.adoc
@@ -0,0 +1,76 @@
+= Init Containers Trait
+
+// Start of autogenerated code - DO NOT EDIT! (badges)
+// End of autogenerated code - DO NOT EDIT! (badges)
+// Start of autogenerated code - DO NOT EDIT! (description)
+The InitContainersTrait trait can be used to configure `init containers` or
`sidecar containers`.
+
+
+This trait is available in the following profiles: **Kubernetes, Knative,
OpenShift**.
+
+NOTE: The init-containers trait is a *platform trait* and cannot be disabled
by the user.
+
+// 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 init-containers.[key]=[value] --trait
init-containers.[key2]=[value2] integration.yaml
+----
+The following configuration options are available:
+
+[cols="2m,1m,5a"]
+|===
+|Property | Type | Description
+
+| init-containers.enabled
+| bool
+| Deprecated: no longer in use.
+
+| init-containers.auto
+| bool
+| To automatically enable the trait
+
+| init-containers.init-tasks
+| []string
+| A list of init tasks to be executed with format
`<name>;<container-image>;<container-command>`.
+
+| init-containers.sidecar-tasks
+| []string
+| A list of sidecar tasks to be executed with format
`<name>;<container-image>;<container-command>`.
+
+|===
+
+// End of autogenerated code - DO NOT EDIT! (configuration)
+
+== An example init container
+
+Create an Integration which read some value initialized by an init container.
The following route takes care to read a file which is expected to be
initialized by another process.
+
+[source,yaml]
+.route.yaml
+----
+- route:
+ from:
+ # Read a file that should have been initialized
+ # by the initContainer
+ uri: file:/tmp
+ parameters:
+ fileName: init
+ steps:
+ - log:
+ message: "${body}"
+----
+
+The route is agnostic how this file is generated.
+
+When creating the Integration, then, it should include an init container
taking care to initialize such file, for example:
+
+[source,console]
+----
+kamel run route.yaml -t mount.empty-dirs=common:/tmp -t
init-containers.tasks="init;alpine;/bin/sh -c \"echo hello >> /tmp/init\""
+----
+
+As the file is shared between the containers you will need to provide a shared
volume (an `EmtpyDir` in this case).
diff --git a/e2e/common/traits/files/init-container.yaml
b/e2e/common/traits/files/init-container.yaml
new file mode 100644
index 000000000..69d4e154d
--- /dev/null
+++ b/e2e/common/traits/files/init-container.yaml
@@ -0,0 +1,27 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+- route:
+ from:
+ # Read a file that should have been initialized
+ # by the initContainer
+ uri: file:/tmp
+ parameters:
+ include: ^(init|sidecar).*
+ steps:
+ - log:
+ message: "${body}"
\ No newline at end of file
diff --git a/e2e/common/traits/init_container_test.go
b/e2e/common/traits/init_container_test.go
new file mode 100644
index 000000000..e6f811706
--- /dev/null
+++ b/e2e/common/traits/init_container_test.go
@@ -0,0 +1,71 @@
+//go:build integration
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go ->
Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package common
+
+import (
+ "context"
+ "testing"
+
+ . "github.com/onsi/gomega"
+
+ corev1 "k8s.io/api/core/v1"
+
+ . "github.com/apache/camel-k/v2/e2e/support"
+ v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+)
+
+func TestInitContainerTrait(t *testing.T) {
+ t.Parallel()
+ WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
+ t.Run("Init container write a file", func(t *testing.T) {
+ name := RandomizedSuffixName("init")
+ g.Expect(KamelRun(t, ctx, ns,
+ "files/init-container.yaml",
+ "-t",
+ "mount.empty-dirs=common:/tmp",
+ "-t",
+ "init-containers.init-tasks=init;alpine;/bin/sh
-c \"echo helloInit >> /tmp/init\"",
+ "--name",
+ name).Execute()).To(Succeed())
+ g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady)).
+ Should(Equal(corev1.ConditionTrue))
+ g.Eventually(IntegrationPodPhase(t, ctx, ns,
name)).Should(Equal(corev1.PodRunning))
+ g.Eventually(IntegrationLogs(t, ctx, ns,
name)).Should(ContainSubstring("helloInit"))
+ })
+ t.Run("Sidecar container write a file", func(t *testing.T) {
+ name := RandomizedSuffixName("sidecar")
+ g.Expect(KamelRun(t, ctx, ns,
+ "files/init-container.yaml",
+ "-t",
+ "mount.empty-dirs=common:/tmp",
+ "-t",
+
"init-containers.sidecar-tasks=sidecar;alpine;/bin/sh -c \"for i in $(seq 1
10); do echo helloSidecar$i > /tmp/sidecar_$i.txt; sleep 1; done\"",
+ "--name",
+ name).Execute()).To(Succeed())
+ g.Eventually(IntegrationConditionStatus(t, ctx, ns,
name, v1.IntegrationConditionReady)).
+ Should(Equal(corev1.ConditionTrue))
+ g.Eventually(IntegrationPodPhase(t, ctx, ns,
name)).Should(Equal(corev1.PodRunning))
+ g.Eventually(IntegrationLogs(t, ctx, ns,
name)).Should(ContainSubstring("helloSidecar10"))
+ })
+ })
+}
diff --git a/helm/camel-k/crds/camel-k-crds.yaml
b/helm/camel-k/crds/camel-k-crds.yaml
index 9f9abcc1e..42433fd38 100644
--- a/helm/camel-k/crds/camel-k-crds.yaml
+++ b/helm/camel-k/crds/camel-k-crds.yaml
@@ -4490,6 +4490,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -6694,6 +6722,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -8800,6 +8856,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -10883,6 +10967,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -19404,6 +19516,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -21430,6 +21570,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -31309,6 +31477,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed
with
+ format
`<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be
executed with
+ format
`<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
diff --git a/pkg/apis/camel/v1/common_types.go
b/pkg/apis/camel/v1/common_types.go
index 71d4bba36..dd06d6337 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -207,6 +207,8 @@ type Traits struct {
Health *trait.HealthTrait `property:"health" json:"health,omitempty"`
// The configuration of Ingress trait
Ingress *trait.IngressTrait `property:"ingress"
json:"ingress,omitempty"`
+ // The configuration of Init Containers trait
+ InitContainers *trait.InitContainersTrait `property:"init-containers"
json:"init-containers,omitempty"`
// The configuration of Istio trait
Istio *trait.IstioTrait `property:"istio" json:"istio,omitempty"`
// The configuration of Jolokia trait
diff --git a/pkg/apis/camel/v1/trait/init_containers.go
b/pkg/apis/camel/v1/trait/init_containers.go
new file mode 100644
index 000000000..af8c98afd
--- /dev/null
+++ b/pkg/apis/camel/v1/trait/init_containers.go
@@ -0,0 +1,31 @@
+/*
+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
+
+// The InitContainersTrait trait can be used to configure `init containers` or
`sidecar containers`.
+//
+// +camel-k:trait=init-containers.
+type InitContainersTrait struct {
+ PlatformBaseTrait `property:",squash" json:",inline"`
+ // To automatically enable the trait
+ Auto *bool `property:"auto" json:"auto,omitempty"`
+ // A list of init tasks to be executed with format
`<name>;<container-image>;<container-command>`.
+ InitTasks []string `property:"init-tasks" json:"initTasks,omitempty"`
+ // A list of sidecar tasks to be executed with format
`<name>;<container-image>;<container-command>`.
+ SidecarTasks []string `property:"sidecar-tasks"
json:"sideCarTasks,omitempty"`
+}
diff --git a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
index 39870bd8f..85011d3c1 100644
--- a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
@@ -479,6 +479,37 @@ func (in *IngressTrait) DeepCopy() *IngressTrait {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
+func (in *InitContainersTrait) DeepCopyInto(out *InitContainersTrait) {
+ *out = *in
+ in.PlatformBaseTrait.DeepCopyInto(&out.PlatformBaseTrait)
+ if in.Auto != nil {
+ in, out := &in.Auto, &out.Auto
+ *out = new(bool)
+ **out = **in
+ }
+ if in.InitTasks != nil {
+ in, out := &in.InitTasks, &out.InitTasks
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.SidecarTasks != nil {
+ in, out := &in.SidecarTasks, &out.SidecarTasks
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new InitContainersTrait.
+func (in *InitContainersTrait) DeepCopy() *InitContainersTrait {
+ if in == nil {
+ return nil
+ }
+ out := new(InitContainersTrait)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
func (in *IstioTrait) DeepCopyInto(out *IstioTrait) {
*out = *in
diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go
b/pkg/apis/camel/v1/zz_generated.deepcopy.go
index 25965dd29..c79874ce1 100644
--- a/pkg/apis/camel/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go
@@ -3228,6 +3228,11 @@ func (in *Traits) DeepCopyInto(out *Traits) {
*out = new(trait.IngressTrait)
(*in).DeepCopyInto(*out)
}
+ if in.InitContainers != nil {
+ in, out := &in.InitContainers, &out.InitContainers
+ *out = new(trait.InitContainersTrait)
+ (*in).DeepCopyInto(*out)
+ }
if in.Istio != nil {
in, out := &in.Istio, &out.Istio
*out = new(trait.IstioTrait)
diff --git a/pkg/client/camel/applyconfiguration/camel/v1/traits.go
b/pkg/client/camel/applyconfiguration/camel/v1/traits.go
index b9654a9c8..7077d311d 100644
--- a/pkg/client/camel/applyconfiguration/camel/v1/traits.go
+++ b/pkg/client/camel/applyconfiguration/camel/v1/traits.go
@@ -39,6 +39,7 @@ type TraitsApplyConfiguration struct {
GC *trait.GCTrait
`json:"gc,omitempty"`
Health *trait.HealthTrait
`json:"health,omitempty"`
Ingress *trait.IngressTrait
`json:"ingress,omitempty"`
+ InitContainers *trait.InitContainersTrait
`json:"init-containers,omitempty"`
Istio *trait.IstioTrait
`json:"istio,omitempty"`
Jolokia *trait.JolokiaTrait
`json:"jolokia,omitempty"`
JVM *trait.JVMTrait
`json:"jvm,omitempty"`
@@ -180,6 +181,14 @@ func (b *TraitsApplyConfiguration) WithIngress(value
trait.IngressTrait) *Traits
return b
}
+// WithInitContainers sets the InitContainers field in the declarative
configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the InitContainers field is set to the value of
the last call.
+func (b *TraitsApplyConfiguration) WithInitContainers(value
trait.InitContainersTrait) *TraitsApplyConfiguration {
+ b.InitContainers = &value
+ return b
+}
+
// WithIstio sets the Istio field in the declarative configuration to the
given value
// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
// If called multiple times, the Istio field is set to the value of the last
call.
diff --git
a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
index dd2a09c1d..3fa5ea073 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
@@ -1259,6 +1259,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -3463,6 +3491,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
diff --git
a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
index 2c10d4958..70b24286d 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
@@ -1127,6 +1127,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -3210,6 +3238,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
index 634f2be68..6a25e9ec8 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
@@ -7545,6 +7545,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
@@ -9571,6 +9599,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed with
format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be executed
with format
+ `<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
diff --git a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
index 5d421f1b1..28c65260d 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
@@ -7597,6 +7597,34 @@ spec:
description: To configure tls secret name
type: string
type: object
+ init-containers:
+ description: The configuration of Init Containers trait
+ properties:
+ auto:
+ description: To automatically enable the trait
+ type: boolean
+ configuration:
+ description: |-
+ Legacy trait configuration parameters.
+ Deprecated: for backward compatibility.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ enabled:
+ description: 'Deprecated: no longer in use.'
+ type: boolean
+ initTasks:
+ description: A list of init tasks to be executed
with
+ format
`<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ sideCarTasks:
+ description: A list of sidecar tasks to be
executed with
+ format
`<name>;<container-image>;<container-command>`.
+ items:
+ type: string
+ type: array
+ type: object
istio:
description: The configuration of Istio trait
properties:
diff --git a/pkg/trait/init_containers.go b/pkg/trait/init_containers.go
new file mode 100644
index 000000000..07a38e900
--- /dev/null
+++ b/pkg/trait/init_containers.go
@@ -0,0 +1,146 @@
+/*
+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 (
+ "fmt"
+ "strings"
+
+ appsv1 "k8s.io/api/apps/v1"
+ batchv1 "k8s.io/api/batch/v1"
+ corev1 "k8s.io/api/core/v1"
+
+ serving "knative.dev/serving/pkg/apis/serving/v1"
+
+ traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+ "k8s.io/utils/ptr"
+)
+
+const (
+ initContainerTraitID = "init-containers"
+ initContainerTraitOrder = 1610
+)
+
+type containerTask struct {
+ name string
+ image string
+ command string
+ isSidecar bool
+}
+
+type initContainersTrait struct {
+ BasePlatformTrait
+ traitv1.InitContainersTrait `property:",squash"`
+
+ tasks []containerTask
+}
+
+func newInitContainersTrait() Trait {
+ return &initContainersTrait{
+ BasePlatformTrait: NewBasePlatformTrait(initContainerTraitID,
initContainerTraitOrder),
+ }
+}
+
+func (t *initContainersTrait) Configure(e *Environment) (bool,
*TraitCondition, error) {
+ if e.Integration == nil || !e.IntegrationInRunningPhases() {
+ return false, nil, nil
+ }
+
+ return t.parseTasks()
+}
+
+func (t *initContainersTrait) Apply(e *Environment) error {
+ var initContainers *[]corev1.Container
+
+ if err := e.Resources.VisitDeploymentE(func(deployment
*appsv1.Deployment) error {
+ // Deployment
+ initContainers = &deployment.Spec.Template.Spec.InitContainers
+ return nil
+ }); err != nil {
+ return err
+ } else if err := e.Resources.VisitKnativeServiceE(func(service
*serving.Service) error {
+ // Knative Service
+ initContainers =
&service.Spec.ConfigurationSpec.Template.Spec.InitContainers
+ return nil
+ }); err != nil {
+ return err
+ } else if err := e.Resources.VisitCronJobE(func(cron *batchv1.CronJob)
error {
+ // CronJob
+ initContainers =
&cron.Spec.JobTemplate.Spec.Template.Spec.InitContainers
+ return nil
+ }); err != nil {
+ return err
+ }
+
+ t.configureContainers(initContainers)
+
+ return nil
+}
+
+func (t *initContainersTrait) configureContainers(containers
*[]corev1.Container) {
+ if containers == nil {
+ containers = &[]corev1.Container{}
+ }
+ for _, task := range t.tasks {
+ initCont := corev1.Container{
+ Name: task.name,
+ Image: task.image,
+ Command: splitContainerCommand(task.command),
+ }
+ if task.isSidecar {
+ initCont.RestartPolicy =
ptr.To(corev1.ContainerRestartPolicyAlways)
+ }
+ *containers = append(*containers, initCont)
+ }
+}
+
+func (t *initContainersTrait) parseTasks() (bool, *TraitCondition, error) {
+ if t.InitTasks == nil && t.SidecarTasks == nil {
+ return false, nil, nil
+ }
+ t.tasks = make([]containerTask, len(t.InitTasks)+len(t.SidecarTasks))
+ i := 0
+ for _, task := range t.InitTasks {
+ split := strings.SplitN(task, ";", 3)
+ if len(split) != 3 {
+ return false, nil, fmt.Errorf(`could not parse init
container task "%s": format expected "name;container-image;command"`, task)
+ }
+ t.tasks[i] = containerTask{
+ name: split[0],
+ image: split[1],
+ command: split[2],
+ isSidecar: false,
+ }
+ i++
+ }
+ for _, task := range t.SidecarTasks {
+ split := strings.SplitN(task, ";", 3)
+ if len(split) != 3 {
+ return false, nil, fmt.Errorf(`could not parse sidecar
container task "%s": format expected "name;container-image;command"`, task)
+ }
+ t.tasks[i] = containerTask{
+ name: split[0],
+ image: split[1],
+ command: split[2],
+ isSidecar: true,
+ }
+ i++
+ }
+
+ return true, nil, nil
+}
diff --git a/pkg/trait/init_containers_test.go
b/pkg/trait/init_containers_test.go
new file mode 100644
index 000000000..3cb4ed886
--- /dev/null
+++ b/pkg/trait/init_containers_test.go
@@ -0,0 +1,287 @@
+/*
+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 (
+ "testing"
+
+ v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+ "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+ "github.com/apache/camel-k/v2/pkg/util/kubernetes"
+ "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/ptr"
+)
+
+func TestParseInitContainerNoIntegration(t *testing.T) {
+ environment := Environment{
+ Resources: kubernetes.NewCollection(),
+ }
+ initCont := newInitContainersTrait()
+ configured, condition, err := initCont.Configure(&environment)
+ assert.False(t, configured, "Should not be configured, Integration is
nil")
+ assert.Nil(t, condition, "should be nil")
+ assert.Nil(t, err, "should be nil")
+}
+
+func TestParseInitContainerShouldFail(t *testing.T) {
+ environment := Environment{
+ Resources: kubernetes.NewCollection(),
+ Integration: &v1.Integration{
+ Status: v1.IntegrationStatus{
+ Phase: v1.IntegrationPhaseRunning,
+ },
+ },
+ }
+ initCont := initContainersTrait{
+ InitContainersTrait: trait.InitContainersTrait{
+ InitTasks: []string{
+ "not a valid format",
+ },
+ },
+ }
+ configured, condition, err := initCont.Configure(&environment)
+ assert.False(t, configured, "Should not be configured, there's an
error")
+ assert.Nil(t, condition)
+ assert.NotNil(t, err)
+ assert.Equal(t, `could not parse init container task "not a valid
format": format expected "name;container-image;command"`, err.Error())
+}
+
+func TestParseInitContainerOK(t *testing.T) {
+ environment := Environment{
+ Resources: kubernetes.NewCollection(),
+ Integration: &v1.Integration{
+ Status: v1.IntegrationStatus{
+ Phase: v1.IntegrationPhaseRunning,
+ },
+ },
+ }
+ initCont := initContainersTrait{
+ InitContainersTrait: trait.InitContainersTrait{
+ InitTasks: []string{
+ "agent;my-agent-image:1.2.3;echo \"hello\"",
+ "more thing;my-image;echo \"hello\" &&
something else",
+ },
+ },
+ }
+ configured, condition, err := initCont.Configure(&environment)
+ assert.True(t, configured)
+ assert.Nil(t, condition)
+ require.Nil(t, err)
+ require.Len(t, initCont.tasks, 2)
+ assert.Equal(t, "agent", initCont.tasks[0].name)
+ assert.Equal(t, "my-agent-image:1.2.3", initCont.tasks[0].image)
+ assert.Equal(t, "echo \"hello\"", initCont.tasks[0].command)
+ assert.Equal(t, "more thing", initCont.tasks[1].name)
+ assert.Equal(t, "my-image", initCont.tasks[1].image)
+ assert.Equal(t, "echo \"hello\" && something else",
initCont.tasks[1].command)
+}
+
+func TestParseInitContainerDefault(t *testing.T) {
+ environment := Environment{
+ Resources: kubernetes.NewCollection(),
+ Integration: &v1.Integration{
+ Status: v1.IntegrationStatus{
+ Phase: v1.IntegrationPhaseRunning,
+ },
+ },
+ }
+ initCont := initContainersTrait{}
+ configured, condition, err := initCont.Configure(&environment)
+ assert.False(t, configured)
+ assert.Nil(t, condition)
+ require.Nil(t, err)
+}
+
+func TestApplyInitContainerOK(t *testing.T) {
+ environment := Environment{
+ Resources: kubernetes.NewCollection(),
+ Integration: &v1.Integration{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-it",
+ },
+ Status: v1.IntegrationStatus{
+ Phase: v1.IntegrationPhaseRunning,
+ },
+ },
+ }
+ environment.Resources.Add(&appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{
+ v1.IntegrationLabel: "my-it",
+ },
+ },
+ Spec: appsv1.DeploymentSpec{
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{},
+ },
+ },
+ })
+ initCont := initContainersTrait{
+ InitContainersTrait: trait.InitContainersTrait{
+ InitTasks: []string{
+ "agent;my-agent-image:1.2.3;echo hello",
+ },
+ },
+ }
+ configured, condition, err := initCont.Configure(&environment)
+ assert.True(t, configured)
+ assert.Nil(t, condition)
+ require.Nil(t, err)
+ err = initCont.Apply(&environment)
+ require.Nil(t, err)
+ deploy :=
environment.Resources.GetDeploymentForIntegration(environment.Integration)
+ require.NotNil(t, deploy)
+
+ require.Len(t, deploy.Spec.Template.Spec.InitContainers, 1)
+ assert.Equal(t, "agent",
deploy.Spec.Template.Spec.InitContainers[0].Name)
+ assert.Equal(t, "my-agent-image:1.2.3",
deploy.Spec.Template.Spec.InitContainers[0].Image)
+ assert.Equal(t, []string{"echo", "hello"},
deploy.Spec.Template.Spec.InitContainers[0].Command)
+ assert.NotEqual(t, ptr.To(corev1.ContainerRestartPolicyAlways),
deploy.Spec.Template.Spec.InitContainers[0].RestartPolicy)
+}
+
+func TestApplyInitContainerSidecarOK(t *testing.T) {
+ environment := Environment{
+ Resources: kubernetes.NewCollection(),
+ Integration: &v1.Integration{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-it",
+ },
+ Status: v1.IntegrationStatus{
+ Phase: v1.IntegrationPhaseRunning,
+ },
+ },
+ }
+ environment.Resources.Add(&appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{
+ v1.IntegrationLabel: "my-it",
+ },
+ },
+ Spec: appsv1.DeploymentSpec{
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{},
+ },
+ },
+ })
+ initCont := initContainersTrait{
+ InitContainersTrait: trait.InitContainersTrait{
+ SidecarTasks: []string{
+ "agent;my-agent-image:1.2.3;echo hello",
+ },
+ },
+ }
+ configured, condition, err := initCont.Configure(&environment)
+ assert.True(t, configured)
+ assert.Nil(t, condition)
+ require.Nil(t, err)
+ err = initCont.Apply(&environment)
+ require.Nil(t, err)
+ deploy :=
environment.Resources.GetDeploymentForIntegration(environment.Integration)
+ require.NotNil(t, deploy)
+
+ require.Len(t, deploy.Spec.Template.Spec.InitContainers, 1)
+ assert.Equal(t, "agent",
deploy.Spec.Template.Spec.InitContainers[0].Name)
+ assert.Equal(t, "my-agent-image:1.2.3",
deploy.Spec.Template.Spec.InitContainers[0].Image)
+ assert.Equal(t, []string{"echo", "hello"},
deploy.Spec.Template.Spec.InitContainers[0].Command)
+ assert.Equal(t, ptr.To(corev1.ContainerRestartPolicyAlways),
deploy.Spec.Template.Spec.InitContainers[0].RestartPolicy)
+}
+
+func TestApplyInitContainerAndSidecarOK(t *testing.T) {
+ environment := Environment{
+ Resources: kubernetes.NewCollection(),
+ Integration: &v1.Integration{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-it",
+ },
+ Status: v1.IntegrationStatus{
+ Phase: v1.IntegrationPhaseRunning,
+ },
+ },
+ }
+ environment.Resources.Add(&appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{
+ v1.IntegrationLabel: "my-it",
+ },
+ },
+ Spec: appsv1.DeploymentSpec{
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{},
+ },
+ },
+ })
+ initCont := initContainersTrait{
+ InitContainersTrait: trait.InitContainersTrait{
+ SidecarTasks: []string{
+ "sidecar;my-agent-image:1.2.3;echo sidecar",
+ },
+ InitTasks: []string{
+ "init;my-agent-image:3.2.1;echo init",
+ },
+ },
+ }
+ configured, condition, err := initCont.Configure(&environment)
+ assert.True(t, configured)
+ assert.Nil(t, condition)
+ require.Nil(t, err)
+ err = initCont.Apply(&environment)
+ require.Nil(t, err)
+ deploy :=
environment.Resources.GetDeploymentForIntegration(environment.Integration)
+ require.NotNil(t, deploy)
+
+ require.Len(t, deploy.Spec.Template.Spec.InitContainers, 2)
+ assert.Contains(t, deploy.Spec.Template.Spec.InitContainers,
corev1.Container{
+ Name: "sidecar",
+ Image: "my-agent-image:1.2.3",
+ Command: []string{"echo", "sidecar"},
+ RestartPolicy: ptr.To(corev1.ContainerRestartPolicyAlways),
+ })
+ assert.Contains(t, deploy.Spec.Template.Spec.InitContainers,
corev1.Container{
+ Name: "init",
+ Image: "my-agent-image:3.2.1",
+ Command: []string{"echo", "init"},
+ RestartPolicy: nil,
+ })
+}
+
+func TestParseTasks(t *testing.T) {
+ trait := &initContainersTrait{
+ InitContainersTrait: trait.InitContainersTrait{
+ InitTasks: []string{"name;image;init-command"},
+ SidecarTasks:
[]string{"name;image;sidecar-command;done"},
+ },
+ }
+
+ trait.parseTasks()
+ assert.Contains(t, trait.tasks, containerTask{
+ name: "name",
+ image: "image",
+ command: "init-command",
+ isSidecar: false,
+ })
+ assert.Contains(t, trait.tasks, containerTask{
+ name: "name",
+ image: "image",
+ command: "sidecar-command;done",
+ isSidecar: true,
+ })
+}
diff --git a/pkg/trait/mount.go b/pkg/trait/mount.go
index 65247e11e..f76cfe191 100644
--- a/pkg/trait/mount.go
+++ b/pkg/trait/mount.go
@@ -44,7 +44,7 @@ import (
const (
mountTraitID = "mount"
- mountTraitOrder = 1610
+ mountTraitOrder = 1620
)
type mountTrait struct {
@@ -54,7 +54,7 @@ type mountTrait struct {
func newMountTrait() Trait {
return &mountTrait{
- // Must follow immediately the container trait
+ // Must follow immediately the container and init-containers
trait
BasePlatformTrait: NewBasePlatformTrait(mountTraitID,
mountTraitOrder),
}
}
@@ -86,11 +86,13 @@ func (t *mountTrait) Apply(e *Environment) error {
}
var volumes *[]corev1.Volume
+ var initContainers *[]corev1.Container
visited := false
// Deployment
if err := e.Resources.VisitDeploymentE(func(deployment
*appsv1.Deployment) error {
volumes = &deployment.Spec.Template.Spec.Volumes
+ initContainers = &deployment.Spec.Template.Spec.InitContainers
visited = true
return nil
}); err != nil {
@@ -100,6 +102,7 @@ func (t *mountTrait) Apply(e *Environment) error {
// Knative Service
if err := e.Resources.VisitKnativeServiceE(func(service
*serving.Service) error {
volumes = &service.Spec.ConfigurationSpec.Template.Spec.Volumes
+ initContainers =
&service.Spec.ConfigurationSpec.Template.Spec.InitContainers
visited = true
return nil
}); err != nil {
@@ -109,6 +112,7 @@ func (t *mountTrait) Apply(e *Environment) error {
// CronJob
if err := e.Resources.VisitCronJobE(func(cron *batchv1.CronJob) error {
volumes = &cron.Spec.JobTemplate.Spec.Template.Spec.Volumes
+ initContainers =
&cron.Spec.JobTemplate.Spec.Template.Spec.InitContainers
visited = true
return nil
}); err != nil {
@@ -119,7 +123,7 @@ func (t *mountTrait) Apply(e *Environment) error {
// Volumes declared in the trait config/resource options
// as this func influences the application.properties
// must be set as the first one to execute
- err := t.configureVolumesAndMounts(e, volumes,
&container.VolumeMounts)
+ err := t.configureVolumesAndMounts(e, volumes,
&container.VolumeMounts, initContainers)
if err != nil {
return err
}
@@ -138,7 +142,13 @@ func (t *mountTrait) Apply(e *Environment) error {
}
// configureVolumesAndMounts is in charge to mount volumes and mounts coming
from the trait configuration.
-func (t *mountTrait) configureVolumesAndMounts(e *Environment, vols
*[]corev1.Volume, mnts *[]corev1.VolumeMount) error {
+// icnts holds the InitContainers which also require to be mounted with the
shared volumes.
+func (t *mountTrait) configureVolumesAndMounts(
+ e *Environment,
+ vols *[]corev1.Volume,
+ mnts *[]corev1.VolumeMount,
+ icnts *[]corev1.Container,
+) error {
for _, c := range t.Configs {
if conf, parseErr := utilResource.ParseConfig(c); parseErr ==
nil {
// Let Camel parse these resources as properties
@@ -162,6 +172,9 @@ func (t *mountTrait) configureVolumesAndMounts(e
*Environment, vols *[]corev1.Vo
}
*vols = append(*vols, *volume)
*mnts = append(*mnts, *volumeMount)
+ for i := range *icnts {
+ (*icnts)[i].VolumeMounts =
append((*icnts)[i].VolumeMounts, *volumeMount)
+ }
}
for _, v := range t.EmptyDirs {
volume, volumeMount, parseErr := ParseEmptyDirVolume(v)
@@ -170,6 +183,9 @@ func (t *mountTrait) configureVolumesAndMounts(e
*Environment, vols *[]corev1.Vo
}
*vols = append(*vols, *volume)
*mnts = append(*mnts, *volumeMount)
+ for i := range *icnts {
+ (*icnts)[i].VolumeMounts =
append((*icnts)[i].VolumeMounts, *volumeMount)
+ }
}
return nil
diff --git a/pkg/trait/mount_test.go b/pkg/trait/mount_test.go
index d1c624056..56c477ac4 100644
--- a/pkg/trait/mount_test.go
+++ b/pkg/trait/mount_test.go
@@ -558,3 +558,37 @@ func TestConfigureVolumesAndMountsSourcesInNativeMode(t
*testing.T) {
m = findVVolumeMount(mnts, func(m corev1.VolumeMount) bool { return
m.Name == v.Name })
assert.NotNil(t, m)
}
+
+func TestMountVolumesInitContainers(t *testing.T) {
+ traitCatalog := NewCatalog(nil)
+ environment := getNominalEnv(t, traitCatalog)
+ // We must provide some init container
+ environment.Integration.Spec.Traits.InitContainers =
&traitv1.InitContainersTrait{
+ InitTasks: []string{"init;my-init-image:1.2.3;echo hello"},
+ }
+ environment.Platform.ResyncStatusFullConfig()
+ conditions, traits, err := traitCatalog.apply(environment)
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, traits)
+ assert.NotEmpty(t, conditions)
+ assert.NotEmpty(t, environment.ExecutedTraits)
+ assert.NotNil(t, environment.GetTrait("mount"))
+
+ s := environment.Resources.GetDeployment(func(service
*appsv1.Deployment) bool {
+ return service.Name == "hello"
+ })
+ assert.NotNil(t, s)
+ spec := s.Spec.Template.Spec
+
+ assert.Len(t, spec.InitContainers[0].VolumeMounts, 1)
+
+ assert.Condition(t, func() bool {
+ for _, v := range spec.InitContainers[0].VolumeMounts {
+ if v.Name == "my-pvc" {
+ return true
+ }
+ }
+ return false
+ })
+}
diff --git a/pkg/trait/trait_register.go b/pkg/trait/trait_register.go
index f5944fd16..e268a6e4c 100644
--- a/pkg/trait/trait_register.go
+++ b/pkg/trait/trait_register.go
@@ -32,6 +32,7 @@ func init() {
AddToTraits(newGCTrait)
AddToTraits(newGitTrait)
AddToTraits(newHealthTrait)
+ AddToTraits(newInitContainersTrait)
AddToTraits(NewInitTrait)
AddToTraits(newIngressTrait)
AddToTraits(newIstioTrait)
diff --git a/pkg/trait/trait_test.go b/pkg/trait/trait_test.go
index f7b692d36..13c92a304 100644
--- a/pkg/trait/trait_test.go
+++ b/pkg/trait/trait_test.go
@@ -193,7 +193,7 @@ func TestOnlySomeTraitsArePlatform(t *testing.T) {
c := NewTraitTestCatalog()
platformTraits := []string{
"builder", "camel", "jvm", "runtime", "container",
"security-context", "mount", "dependencies", "deployer",
- "deployment", "environment", "error-handler", "kamelets",
"openapi", "owner", "platform", "quarkus",
+ "deployment", "environment", "error-handler",
"init-containers", "kamelets", "openapi", "owner", "platform", "quarkus",
}
for _, trait := range c.AllTraits() {