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
commit d44ebd19e151ebe22cd019d072c9bab8d35539f2 Author: Pasquale Congiusti <[email protected]> AuthorDate: Mon May 27 13:19:07 2024 +0200 fix(trait): dynamic dependencies path --- pkg/apis/camel/v1/integrationkit_types_support.go | 17 ++++++++ .../camel/v1/integrationkit_types_support_test.go | 47 ++++++++++++++++++++++ pkg/cmd/promote.go | 31 ++++++++++++++ pkg/cmd/promote_test.go | 30 +++++++++++--- pkg/controller/integrationkit/error.go | 4 ++ pkg/controller/integrationkit/initialize.go | 20 ++++----- .../integrationkit/integrationkit_controller.go | 2 - pkg/controller/integrationkit/monitor.go | 4 ++ pkg/trait/jvm.go | 25 ++++++------ pkg/trait/jvm_test.go | 38 +++++------------ 10 files changed, 162 insertions(+), 56 deletions(-) diff --git a/pkg/apis/camel/v1/integrationkit_types_support.go b/pkg/apis/camel/v1/integrationkit_types_support.go index b58653227..b6b70624d 100644 --- a/pkg/apis/camel/v1/integrationkit_types_support.go +++ b/pkg/apis/camel/v1/integrationkit_types_support.go @@ -18,8 +18,12 @@ limitations under the License. package v1 import ( + "fmt" + "path/filepath" + "sort" "strconv" + "github.com/apache/camel-k/v2/pkg/util/sets" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -205,6 +209,19 @@ func (in *IntegrationKitStatus) GetConditions() []ResourceCondition { return res } +// GetDependenciesPaths returns the set of dependency paths. +func (in *IntegrationKitStatus) GetDependenciesPaths() []string { + s := sets.NewSet() + for _, dep := range in.Artifacts { + path := filepath.Dir(dep.Target) + s.Add(fmt.Sprintf("%s/*", path)) + } + values := s.List() + sort.Strings(values) + + return values +} + func (c IntegrationKitCondition) GetType() string { return string(c.Type) } diff --git a/pkg/apis/camel/v1/integrationkit_types_support_test.go b/pkg/apis/camel/v1/integrationkit_types_support_test.go new file mode 100644 index 000000000..78a741f81 --- /dev/null +++ b/pkg/apis/camel/v1/integrationkit_types_support_test.go @@ -0,0 +1,47 @@ +/* +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 v1 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetKitDependenciesDirectories(t *testing.T) { + kit := &IntegrationKit{ + Status: IntegrationKitStatus{ + Artifacts: []Artifact{ + {Target: "my-dir1/lib/mytest.jar"}, + {Target: "my-dir1/lib/mytest2.jar"}, + {Target: "my-dir1/lib/mytest3.jar"}, + {Target: "my-dir2/lib/mytest4.jar"}, + {Target: "my-dir1/lib2/mytest5.jar"}, + {Target: "my-dir/mytest6.jar"}, + {Target: "my-dir/mytest7.jar"}, + }, + Phase: IntegrationKitPhaseReady, + }, + } + paths := kit.Status.GetDependenciesPaths() + assert.Len(t, paths, 4) + assert.Equal(t, "my-dir/*", paths[0]) + assert.Equal(t, "my-dir1/lib/*", paths[1]) + assert.Equal(t, "my-dir1/lib2/*", paths[2]) + assert.Equal(t, "my-dir2/lib/*", paths[3]) +} diff --git a/pkg/cmd/promote.go b/pkg/cmd/promote.go index 6879f0ade..c86a8dc5e 100644 --- a/pkg/cmd/promote.go +++ b/pkg/cmd/promote.go @@ -26,6 +26,7 @@ import ( "strings" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" + traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/client" "github.com/apache/camel-k/v2/pkg/trait" "github.com/apache/camel-k/v2/pkg/util/camel" @@ -514,6 +515,20 @@ func (o *promoteCmdOptions) editIntegration(it *v1.Integration, kit *v1.Integrat Name: dstKit.Name, Kind: dstKit.Kind, } + // We must provide the classpath expected for the IntegrationKit. This is calculated dynamically and + // would get lost when creating the promoted IntegrationKit (which is in .status.artifacts). For this reason + // we must report it in the promoted Integration. + kitClasspath := kit.Status.GetDependenciesPaths() + if len(kitClasspath) > 0 { + if dstIt.Spec.Traits.JVM == nil { + dstIt.Spec.Traits.JVM = &traitv1.JVMTrait{} + } + jvmTrait := dstIt.Spec.Traits.JVM + if jvmTrait.Classpath != "" { + jvmTrait.Classpath += ":" + } + jvmTrait.Classpath += strings.Join(kitClasspath, ":") + } return &dstIt, dstKit } @@ -583,6 +598,22 @@ func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it *v1.Integration, kit *v1.In } } } + + // We must provide the classpath expected for the IntegrationKit. This is calculated dynamically and + // would get lost when creating the promoted IntegrationKit (which is in .status.artifacts). For this reason + // we must report it in the promoted Integration. + kitClasspath := kit.Status.GetDependenciesPaths() + if len(kitClasspath) > 0 { + if dst.Spec.Integration.Traits.JVM == nil { + dst.Spec.Integration.Traits.JVM = &traitv1.JVMTrait{} + } + jvmTrait := dst.Spec.Integration.Traits.JVM + if jvmTrait.Classpath != "" { + jvmTrait.Classpath += ":" + } + jvmTrait.Classpath += strings.Join(kitClasspath, ":") + } + return &dst, dstKit } diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go index 24036478d..91c1b9dc3 100644 --- a/pkg/cmd/promote_test.go +++ b/pkg/cmd/promote_test.go @@ -117,7 +117,9 @@ spec: kind: IntegrationKit name: my-it-test-kit namespace: prod-namespace - traits: {} + traits: + jvm: + classpath: /path/to/artifact-1/*:/path/to/artifact-2/* status: {} `, output) } @@ -127,6 +129,12 @@ func nominalIntegration(name string) (v1.Integration, v1.IntegrationKit) { it.Status.Phase = v1.IntegrationPhaseRunning it.Status.Image = "my-special-image" ik := v1.NewIntegrationKit("default", name+"-kit") + ik.Status = v1.IntegrationKitStatus{ + Artifacts: []v1.Artifact{ + {Target: "/path/to/artifact-1/a-1.jar"}, + {Target: "/path/to/artifact-2/a-2.jar"}, + }, + } it.Status.IntegrationKit = &corev1.ObjectReference{ Namespace: ik.Namespace, Name: ik.Name, @@ -178,7 +186,9 @@ spec: kind: IntegrationKit name: my-kb-test-kit namespace: prod-namespace - traits: {} + traits: + jvm: + classpath: /path/to/artifact-1/*:/path/to/artifact-2/* sink: {} source: {} status: {} @@ -249,7 +259,9 @@ spec: kind: IntegrationKit name: my-it-test-kit namespace: prod-namespace - traits: {} + traits: + jvm: + classpath: /path/to/artifact-1/*:/path/to/artifact-2/* status: {} `, output) } @@ -308,7 +320,9 @@ spec: kind: IntegrationKit name: my-kb-test-kit namespace: prod-namespace - traits: {} + traits: + jvm: + classpath: /path/to/artifact-1/*:/path/to/artifact-2/* sink: {} source: {} status: {} @@ -400,7 +414,9 @@ spec: kind: IntegrationKit name: my-it-test-kit namespace: prod - traits: {} + traits: + jvm: + classpath: /path/to/artifact-1/*:/path/to/artifact-2/* status: {} `, output) // Verify also when the operator Id is set in the integration @@ -439,7 +455,9 @@ spec: kind: IntegrationKit name: my-it-test-kit namespace: prod - traits: {} + traits: + jvm: + classpath: /path/to/artifact-1/*:/path/to/artifact-2/* status: {} `, output) } diff --git a/pkg/controller/integrationkit/error.go b/pkg/controller/integrationkit/error.go index 5d2e6ef68..9f245f0ef 100644 --- a/pkg/controller/integrationkit/error.go +++ b/pkg/controller/integrationkit/error.go @@ -42,6 +42,10 @@ func (action *errorAction) CanHandle(kit *v1.IntegrationKit) bool { } func (action *errorAction) Handle(ctx context.Context, kit *v1.IntegrationKit) (*v1.IntegrationKit, error) { + if kit.IsExternal() || kit.IsSynthetic() { + // do nothing, it's not a managed kit + return nil, nil + } hash, err := digest.ComputeForIntegrationKit(kit) if err != nil { return nil, err diff --git a/pkg/controller/integrationkit/initialize.go b/pkg/controller/integrationkit/initialize.go index de356e6a9..f6ea9116c 100644 --- a/pkg/controller/integrationkit/initialize.go +++ b/pkg/controller/integrationkit/initialize.go @@ -49,12 +49,21 @@ func (action *initializeAction) CanHandle(kit *v1.IntegrationKit) bool { } func (action *initializeAction) Handle(ctx context.Context, kit *v1.IntegrationKit) (*v1.IntegrationKit, error) { + action.L.Info("Initializing IntegrationKit") + if kit.Spec.Image != "" { + // Synthetic Kit + action.L.Info("Synthetic Kit, won't be able to build or monitor this one.") + kit.Status.Phase = v1.IntegrationKitPhaseReady + kit.Status.Image = kit.Spec.Image + + return kit, nil + } + + // Managed Kit env, err := trait.Apply(ctx, action.client, nil, kit) if err != nil { return nil, err } - - action.L.Info("Initializing IntegrationKit") kit.Status.Version = defaults.Version if kit.Spec.Image == "" { @@ -98,13 +107,6 @@ func (action *initializeAction) Handle(ctx context.Context, kit *v1.IntegrationK } // now the kit can be built kit.Status.Phase = v1.IntegrationKitPhaseBuildSubmitted - } else { - // but in case it has been created from an image, mark the - // kit as ready - kit.Status.Phase = v1.IntegrationKitPhaseReady - - // and set the image to be used - kit.Status.Image = kit.Spec.Image } return kit, nil diff --git a/pkg/controller/integrationkit/integrationkit_controller.go b/pkg/controller/integrationkit/integrationkit_controller.go index 9df46854c..135085233 100644 --- a/pkg/controller/integrationkit/integrationkit_controller.go +++ b/pkg/controller/integrationkit/integrationkit_controller.go @@ -334,9 +334,7 @@ func (r *reconcileIntegrationKit) update(ctx context.Context, base *v1.Integrati } target.Status.Digest = dgst - target.Status.ObservedGeneration = base.Generation - err = r.client.Status().Patch(ctx, target, ctrl.MergeFrom(base)) return reconcile.Result{}, err diff --git a/pkg/controller/integrationkit/monitor.go b/pkg/controller/integrationkit/monitor.go index 6852c9238..5b72ef153 100644 --- a/pkg/controller/integrationkit/monitor.go +++ b/pkg/controller/integrationkit/monitor.go @@ -42,6 +42,10 @@ func (action *monitorAction) CanHandle(kit *v1.IntegrationKit) bool { } func (action *monitorAction) Handle(ctx context.Context, kit *v1.IntegrationKit) (*v1.IntegrationKit, error) { + if kit.IsExternal() || kit.IsSynthetic() { + // do nothing, it's not a managed kit + return nil, nil + } hash, err := digest.ComputeForIntegrationKit(kit) if err != nil { return nil, err diff --git a/pkg/trait/jvm.go b/pkg/trait/jvm.go index 87f3da133..790a6b700 100644 --- a/pkg/trait/jvm.go +++ b/pkg/trait/jvm.go @@ -160,7 +160,7 @@ func (t *jvmTrait) Apply(e *Environment) error { // If user provided the jar, we will execute on the container something like // java -Dxyx ... -cp ... -jar my-app.jar - // For this reason it's imporant that the container is a java based container able to run a Camel (hence Java) application + // For this reason it's important that the container is a java based container able to run a Camel (hence Java) application container.WorkingDir = builder.DeploymentDir container.Command = []string{"java"} classpathItems := t.prepareClasspathItems(container) @@ -172,7 +172,11 @@ func (t *jvmTrait) Apply(e *Environment) error { if e.CamelCatalog == nil { return fmt.Errorf("cannot execute trait: missing Camel catalog") } - kitDepsDirs := getKitDependenciesDirectories(kit) + kitDepsDirs := kit.Status.GetDependenciesPaths() + if len(kitDepsDirs) == 0 { + // Use legacy Camel Quarkus expected structure + kitDepsDirs = getLegacyCamelQuarkusDependenciesPaths() + } classpathItems = append(classpathItems, kitDepsDirs...) args = append(args, "-cp", strings.Join(classpathItems, ":")) args = append(args, e.CamelCatalog.Runtime.ApplicationClass) @@ -277,15 +281,12 @@ func (t *jvmTrait) prepareHTTPProxy(container *corev1.Container) ([]string, erro return args, nil } -// getKitDependenciesDirectories returns the list of directories, scanning the dependencies list. -func getKitDependenciesDirectories(kit *v1.IntegrationKit) []string { - s := sets.NewSet() - for _, dep := range kit.Status.Artifacts { - path := filepath.Dir(dep.Target) - s.Add(fmt.Sprintf("%s/*", path)) +// Deprecated: to be removed as soon as version 2.3.x is no longer supported. +func getLegacyCamelQuarkusDependenciesPaths() []string { + return []string{ + "dependencies/*", + "dependencies/lib/boot/*", + "dependencies/lib/main/*", + "dependencies/quarkus/*", } - values := s.List() - sort.Strings(values) - - return values } diff --git a/pkg/trait/jvm_test.go b/pkg/trait/jvm_test.go index 6f04f549e..ff5fae279 100644 --- a/pkg/trait/jvm_test.go +++ b/pkg/trait/jvm_test.go @@ -300,7 +300,11 @@ func TestApplyJvmTraitWithDeploymentResource(t *testing.T) { require.NoError(t, err) assert.Equal(t, []string{ "-cp", - fmt.Sprintf("./resources:%s:%s:/mount/path", crMountPath, rdMountPath), + fmt.Sprintf( + "./resources:%s:%s:/mount/path:dependencies/*", + crMountPath, + rdMountPath, + ), "io.quarkus.bootstrap.runner.QuarkusEntryPoint", }, d.Spec.Template.Spec.Containers[0].Args) } @@ -331,7 +335,7 @@ func TestApplyJvmTraitWithKNativeResource(t *testing.T) { require.NoError(t, err) assert.Equal(t, []string{ "-cp", - fmt.Sprintf("./resources:%s:%s:/mount/path", crMountPath, rdMountPath), + fmt.Sprintf("./resources:%s:%s:/mount/path:dependencies/*", crMountPath, rdMountPath), "io.quarkus.bootstrap.runner.QuarkusEntryPoint", }, s.Spec.Template.Spec.Containers[0].Args) } @@ -398,7 +402,7 @@ func TestApplyJvmTraitWithExternalKitType(t *testing.T) { assert.Equal(t, []string{ "-cp", - fmt.Sprintf("./resources:%s:%s", crMountPath, rdMountPath), + fmt.Sprintf("./resources:%s:%s:dependencies/*", crMountPath, rdMountPath), "io.quarkus.bootstrap.runner.QuarkusEntryPoint", }, d.Spec.Template.Spec.Containers[0].Args) } @@ -435,7 +439,7 @@ func TestApplyJvmTraitWithClasspath(t *testing.T) { require.NoError(t, err) assert.Equal(t, []string{ "-cp", - fmt.Sprintf("./resources:%s:%s:/mount/path:%s:%s", crMountPath, rdMountPath, "/path/to/another/dep.jar", "/path/to/my-dep.jar"), + fmt.Sprintf("./resources:%s:%s:/mount/path:%s:%s:dependencies/*", crMountPath, rdMountPath, "/path/to/another/dep.jar", "/path/to/my-dep.jar"), "io.quarkus.bootstrap.runner.QuarkusEntryPoint", }, d.Spec.Template.Spec.Containers[0].Args) } @@ -556,6 +560,9 @@ func createNominalJvmTest(kitType string) (*jvmTrait, *Environment) { }, }, Status: v1.IntegrationKitStatus{ + Artifacts: []v1.Artifact{ + {Target: "dependencies/my-dep.jar"}, + }, Phase: v1.IntegrationKitPhaseReady, }, }, @@ -564,26 +571,3 @@ func createNominalJvmTest(kitType string) (*jvmTrait, *Environment) { return trait, environment } - -func TestGetKitDependenciesDirectories(t *testing.T) { - kit := &v1.IntegrationKit{ - Status: v1.IntegrationKitStatus{ - Artifacts: []v1.Artifact{ - {Target: "my-dir1/lib/mytest.jar"}, - {Target: "my-dir1/lib/mytest2.jar"}, - {Target: "my-dir1/lib/mytest3.jar"}, - {Target: "my-dir2/lib/mytest4.jar"}, - {Target: "my-dir1/lib2/mytest5.jar"}, - {Target: "my-dir/mytest6.jar"}, - {Target: "my-dir/mytest7.jar"}, - }, - Phase: v1.IntegrationKitPhaseReady, - }, - } - paths := getKitDependenciesDirectories(kit) - assert.Len(t, paths, 4) - assert.Equal(t, "my-dir/*", paths[0]) - assert.Equal(t, "my-dir1/lib/*", paths[1]) - assert.Equal(t, "my-dir1/lib2/*", paths[2]) - assert.Equal(t, "my-dir2/lib/*", paths[3]) -}
