From 0f30d7314eba51cbd4ed6160a51ab4ee92428782 Mon Sep 17 00:00:00 2001 From: Gaelle Fournier Date: Mon, 10 Jul 2023 18:13:16 +0200 Subject: [PATCH] feat(trait): Add maven profile to Integration in builder trait Ref #4560 * Add builder.maven-profile property referencing a secret or a configmap * Inject the given profile into the pom.xml generated * Some refactoring on configmap/secret decoding from cli --- config/crd/bases/camel.apache.org_builds.yaml | 44 ++++++++ .../camel.apache.org_integrationkits.yaml | 10 ++ ...camel.apache.org_integrationplatforms.yaml | 104 ++++++++++++++++++ .../bases/camel.apache.org_integrations.yaml | 10 ++ .../camel.apache.org_kameletbindings.yaml | 11 ++ config/crd/bases/camel.apache.org_pipes.yaml | 11 ++ .../ROOT/partials/apis/camel-k-crds.adoc | 17 +++ docs/modules/traits/pages/builder.adoc | 6 + e2e/common/traits/builder_test.go | 78 +++++++++++++ helm/camel-k/crds/crd-build.yaml | 44 ++++++++ helm/camel-k/crds/crd-integration-kit.yaml | 10 ++ .../crds/crd-integration-platform.yaml | 104 ++++++++++++++++++ helm/camel-k/crds/crd-integration.yaml | 10 ++ helm/camel-k/crds/crd-kamelet-binding.yaml | 11 ++ helm/camel-k/crds/crd-pipe.yaml | 11 ++ pkg/apis/camel/v1/common_types_support.go | 45 ++++++++ .../camel/v1/common_types_support_test.go | 84 ++++++++++++++ pkg/apis/camel/v1/maven_types.go | 3 + pkg/apis/camel/v1/trait/builder.go | 4 + pkg/apis/camel/v1/zz_generated.deepcopy.go | 1 + pkg/builder/project.go | 14 +++ .../camel/v1/mavenbuildspec.go | 8 ++ .../applyconfiguration/camel/v1/mavenspec.go | 9 ++ pkg/cmd/install.go | 3 +- pkg/trait/builder.go | 10 ++ pkg/trait/builder_test.go | 19 ++++ pkg/util/maven/maven_project.go | 4 + pkg/util/maven/maven_project_test.go | 3 + pkg/util/maven/maven_types.go | 5 + resources/traits.yaml | 8 ++ 30 files changed, 700 insertions(+), 1 deletion(-) diff --git a/config/crd/bases/camel.apache.org_builds.yaml b/config/crd/bases/camel.apache.org_builds.yaml index f7947276d4..1c136fc3a7 100644 --- a/config/crd/bases/camel.apache.org_builds.yaml +++ b/config/crd/bases/camel.apache.org_builds.yaml @@ -310,6 +310,50 @@ spec: localRepository: description: The path of the local Maven repository. type: string + profile: + description: A reference to the ConfigMap or Secret + key that contains the Maven profile. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + secretKeyRef: + description: Selects a key of a secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object properties: additionalProperties: type: string diff --git a/config/crd/bases/camel.apache.org_integrationkits.yaml b/config/crd/bases/camel.apache.org_integrationkits.yaml index c86813bc5c..d34ca382cb 100644 --- a/config/crd/bases/camel.apache.org_integrationkits.yaml +++ b/config/crd/bases/camel.apache.org_integrationkits.yaml @@ -211,6 +211,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/config/crd/bases/camel.apache.org_integrationplatforms.yaml b/config/crd/bases/camel.apache.org_integrationplatforms.yaml index 6f3b9d984c..c96606c877 100644 --- a/config/crd/bases/camel.apache.org_integrationplatforms.yaml +++ b/config/crd/bases/camel.apache.org_integrationplatforms.yaml @@ -202,6 +202,48 @@ spec: localRepository: description: The path of the local Maven repository. type: string + profile: + description: A reference to the ConfigMap or Secret key that + contains the Maven profile. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + secretKeyRef: + description: Selects a key of a secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + type: object properties: additionalProperties: type: string @@ -469,6 +511,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) @@ -1850,6 +1902,48 @@ spec: localRepository: description: The path of the local Maven repository. type: string + profile: + description: A reference to the ConfigMap or Secret key that + contains the Maven profile. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + secretKeyRef: + description: Selects a key of a secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + type: object properties: additionalProperties: type: string @@ -2165,6 +2259,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/config/crd/bases/camel.apache.org_integrations.yaml b/config/crd/bases/camel.apache.org_integrations.yaml index 8f460495d4..3fa150b039 100644 --- a/config/crd/bases/camel.apache.org_integrations.yaml +++ b/config/crd/bases/camel.apache.org_integrations.yaml @@ -6194,6 +6194,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/config/crd/bases/camel.apache.org_kameletbindings.yaml b/config/crd/bases/camel.apache.org_kameletbindings.yaml index ef1cdf18e2..03d3caab74 100644 --- a/config/crd/bases/camel.apache.org_kameletbindings.yaml +++ b/config/crd/bases/camel.apache.org_kameletbindings.yaml @@ -6469,6 +6469,17 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret + that contains a maven profile. The content of the maven + profile is expected to be a text containing a valid + maven profile starting with `` and ending with + `` that will be integrated as an inline profile + in the POM. Syntax: [configmap|secret]:name[/key], where + name represents the resource name, key optionally represents + the resource key to be filtered (default key value = + profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/config/crd/bases/camel.apache.org_pipes.yaml b/config/crd/bases/camel.apache.org_pipes.yaml index bc442ac3ae..067f9de2af 100644 --- a/config/crd/bases/camel.apache.org_pipes.yaml +++ b/config/crd/bases/camel.apache.org_pipes.yaml @@ -6466,6 +6466,17 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret + that contains a maven profile. The content of the maven + profile is expected to be a text containing a valid + maven profile starting with `` and ending with + `` that will be integrated as an inline profile + in the POM. Syntax: [configmap|secret]:name[/key], where + name represents the resource name, key optionally represents + the resource key to be filtered (default key value = + profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index c922052faf..752e05983a 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -3836,6 +3836,14 @@ map[string]string The Maven properties. +|`profile` + +*xref:#_camel_apache_org_v1_ValueSource[ValueSource]* +| + + +A reference to the ConfigMap or Secret key that contains +the Maven profile. + |`settings` + *xref:#_camel_apache_org_v1_ValueSource[ValueSource]* | @@ -5442,6 +5450,15 @@ string When using `pod` strategy, the maximum amount of memory required by the pod builder. +|`mavenProfile` + +string +| + + +A reference pointing to a configmap/secret that contains a maven profile. +The content of the maven profile is expected to be a text containing a valid maven profile starting with `` and ending with `` that will be integrated as an inline profile in the POM. +Syntax: [configmap{vbar}secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = profile.xml). + |`tasks` + []string | diff --git a/docs/modules/traits/pages/builder.adoc b/docs/modules/traits/pages/builder.adoc index e2254e9cec..b9d9edf599 100755 --- a/docs/modules/traits/pages/builder.adoc +++ b/docs/modules/traits/pages/builder.adoc @@ -60,6 +60,12 @@ The following configuration options are available: | string | When using `pod` strategy, the maximum amount of memory required by the pod builder. +| builder.maven-profile +| string +| A reference pointing to a configmap/secret that contains a maven profile. +The content of the maven profile is expected to be a text containing a valid maven profile starting with `` and ending with `` that will be integrated as an inline profile in the POM. +Syntax: [configmap\|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = profile.xml). + | builder.tasks | []string | A list of tasks to be executed (available only when using `pod` strategy) with format ;; diff --git a/e2e/common/traits/builder_test.go b/e2e/common/traits/builder_test.go index 6d7f7f2e64..c1e9ed492a 100644 --- a/e2e/common/traits/builder_test.go +++ b/e2e/common/traits/builder_test.go @@ -29,6 +29,7 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" . "github.com/apache/camel-k/v2/e2e/support" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" @@ -224,4 +225,81 @@ func TestBuilderTrait(t *testing.T) { Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed()) }) + + t.Run("Run maven profile", func(t *testing.T) { + name := "java-maven-profile" + + mavenProfileCm := newMavenProfileConfigMap(ns, "maven-profile", "owasp-profile") + Expect(TestClient().Create(TestContext, mavenProfileCm)).To(Succeed()) + + Expect(KamelRunWithID(operatorID, ns, "files/Java.java", + "--name", name, + "-t", "builder.maven-profile=configmap:maven-profile/owasp-profile", + "-t", "builder.tasks=custom1;alpine;cat maven/pom.xml", + "-t", "builder.strategy=pod", + ).Execute()).To(Succeed()) + + Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning)) + Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutLong).Should(Equal(corev1.ConditionTrue)) + Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Magicstring!")) + + integrationKitName := IntegrationKit(ns, name)() + builderKitName := fmt.Sprintf("camel-k-%s-builder", integrationKitName) + Eventually(BuilderPod(ns, builderKitName), TestTimeoutShort).ShouldNot(BeNil()) + Eventually(len(BuilderPod(ns, builderKitName)().Spec.InitContainers), TestTimeoutShort).Should(Equal(2)) + Eventually(BuilderPod(ns, builderKitName)().Spec.InitContainers[0].Name, TestTimeoutShort).Should(Equal("builder")) + Eventually(BuilderPod(ns, builderKitName)().Spec.InitContainers[1].Name, TestTimeoutShort).Should(Equal("custom1")) + + // Check containers conditions + Eventually(Build(ns, integrationKitName), TestTimeoutShort).ShouldNot(BeNil()) + Eventually( + Build(ns, integrationKitName)().Status.GetCondition(v1.BuildConditionType("Container custom1 succeeded")).Status, + TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + Eventually( + Build(ns, integrationKitName)().Status.GetCondition(v1.BuildConditionType("Container custom1 succeeded")).Message, + TestTimeoutShort).Should(ContainSubstring("")) + + // Check logs + Eventually(Logs(ns, builderKitName, corev1.PodLogOptions{Container: "custom1"})).Should(ContainSubstring(`owasp-dependency-check`)) + + Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed()) + Expect(TestClient().Delete(TestContext, mavenProfileCm)).To(Succeed()) + }) +} + +func newMavenProfileConfigMap(ns, name, key string) *corev1.ConfigMap { + return &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: corev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: name, + }, + Data: map[string]string{ + key: fmt.Sprintf(` + + owasp-dependency-check + + + + org.owasp + dependency-check-maven + 5.3.0 + + + + check + + + + + + + +`, + ), + }, + } } diff --git a/helm/camel-k/crds/crd-build.yaml b/helm/camel-k/crds/crd-build.yaml index f7947276d4..1c136fc3a7 100644 --- a/helm/camel-k/crds/crd-build.yaml +++ b/helm/camel-k/crds/crd-build.yaml @@ -310,6 +310,50 @@ spec: localRepository: description: The path of the local Maven repository. type: string + profile: + description: A reference to the ConfigMap or Secret + key that contains the Maven profile. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + secretKeyRef: + description: Selects a key of a secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + type: object properties: additionalProperties: type: string diff --git a/helm/camel-k/crds/crd-integration-kit.yaml b/helm/camel-k/crds/crd-integration-kit.yaml index c86813bc5c..d34ca382cb 100644 --- a/helm/camel-k/crds/crd-integration-kit.yaml +++ b/helm/camel-k/crds/crd-integration-kit.yaml @@ -211,6 +211,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/helm/camel-k/crds/crd-integration-platform.yaml b/helm/camel-k/crds/crd-integration-platform.yaml index 6f3b9d984c..c96606c877 100644 --- a/helm/camel-k/crds/crd-integration-platform.yaml +++ b/helm/camel-k/crds/crd-integration-platform.yaml @@ -202,6 +202,48 @@ spec: localRepository: description: The path of the local Maven repository. type: string + profile: + description: A reference to the ConfigMap or Secret key that + contains the Maven profile. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + secretKeyRef: + description: Selects a key of a secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + type: object properties: additionalProperties: type: string @@ -469,6 +511,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) @@ -1850,6 +1902,48 @@ spec: localRepository: description: The path of the local Maven repository. type: string + profile: + description: A reference to the ConfigMap or Secret key that + contains the Maven profile. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + secretKeyRef: + description: Selects a key of a secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + type: object properties: additionalProperties: type: string @@ -2165,6 +2259,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/helm/camel-k/crds/crd-integration.yaml b/helm/camel-k/crds/crd-integration.yaml index 8f460495d4..3fa150b039 100644 --- a/helm/camel-k/crds/crd-integration.yaml +++ b/helm/camel-k/crds/crd-integration.yaml @@ -6194,6 +6194,16 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret that + contains a maven profile. The content of the maven profile + is expected to be a text containing a valid maven profile + starting with `` and ending with `` that + will be integrated as an inline profile in the POM. Syntax: + [configmap|secret]:name[/key], where name represents the + resource name, key optionally represents the resource key + to be filtered (default key value = profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml b/helm/camel-k/crds/crd-kamelet-binding.yaml index ef1cdf18e2..03d3caab74 100644 --- a/helm/camel-k/crds/crd-kamelet-binding.yaml +++ b/helm/camel-k/crds/crd-kamelet-binding.yaml @@ -6469,6 +6469,17 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret + that contains a maven profile. The content of the maven + profile is expected to be a text containing a valid + maven profile starting with `` and ending with + `` that will be integrated as an inline profile + in the POM. Syntax: [configmap|secret]:name[/key], where + name represents the resource name, key optionally represents + the resource key to be filtered (default key value = + profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/helm/camel-k/crds/crd-pipe.yaml b/helm/camel-k/crds/crd-pipe.yaml index bc442ac3ae..067f9de2af 100644 --- a/helm/camel-k/crds/crd-pipe.yaml +++ b/helm/camel-k/crds/crd-pipe.yaml @@ -6466,6 +6466,17 @@ spec: description: When using `pod` strategy, the maximum amount of memory required by the pod builder. type: string + mavenProfile: + description: 'A reference pointing to a configmap/secret + that contains a maven profile. The content of the maven + profile is expected to be a text containing a valid + maven profile starting with `` and ending with + `` that will be integrated as an inline profile + in the POM. Syntax: [configmap|secret]:name[/key], where + name represents the resource name, key optionally represents + the resource key to be filtered (default key value = + profile.xml).' + type: string orderStrategy: description: The build order strategy to use, either `dependencies`, `fifo` or `sequential` (default sequential) diff --git a/pkg/apis/camel/v1/common_types_support.go b/pkg/apis/camel/v1/common_types_support.go index 6b48170d34..029d4ba67c 100644 --- a/pkg/apis/camel/v1/common_types_support.go +++ b/pkg/apis/camel/v1/common_types_support.go @@ -21,8 +21,10 @@ import ( "encoding/json" "errors" "fmt" + "regexp" "strings" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/imdario/mergo" @@ -165,3 +167,46 @@ func (bc *BuildConfiguration) IsEmpty() bool { bc.LimitCPU == "" && bc.LimitMemory == "" } + +// DecodeValueSource returns a ValueSource object from an input that respects the format configmap|secret:resource-name[/path]. +func DecodeValueSource(input string, defaultKey string, errorMessage string) (ValueSource, error) { + sub := make([]string, 0) + rex := regexp.MustCompile(`^(configmap|secret):([a-zA-Z0-9][a-zA-Z0-9-]*)(/([a-zA-Z0-9].*))?$`) + hits := rex.FindAllStringSubmatch(input, -1) + + for _, hit := range hits { + if len(hit) > 1 { + sub = append(sub, hit[1:]...) + } + } + + if len(sub) >= 2 { + key := defaultKey + if len(sub) == 4 && sub[3] != "" { + key = sub[3] + } + + if sub[0] == "configmap" { + return ValueSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sub[1], + }, + Key: key, + }, + }, nil + } + if sub[0] == "secret" { + return ValueSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: sub[1], + }, + Key: key, + }, + }, nil + } + } + + return ValueSource{}, fmt.Errorf(errorMessage) +} diff --git a/pkg/apis/camel/v1/common_types_support_test.go b/pkg/apis/camel/v1/common_types_support_test.go index a5ff495720..934c870b96 100644 --- a/pkg/apis/camel/v1/common_types_support_test.go +++ b/pkg/apis/camel/v1/common_types_support_test.go @@ -19,6 +19,7 @@ package v1 import ( "encoding/json" + "fmt" "testing" "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" @@ -106,6 +107,89 @@ func TestTraitsMerge(t *testing.T) { t1.Addons["telemetry"]) } +func TestDecodeValueSourceValid(t *testing.T) { + res, err := DecodeValueSource("configmap:my-configmap", "defaultkey", "errorMessage") + require.NoError(t, err) + + assert.NotNil(t, res) + assert.Nil(t, res.SecretKeyRef) + assert.NotNil(t, res.ConfigMapKeyRef) + assert.Equal(t, "defaultkey", res.ConfigMapKeyRef.Key) + + res, err = DecodeValueSource("configmap:my-configmap/my-key", "defaultkey", "errorMessage") + require.NoError(t, err) + + assert.NotNil(t, res) + assert.Nil(t, res.SecretKeyRef) + assert.NotNil(t, res.ConfigMapKeyRef) + assert.Equal(t, "my-key", res.ConfigMapKeyRef.Key) + + res, err = DecodeValueSource("secret:my-secret/mykey", "defaultkey", "errorMessage") + require.NoError(t, err) + + assert.NotNil(t, res) + assert.Nil(t, res.ConfigMapKeyRef) + assert.NotNil(t, res.SecretKeyRef) + assert.Equal(t, "mykey", res.SecretKeyRef.Key) + + res, err = DecodeValueSource("secret:my-secret", "defaultkey", "errorMessage") + require.NoError(t, err) + + assert.NotNil(t, res) + assert.Nil(t, res.ConfigMapKeyRef) + assert.NotNil(t, res.SecretKeyRef) + assert.Equal(t, "defaultkey", res.SecretKeyRef.Key) +} + +func TestDecodeValueSourceInvalid(t *testing.T) { + testcases := []struct { + name string + input string + defaultKey string + errorMessage string + }{ + { + name: "invalidResource", + input: "invalid:my-resource", + defaultKey: "defaultKey", + errorMessage: "invalidResource", + }, + { + name: "noResourceName", + input: "secret:", + defaultKey: "defaultKey", + errorMessage: "noResourceName", + }, + { + name: "invalidResourceName", + input: "configmap:***", + defaultKey: "defaultKey", + errorMessage: "errorMessage", + }, + { + name: "invalidResourceKey", + input: "configmap:my-cm/-", + defaultKey: "defaultKey", + errorMessage: "invalidResourceKey", + }, + { + name: "invalidResourceNameWithKey", + input: "configmap:/my-key", + defaultKey: "defaultKey", + errorMessage: "invalidResourceNameWithKey", + }} + + for i, tc := range testcases { + t.Run(fmt.Sprintf("test-%d-%s", i, tc.name), func(t *testing.T) { + res, err := DecodeValueSource(tc.input, tc.defaultKey, tc.errorMessage) + assert.NotNil(t, err) + assert.Equal(t, ValueSource{}, res) + assert.Equal(t, err.Error(), tc.errorMessage) + }) + } + +} + func configurationFromMap(t *testing.T, configMap map[string]interface{}) *trait.Configuration { t.Helper() diff --git a/pkg/apis/camel/v1/maven_types.go b/pkg/apis/camel/v1/maven_types.go index 378d7cfc49..66101d2026 100644 --- a/pkg/apis/camel/v1/maven_types.go +++ b/pkg/apis/camel/v1/maven_types.go @@ -30,6 +30,9 @@ type MavenSpec struct { // The Maven properties. Properties map[string]string `json:"properties,omitempty"` // A reference to the ConfigMap or Secret key that contains + // the Maven profile. + Profile ValueSource `json:"profile,omitempty"` + // A reference to the ConfigMap or Secret key that contains // the Maven settings. Settings ValueSource `json:"settings,omitempty"` // A reference to the ConfigMap or Secret key that contains diff --git a/pkg/apis/camel/v1/trait/builder.go b/pkg/apis/camel/v1/trait/builder.go index 044b9a39c9..dd4fa05c7e 100644 --- a/pkg/apis/camel/v1/trait/builder.go +++ b/pkg/apis/camel/v1/trait/builder.go @@ -39,6 +39,10 @@ type BuilderTrait struct { LimitCPU string `property:"limit-cpu" json:"limitCPU,omitempty"` // When using `pod` strategy, the maximum amount of memory required by the pod builder. LimitMemory string `property:"limit-memory" json:"limitMemory,omitempty"` + // A reference pointing to a configmap/secret that contains a maven profile. + // The content of the maven profile is expected to be a text containing a valid maven profile starting with `` and ending with `` that will be integrated as an inline profile in the POM. + // Syntax: [configmap|secret]:name[/key], where name represents the resource name, key optionally represents the resource key to be filtered (default key value = profile.xml). + MavenProfile string `property:"maven-profile" json:"mavenProfile,omitempty"` // A list of tasks to be executed (available only when using `pod` strategy) with format ;; Tasks []string `property:"tasks" json:"tasks,omitempty"` } diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go b/pkg/apis/camel/v1/zz_generated.deepcopy.go index e7d79c4dd7..e1e5783895 100644 --- a/pkg/apis/camel/v1/zz_generated.deepcopy.go +++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go @@ -2000,6 +2000,7 @@ func (in *MavenSpec) DeepCopyInto(out *MavenSpec) { (*out)[key] = val } } + in.Profile.DeepCopyInto(&out.Profile) in.Settings.DeepCopyInto(&out.Settings) in.SettingsSecurity.DeepCopyInto(&out.SettingsSecurity) if in.CASecrets != nil { diff --git a/pkg/builder/project.go b/pkg/builder/project.go index 77794014be..ab6c8baf78 100644 --- a/pkg/builder/project.go +++ b/pkg/builder/project.go @@ -41,6 +41,7 @@ func init() { Project.GenerateProjectSettings, Project.InjectDependencies, Project.SanitizeDependencies, + Project.InjectProfile, } } @@ -50,6 +51,7 @@ type projectSteps struct { GenerateProjectSettings Step InjectDependencies Step SanitizeDependencies Step + InjectProfile Step CommonSteps []Step } @@ -60,6 +62,7 @@ var Project = projectSteps{ GenerateProjectSettings: NewStep(ProjectGenerationPhase+1, generateProjectSettings), InjectDependencies: NewStep(ProjectGenerationPhase+2, injectDependencies), SanitizeDependencies: NewStep(ProjectGenerationPhase+3, sanitizeDependencies), + InjectProfile: NewStep(ProjectGenerationPhase+4, injectProfile), } func cleanUpBuildDir(ctx *builderContext) error { @@ -191,3 +194,14 @@ func injectDependencies(ctx *builderContext) error { func sanitizeDependencies(ctx *builderContext) error { return camel.SanitizeIntegrationDependencies(ctx.Maven.Project.Dependencies) } + +func injectProfile(ctx *builderContext) error { + val, err := kubernetes.ResolveValueSource(ctx.C, ctx.Client, ctx.Namespace, &ctx.Build.Maven.Profile) + if err != nil { + return err + } + if val != "" { + ctx.Maven.Project.AddProfile(val) + } + return nil +} diff --git a/pkg/client/camel/applyconfiguration/camel/v1/mavenbuildspec.go b/pkg/client/camel/applyconfiguration/camel/v1/mavenbuildspec.go index 8878c5f373..52528bcf87 100644 --- a/pkg/client/camel/applyconfiguration/camel/v1/mavenbuildspec.go +++ b/pkg/client/camel/applyconfiguration/camel/v1/mavenbuildspec.go @@ -59,6 +59,14 @@ func (b *MavenBuildSpecApplyConfiguration) WithProperties(entries map[string]str return b } +// WithProfile sets the Profile 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 Profile field is set to the value of the last call. +func (b *MavenBuildSpecApplyConfiguration) WithProfile(value *ValueSourceApplyConfiguration) *MavenBuildSpecApplyConfiguration { + b.Profile = value + return b +} + // WithSettings sets the Settings 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 Settings field is set to the value of the last call. diff --git a/pkg/client/camel/applyconfiguration/camel/v1/mavenspec.go b/pkg/client/camel/applyconfiguration/camel/v1/mavenspec.go index b10564b40e..b73c97f279 100644 --- a/pkg/client/camel/applyconfiguration/camel/v1/mavenspec.go +++ b/pkg/client/camel/applyconfiguration/camel/v1/mavenspec.go @@ -28,6 +28,7 @@ import ( type MavenSpecApplyConfiguration struct { LocalRepository *string `json:"localRepository,omitempty"` Properties map[string]string `json:"properties,omitempty"` + Profile *ValueSourceApplyConfiguration `json:"profile,omitempty"` Settings *ValueSourceApplyConfiguration `json:"settings,omitempty"` SettingsSecurity *ValueSourceApplyConfiguration `json:"settingsSecurity,omitempty"` CASecrets []corev1.SecretKeySelector `json:"caSecrets,omitempty"` @@ -63,6 +64,14 @@ func (b *MavenSpecApplyConfiguration) WithProperties(entries map[string]string) return b } +// WithProfile sets the Profile 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 Profile field is set to the value of the last call. +func (b *MavenSpecApplyConfiguration) WithProfile(value *ValueSourceApplyConfiguration) *MavenSpecApplyConfiguration { + b.Profile = value + return b +} + // WithSettings sets the Settings 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 Settings field is set to the value of the last call. diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index 6a4f3bd088..06ad04b46b 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -568,7 +568,8 @@ func (o *installCmdOptions) setupIntegrationPlatform(c client.Client, namespace } if o.MavenSettings != "" { - mavenSettings, err := decodeMavenSettings(o.MavenSettings) + mavenSettings, err := v1.DecodeValueSource(o.MavenSettings, "settings.xml", + "illegal maven setting definition, syntax: configmap|secret:resource-name[/settings path]") if err != nil { return nil, err } diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go index 2d997210e6..d42922e44d 100644 --- a/pkg/trait/builder.go +++ b/pkg/trait/builder.go @@ -261,6 +261,16 @@ func (t *builderTrait) builderTask(e *Environment) (*v1.BuilderTask, error) { } } + // User provides a maven profile + if t.MavenProfile != "" { + mavenProfile, err := v1.DecodeValueSource(t.MavenProfile, "profile.xml", + "illegal profile definition, syntax: configmap|secret:resource-name[/profile path]") + if err != nil { + return nil, fmt.Errorf("invalid maven profile: %s: %w. ", t.MavenProfile, err) + } + task.Maven.Profile = mavenProfile + } + steps := make([]builder.Step, 0) steps = append(steps, builder.Project.CommonSteps...) diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go index d9ea2c8ce9..a260c18a02 100644 --- a/pkg/trait/builder_test.go +++ b/pkg/trait/builder_test.go @@ -202,3 +202,22 @@ func findCustomTaskByName(tasks []v1.Task, name string) v1.Task { } return v1.Task{} } + +func TestMavenProfileBuilderTrait(t *testing.T) { + env := createBuilderTestEnv(v1.IntegrationPlatformClusterKubernetes, v1.IntegrationPlatformBuildPublishStrategyKaniko) + builderTrait := createNominalBuilderTraitTest() + builderTrait.MavenProfile = "configmap:maven-profile/owasp-profile.xml" + + err := builderTrait.Apply(env) + + assert.Nil(t, err) + + assert.Equal(t, v1.ValueSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "maven-profile", + }, + Key: "owasp-profile.xml", + }, + }, env.Pipeline[0].Builder.Maven.MavenSpec.Profile) +} diff --git a/pkg/util/maven/maven_project.go b/pkg/util/maven/maven_project.go index 862348567d..4a75003f4f 100644 --- a/pkg/util/maven/maven_project.go +++ b/pkg/util/maven/maven_project.go @@ -152,6 +152,10 @@ func (p *Project) AddEncodedDependencyExclusion(gav string, exclusion Exclusion) } } +func (p *Project) AddProfile(profile string) { + p.Profiles = ProfilesContent{InnerXML: profile} +} + // NewDependency creates an new dependency from the given GAV. func NewDependency(groupID string, artifactID string, version string) Dependency { return Dependency{ diff --git a/pkg/util/maven/maven_project_test.go b/pkg/util/maven/maven_project_test.go index cc25a5be58..28cf334ac2 100644 --- a/pkg/util/maven/maven_project_test.go +++ b/pkg/util/maven/maven_project_test.go @@ -80,6 +80,7 @@ const expectedPom = ` + custom ` func TestPomGeneration(t *testing.T) { @@ -129,6 +130,8 @@ func TestPomGeneration(t *testing.T) { }, } + project.Profiles = ProfilesContent{InnerXML: `custom`} + pom, err := util.EncodeXML(project) assert.Nil(t, err) diff --git a/pkg/util/maven/maven_types.go b/pkg/util/maven/maven_types.go index 57edc133c0..98494c54b2 100644 --- a/pkg/util/maven/maven_types.go +++ b/pkg/util/maven/maven_types.go @@ -80,6 +80,7 @@ type Project struct { Repositories []v1.Repository `xml:"repositories>repository,omitempty"` PluginRepositories []v1.Repository `xml:"pluginRepositories>pluginRepository,omitempty"` Build *Build `xml:"build,omitempty"` + Profiles ProfilesContent `xml:"profiles,omitempty"` } // Exclusion models a dependency exclusion. @@ -132,3 +133,7 @@ type Proxy struct { Password string `xml:"password,omitempty"` NonProxyHosts string `xml:"nonProxyHosts,omitempty"` } + +type ProfilesContent struct { + InnerXML string `xml:",innerxml"` +} diff --git a/resources/traits.yaml b/resources/traits.yaml index 8be71a81d8..ed03494e61 100755 --- a/resources/traits.yaml +++ b/resources/traits.yaml @@ -232,6 +232,14 @@ traits: type: string description: When using `pod` strategy, the maximum amount of memory required by the pod builder. + - name: maven-profile + type: string + description: 'A reference pointing to a configmap/secret that contains a maven + profile. The content of the maven profile is expected to be a text containing + a valid maven profile starting with `` and ending with `` + that will be integrated as an inline profile in the POM. Syntax: [configmap|secret]:name[/key], + where name represents the resource name, key optionally represents the resource + key to be filtered (default key value = profile.xml).' - name: tasks type: '[]string' description: A list of tasks to be executed (available only when using `pod` strategy)