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])
-}

Reply via email to