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 f83f39b59df2095ab00ae8c691819a1502e9b5a1
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Tue Oct 10 10:54:20 2023 +0200

    feat(trait): mount kamelets for runtime
    
    * Add a configmap as a bundle for all kamelets used by the Integration
    * Mount the bundle in /etc/camel/kamelets
    * Let the runtime use the Kamelets instead of trasforming into 
RouteTemplates
    * Let the operator use the Kamelet template for capability parsing
    
    Closes #4618
---
 config/crd/bases/camel.apache.org_builds.yaml      |   8 ++
 .../bases/camel.apache.org_integrationkits.yaml    |   3 +
 .../camel.apache.org_integrationplatforms.yaml     |   8 ++
 .../crd/bases/camel.apache.org_integrations.yaml   |  10 ++
 .../bases/camel.apache.org_kameletbindings.yaml    |   7 ++
 config/crd/bases/camel.apache.org_kamelets.yaml    |   6 ++
 config/crd/bases/camel.apache.org_pipes.yaml       |   7 ++
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc  |  14 +++
 docs/modules/traits/pages/kamelets.adoc            |   4 +
 helm/camel-k/crds/crd-build.yaml                   |   8 ++
 helm/camel-k/crds/crd-integration-kit.yaml         |   3 +
 helm/camel-k/crds/crd-integration-platform.yaml    |   8 ++
 helm/camel-k/crds/crd-integration.yaml             |  10 ++
 helm/camel-k/crds/crd-kamelet-binding.yaml         |   7 ++
 helm/camel-k/crds/crd-kamelet.yaml                 |   6 ++
 helm/camel-k/crds/crd-pipe.yaml                    |   7 ++
 pkg/apis/camel/v1/common_types.go                  |   2 +
 pkg/apis/camel/v1/common_types_support.go          |   5 +
 pkg/apis/camel/v1/trait/kamelets.go                |   2 +
 .../applyconfiguration/camel/v1/sourcespec.go      |   9 ++
 pkg/trait/camel.go                                 |   1 +
 pkg/trait/kamelets.go                              | 117 +++++++++++----------
 pkg/trait/kamelets_test.go                         |   6 +-
 pkg/trait/trait_types.go                           |  74 +++++++------
 pkg/util/kubernetes/factory.go                     |   3 +
 resources/traits.yaml                              |   4 +
 26 files changed, 251 insertions(+), 88 deletions(-)

diff --git a/config/crd/bases/camel.apache.org_builds.yaml 
b/config/crd/bases/camel.apache.org_builds.yaml
index 08a6cc213..caacc731d 100644
--- a/config/crd/bases/camel.apache.org_builds.yaml
+++ b/config/crd/bases/camel.apache.org_builds.yaml
@@ -686,6 +686,10 @@ spec:
                               contentType:
                                 description: the content type (tipically text 
or binary)
                                 type: string
+                              from-kamelet:
+                                description: True if the spec is generated 
from a
+                                  Kamelet
+                                type: boolean
                               interceptors:
                                 description: Interceptors are optional 
identifiers
                                   the org.apache.camel.k.RoutesLoader uses to 
pre/post
@@ -1424,6 +1428,10 @@ spec:
                               contentType:
                                 description: the content type (tipically text 
or binary)
                                 type: string
+                              from-kamelet:
+                                description: True if the spec is generated 
from a
+                                  Kamelet
+                                type: boolean
                               interceptors:
                                 description: Interceptors are optional 
identifiers
                                   the org.apache.camel.k.RoutesLoader uses to 
pre/post
diff --git a/config/crd/bases/camel.apache.org_integrationkits.yaml 
b/config/crd/bases/camel.apache.org_integrationkits.yaml
index 3d56b6ab8..d3e061b62 100644
--- a/config/crd/bases/camel.apache.org_integrationkits.yaml
+++ b/config/crd/bases/camel.apache.org_integrationkits.yaml
@@ -143,6 +143,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
diff --git a/config/crd/bases/camel.apache.org_integrationplatforms.yaml 
b/config/crd/bases/camel.apache.org_integrationplatforms.yaml
index d34c2f432..011141207 100644
--- a/config/crd/bases/camel.apache.org_integrationplatforms.yaml
+++ b/config/crd/bases/camel.apache.org_integrationplatforms.yaml
@@ -1190,6 +1190,10 @@ spec:
                         description: Comma separated list of Kamelet names to 
load
                           into the current integration
                         type: string
+                      mountPoint:
+                        description: The directory where the application 
mounts and
+                          reads Kamelet spec (default `/etc/camel/kamelets`)
+                        type: string
                     type: object
                   keda:
                     description: 'Deprecated: for backward compatibility.'
@@ -3004,6 +3008,10 @@ spec:
                         description: Comma separated list of Kamelet names to 
load
                           into the current integration
                         type: string
+                      mountPoint:
+                        description: The directory where the application 
mounts and
+                          reads Kamelet spec (default `/etc/camel/kamelets`)
+                        type: string
                     type: object
                   keda:
                     description: 'Deprecated: for backward compatibility.'
diff --git a/config/crd/bases/camel.apache.org_integrations.yaml 
b/config/crd/bases/camel.apache.org_integrations.yaml
index 608118fef..0ea61efce 100644
--- a/config/crd/bases/camel.apache.org_integrations.yaml
+++ b/config/crd/bases/camel.apache.org_integrations.yaml
@@ -189,6 +189,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
@@ -7107,6 +7110,10 @@ spec:
                         description: Comma separated list of Kamelet names to 
load
                           into the current integration
                         type: string
+                      mountPoint:
+                        description: The directory where the application 
mounts and
+                          reads Kamelet spec (default `/etc/camel/kamelets`)
+                        type: string
                     type: object
                   keda:
                     description: 'Deprecated: for backward compatibility.'
@@ -7916,6 +7923,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
diff --git a/config/crd/bases/camel.apache.org_kameletbindings.yaml 
b/config/crd/bases/camel.apache.org_kameletbindings.yaml
index b40d8c9a8..5e137abd8 100644
--- a/config/crd/bases/camel.apache.org_kameletbindings.yaml
+++ b/config/crd/bases/camel.apache.org_kameletbindings.yaml
@@ -189,6 +189,9 @@ spec:
                         contentType:
                           description: the content type (tipically text or 
binary)
                           type: string
+                        from-kamelet:
+                          description: True if the spec is generated from a 
Kamelet
+                          type: boolean
                         interceptors:
                           description: Interceptors are optional identifiers 
the org.apache.camel.k.RoutesLoader
                             uses to pre/post process sources
@@ -7393,6 +7396,10 @@ spec:
                             description: Comma separated list of Kamelet names 
to
                               load into the current integration
                             type: string
+                          mountPoint:
+                            description: The directory where the application 
mounts
+                              and reads Kamelet spec (default 
`/etc/camel/kamelets`)
+                            type: string
                         type: object
                       keda:
                         description: 'Deprecated: for backward compatibility.'
diff --git a/config/crd/bases/camel.apache.org_kamelets.yaml 
b/config/crd/bases/camel.apache.org_kamelets.yaml
index 3131ac0e2..aeb9739e2 100644
--- a/config/crd/bases/camel.apache.org_kamelets.yaml
+++ b/config/crd/bases/camel.apache.org_kamelets.yaml
@@ -466,6 +466,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
@@ -1163,6 +1166,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
diff --git a/config/crd/bases/camel.apache.org_pipes.yaml 
b/config/crd/bases/camel.apache.org_pipes.yaml
index ca6c71c0e..a30364531 100644
--- a/config/crd/bases/camel.apache.org_pipes.yaml
+++ b/config/crd/bases/camel.apache.org_pipes.yaml
@@ -187,6 +187,9 @@ spec:
                         contentType:
                           description: the content type (tipically text or 
binary)
                           type: string
+                        from-kamelet:
+                          description: True if the spec is generated from a 
Kamelet
+                          type: boolean
                         interceptors:
                           description: Interceptors are optional identifiers 
the org.apache.camel.k.RoutesLoader
                             uses to pre/post process sources
@@ -7391,6 +7394,10 @@ spec:
                             description: Comma separated list of Kamelet names 
to
                               load into the current integration
                             type: string
+                          mountPoint:
+                            description: The directory where the application 
mounts
+                              and reads Kamelet spec (default 
`/etc/camel/kamelets`)
+                            type: string
                         type: object
                       keda:
                         description: 'Deprecated: for backward compatibility.'
diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc 
b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index d280492a7..a6d669c43 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -5064,6 +5064,13 @@ Type defines the kind of source described by this object
 
 List of property names defined in the source (e.g. if type is "template")
 
+|`from-kamelet` +
+bool
+|
+
+
+True if the spec is generated from a Kamelet
+
 
 |===
 
@@ -6932,6 +6939,13 @@ string
 
 Comma separated list of Kamelet names to load into the current integration
 
+|`mountPoint` +
+string
+|
+
+
+The directory where the application mounts and reads Kamelet spec (default 
`/etc/camel/kamelets`)
+
 
 |===
 
diff --git a/docs/modules/traits/pages/kamelets.adoc 
b/docs/modules/traits/pages/kamelets.adoc
index 0336e0ff4..5fbf1f197 100755
--- a/docs/modules/traits/pages/kamelets.adoc
+++ b/docs/modules/traits/pages/kamelets.adoc
@@ -33,6 +33,10 @@ The following configuration options are available:
 | string
 | Comma separated list of Kamelet names to load into the current integration
 
+| kamelets.mount-point
+| string
+| The directory where the application mounts and reads Kamelet spec (default 
`/etc/camel/kamelets`)
+
 |===
 
 // End of autogenerated code - DO NOT EDIT! (configuration)
diff --git a/helm/camel-k/crds/crd-build.yaml b/helm/camel-k/crds/crd-build.yaml
index 08a6cc213..caacc731d 100644
--- a/helm/camel-k/crds/crd-build.yaml
+++ b/helm/camel-k/crds/crd-build.yaml
@@ -686,6 +686,10 @@ spec:
                               contentType:
                                 description: the content type (tipically text 
or binary)
                                 type: string
+                              from-kamelet:
+                                description: True if the spec is generated 
from a
+                                  Kamelet
+                                type: boolean
                               interceptors:
                                 description: Interceptors are optional 
identifiers
                                   the org.apache.camel.k.RoutesLoader uses to 
pre/post
@@ -1424,6 +1428,10 @@ spec:
                               contentType:
                                 description: the content type (tipically text 
or binary)
                                 type: string
+                              from-kamelet:
+                                description: True if the spec is generated 
from a
+                                  Kamelet
+                                type: boolean
                               interceptors:
                                 description: Interceptors are optional 
identifiers
                                   the org.apache.camel.k.RoutesLoader uses to 
pre/post
diff --git a/helm/camel-k/crds/crd-integration-kit.yaml 
b/helm/camel-k/crds/crd-integration-kit.yaml
index 3d56b6ab8..d3e061b62 100644
--- a/helm/camel-k/crds/crd-integration-kit.yaml
+++ b/helm/camel-k/crds/crd-integration-kit.yaml
@@ -143,6 +143,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
diff --git a/helm/camel-k/crds/crd-integration-platform.yaml 
b/helm/camel-k/crds/crd-integration-platform.yaml
index d34c2f432..011141207 100644
--- a/helm/camel-k/crds/crd-integration-platform.yaml
+++ b/helm/camel-k/crds/crd-integration-platform.yaml
@@ -1190,6 +1190,10 @@ spec:
                         description: Comma separated list of Kamelet names to 
load
                           into the current integration
                         type: string
+                      mountPoint:
+                        description: The directory where the application 
mounts and
+                          reads Kamelet spec (default `/etc/camel/kamelets`)
+                        type: string
                     type: object
                   keda:
                     description: 'Deprecated: for backward compatibility.'
@@ -3004,6 +3008,10 @@ spec:
                         description: Comma separated list of Kamelet names to 
load
                           into the current integration
                         type: string
+                      mountPoint:
+                        description: The directory where the application 
mounts and
+                          reads Kamelet spec (default `/etc/camel/kamelets`)
+                        type: string
                     type: object
                   keda:
                     description: 'Deprecated: for backward compatibility.'
diff --git a/helm/camel-k/crds/crd-integration.yaml 
b/helm/camel-k/crds/crd-integration.yaml
index 608118fef..0ea61efce 100644
--- a/helm/camel-k/crds/crd-integration.yaml
+++ b/helm/camel-k/crds/crd-integration.yaml
@@ -189,6 +189,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
@@ -7107,6 +7110,10 @@ spec:
                         description: Comma separated list of Kamelet names to 
load
                           into the current integration
                         type: string
+                      mountPoint:
+                        description: The directory where the application 
mounts and
+                          reads Kamelet spec (default `/etc/camel/kamelets`)
+                        type: string
                     type: object
                   keda:
                     description: 'Deprecated: for backward compatibility.'
@@ -7916,6 +7923,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml 
b/helm/camel-k/crds/crd-kamelet-binding.yaml
index b40d8c9a8..5e137abd8 100644
--- a/helm/camel-k/crds/crd-kamelet-binding.yaml
+++ b/helm/camel-k/crds/crd-kamelet-binding.yaml
@@ -189,6 +189,9 @@ spec:
                         contentType:
                           description: the content type (tipically text or 
binary)
                           type: string
+                        from-kamelet:
+                          description: True if the spec is generated from a 
Kamelet
+                          type: boolean
                         interceptors:
                           description: Interceptors are optional identifiers 
the org.apache.camel.k.RoutesLoader
                             uses to pre/post process sources
@@ -7393,6 +7396,10 @@ spec:
                             description: Comma separated list of Kamelet names 
to
                               load into the current integration
                             type: string
+                          mountPoint:
+                            description: The directory where the application 
mounts
+                              and reads Kamelet spec (default 
`/etc/camel/kamelets`)
+                            type: string
                         type: object
                       keda:
                         description: 'Deprecated: for backward compatibility.'
diff --git a/helm/camel-k/crds/crd-kamelet.yaml 
b/helm/camel-k/crds/crd-kamelet.yaml
index 3131ac0e2..aeb9739e2 100644
--- a/helm/camel-k/crds/crd-kamelet.yaml
+++ b/helm/camel-k/crds/crd-kamelet.yaml
@@ -466,6 +466,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
@@ -1163,6 +1166,9 @@ spec:
                     contentType:
                       description: the content type (tipically text or binary)
                       type: string
+                    from-kamelet:
+                      description: True if the spec is generated from a Kamelet
+                      type: boolean
                     interceptors:
                       description: Interceptors are optional identifiers the 
org.apache.camel.k.RoutesLoader
                         uses to pre/post process sources
diff --git a/helm/camel-k/crds/crd-pipe.yaml b/helm/camel-k/crds/crd-pipe.yaml
index ca6c71c0e..a30364531 100644
--- a/helm/camel-k/crds/crd-pipe.yaml
+++ b/helm/camel-k/crds/crd-pipe.yaml
@@ -187,6 +187,9 @@ spec:
                         contentType:
                           description: the content type (tipically text or 
binary)
                           type: string
+                        from-kamelet:
+                          description: True if the spec is generated from a 
Kamelet
+                          type: boolean
                         interceptors:
                           description: Interceptors are optional identifiers 
the org.apache.camel.k.RoutesLoader
                             uses to pre/post process sources
@@ -7391,6 +7394,10 @@ spec:
                             description: Comma separated list of Kamelet names 
to
                               load into the current integration
                             type: string
+                          mountPoint:
+                            description: The directory where the application 
mounts
+                              and reads Kamelet spec (default 
`/etc/camel/kamelets`)
+                            type: string
                         type: object
                       keda:
                         description: 'Deprecated: for backward compatibility.'
diff --git a/pkg/apis/camel/v1/common_types.go 
b/pkg/apis/camel/v1/common_types.go
index f63f4db35..21c202f1a 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -414,6 +414,8 @@ type SourceSpec struct {
        Type SourceType `json:"type,omitempty"`
        // List of property names defined in the source (e.g. if type is 
"template")
        PropertyNames []string `json:"property-names,omitempty"`
+       // True if the spec is generated from a Kamelet
+       FromKamelet bool `json:"from-kamelet,omitempty"`
 }
 
 // SourceType represents an available source type.
diff --git a/pkg/apis/camel/v1/common_types_support.go 
b/pkg/apis/camel/v1/common_types_support.go
index a7a956f98..c8adc7809 100644
--- a/pkg/apis/camel/v1/common_types_support.go
+++ b/pkg/apis/camel/v1/common_types_support.go
@@ -211,3 +211,8 @@ func DecodeValueSource(input string, defaultKey string, 
errorMessage string) (Va
 
        return ValueSource{}, fmt.Errorf(errorMessage)
 }
+
+// IsGeneratedFromKamelet determines is a source spec is derived from a Kamelet
+func (s *SourceSpec) IsGeneratedFromKamelet() bool {
+       return s.FromKamelet
+}
diff --git a/pkg/apis/camel/v1/trait/kamelets.go 
b/pkg/apis/camel/v1/trait/kamelets.go
index 9467b4883..8b9cfd6b0 100644
--- a/pkg/apis/camel/v1/trait/kamelets.go
+++ b/pkg/apis/camel/v1/trait/kamelets.go
@@ -26,4 +26,6 @@ type KameletsTrait struct {
        Auto *bool `property:"auto" json:"auto,omitempty"`
        // Comma separated list of Kamelet names to load into the current 
integration
        List string `property:"list" json:"list,omitempty"`
+       // The directory where the application mounts and reads Kamelet spec 
(default `/etc/camel/kamelets`)
+       MountPoint string `property:"mount-point" json:"mountPoint,omitempty"`
 }
diff --git a/pkg/client/camel/applyconfiguration/camel/v1/sourcespec.go 
b/pkg/client/camel/applyconfiguration/camel/v1/sourcespec.go
index 8c844b189..0cf5fdac3 100644
--- a/pkg/client/camel/applyconfiguration/camel/v1/sourcespec.go
+++ b/pkg/client/camel/applyconfiguration/camel/v1/sourcespec.go
@@ -32,6 +32,7 @@ type SourceSpecApplyConfiguration struct {
        Interceptors               []string            
`json:"interceptors,omitempty"`
        Type                       *camelv1.SourceType `json:"type,omitempty"`
        PropertyNames              []string            
`json:"property-names,omitempty"`
+       FromKamelet                *bool               
`json:"from-kamelet,omitempty"`
 }
 
 // SourceSpecApplyConfiguration constructs an declarative configuration of the 
SourceSpec type for use with
@@ -149,3 +150,11 @@ func (b *SourceSpecApplyConfiguration) 
WithPropertyNames(values ...string) *Sour
        }
        return b
 }
+
+// WithFromKamelet sets the FromKamelet 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 FromKamelet field is set to the value of the 
last call.
+func (b *SourceSpecApplyConfiguration) WithFromKamelet(value bool) 
*SourceSpecApplyConfiguration {
+       b.FromKamelet = &value
+       return b
+}
diff --git a/pkg/trait/camel.go b/pkg/trait/camel.go
index 6065a1fb0..e96dd6fcb 100644
--- a/pkg/trait/camel.go
+++ b/pkg/trait/camel.go
@@ -219,6 +219,7 @@ func (t *camelTrait) computeConfigMaps(e *Environment) 
[]ctrl.Object {
                                        Labels: map[string]string{
                                                v1.IntegrationLabel:            
    e.Integration.Name,
                                                
"camel.apache.org/properties.type": "user",
+                                               kubernetes.ConfigMapTypeLabel:  
    "camel-properties",
                                        },
                                },
                                Data: map[string]string{
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index b2c410a59..705026397 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -20,6 +20,7 @@ package trait
 import (
        "errors"
        "fmt"
+       "path/filepath"
        "sort"
        "strconv"
        "strings"
@@ -35,14 +36,16 @@ import (
        "github.com/apache/camel-k/v2/pkg/kamelet/repository"
        "github.com/apache/camel-k/v2/pkg/platform"
        "github.com/apache/camel-k/v2/pkg/util"
+       "github.com/apache/camel-k/v2/pkg/util/camel"
        "github.com/apache/camel-k/v2/pkg/util/digest"
        "github.com/apache/camel-k/v2/pkg/util/dsl"
        "github.com/apache/camel-k/v2/pkg/util/kamelets"
+       "github.com/apache/camel-k/v2/pkg/util/kubernetes"
 )
 
 const (
-       contentKey = "content"
-
+       contentKey                = "content"
+       KameletLocationProperty   = "camel.component.kamelet.location"
        kameletLabel              = "camel.apache.org/kamelet"
        kameletConfigurationLabel = "camel.apache.org/kamelet.configuration"
 )
@@ -89,6 +92,10 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, 
error) {
                        sort.Strings(kamelets)
                        t.List = strings.Join(kamelets, ",")
                }
+
+               if t.MountPoint == "" {
+                       t.MountPoint = filepath.Join(camel.BasePath, "kamelets")
+               }
        }
 
        return len(t.getKameletKeys()) > 0, nil
@@ -102,8 +109,6 @@ func (t *kameletsTrait) Apply(e *Environment) error {
        }
        if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
                return t.addConfigurationSecrets(e)
-       } else if e.IntegrationInRunningPhases() {
-               return t.configureApplicationProperties(e)
        }
 
        return nil
@@ -129,7 +134,6 @@ func (t *kameletsTrait) collectKamelets(e *Environment) 
(map[string]*v1.Kamelet,
                        missingKamelets = append(missingKamelets, key)
                } else {
                        availableKamelets = append(availableKamelets, key)
-
                        // Initialize remote kamelets
                        kamelets[key], err = kameletutils.Initialize(kamelet)
                        if err != nil {
@@ -142,7 +146,7 @@ func (t *kameletsTrait) collectKamelets(e *Environment) 
(map[string]*v1.Kamelet,
        sort.Strings(missingKamelets)
 
        if len(missingKamelets) > 0 {
-               message := fmt.Sprintf("kamelets [%s] found, [%s] not found in 
repositories: %s",
+               message := fmt.Sprintf("kamelets [%s] found, kamelets [%s] not 
found in %s repositories",
                        strings.Join(availableKamelets, ","),
                        strings.Join(missingKamelets, ","),
                        repo.String())
@@ -161,7 +165,7 @@ func (t *kameletsTrait) collectKamelets(e *Environment) 
(map[string]*v1.Kamelet,
                v1.IntegrationConditionKameletsAvailable,
                corev1.ConditionTrue,
                v1.IntegrationConditionKameletsAvailableReason,
-               fmt.Sprintf("kamelets [%s] found in repositories: %s", 
strings.Join(availableKamelets, ","), repo.String()),
+               fmt.Sprintf("kamelets [%s] found in %s repositories", 
strings.Join(availableKamelets, ","), repo.String()),
        )
 
        return kamelets, nil
@@ -173,59 +177,61 @@ func (t *kameletsTrait) addKamelets(e *Environment) error 
{
                if err != nil {
                        return err
                }
-
+               kameletsBundleConfigmap := 
initializeConfigmapBundle(e.Integration.Name, e.Integration.Namespace)
                for _, key := range t.getKameletKeys() {
                        kamelet := kamelets[key]
-
                        if kamelet.Status.Phase != v1.KameletPhaseReady {
                                return fmt.Errorf("kamelet %q is not %s: %s", 
key, v1.KameletPhaseReady, kamelet.Status.Phase)
                        }
-
+                       // Add source for parsing capabilities
                        if err := t.addKameletAsSource(e, kamelet); err != nil {
                                return err
                        }
-
-                       // Adding dependencies from Kamelets
+                       // Adding explicit dependencies from Kamelets
                        
util.StringSliceUniqueConcat(&e.Integration.Status.Dependencies, 
kamelet.Spec.Dependencies)
+                       // Add to Kamelet bundle configmap
+                       serialized, err := 
kubernetes.ToYAMLNoManagedFields(kamelet)
+                       if err != nil {
+                               return err
+                       }
+                       
kameletsBundleConfigmap.Data[fmt.Sprintf("%s.kamelet.yaml", kamelet.Name)] = 
string(serialized)
+               }
+               // set kamelets runtime location
+               if e.ApplicationProperties == nil {
+                       e.ApplicationProperties = map[string]string{}
                }
+               e.ApplicationProperties[KameletLocationProperty] = 
fmt.Sprintf("file:%s", t.MountPoint)
+               e.Resources.Add(&kameletsBundleConfigmap)
                // resort dependencies
                sort.Strings(e.Integration.Status.Dependencies)
        }
        return nil
 }
 
-func (t *kameletsTrait) configureApplicationProperties(e *Environment) error {
-       if len(t.getKameletKeys()) > 0 {
-               kamelets, err := t.collectKamelets(e)
-               if err != nil {
-                       return err
-               }
-
-               for _, key := range t.getKameletKeys() {
-                       kamelet := kamelets[key]
-                       // Configuring defaults from Kamelet
-                       for _, prop := range kamelet.Status.Properties {
-                               if prop.Default != "" {
-                                       // Check whether user specified a value
-                                       userDefined := false
-                                       propName := 
fmt.Sprintf("camel.kamelet.%s.%s", kamelet.Name, prop.Name)
-                                       propPrefix := propName + "="
-                                       for _, userProp := range 
e.Integration.Spec.Configuration {
-                                               if 
strings.HasPrefix(userProp.Value, propPrefix) {
-                                                       userDefined = true
-                                                       break
-                                               }
-                                       }
-                                       if !userDefined {
-                                               
e.ApplicationProperties[propName] = prop.Default
-                                       }
-                               }
-                       }
-               }
+func initializeConfigmapBundle(name, namespace string) corev1.ConfigMap {
+       return corev1.ConfigMap{
+               TypeMeta: metav1.TypeMeta{
+                       Kind:       "ConfigMap",
+                       APIVersion: "v1",
+               },
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      fmt.Sprintf("kamelets-bundle-%s", name),
+                       Namespace: namespace,
+                       Labels: map[string]string{
+                               v1.IntegrationLabel:           name,
+                               kubernetes.ConfigMapTypeLabel: 
"kamelets-bundle",
+                       },
+                       Annotations: map[string]string{
+                               kubernetes.ConfigMapAutogenLabel: "true",
+                       },
+               },
+               Data: map[string]string{},
        }
-       return nil
 }
 
+// This func will add a Kamelet as a generated Integration source. The source 
included here is going to be used in order to parse the Kamelet
+// for any component or capability (ie, rest) which is included in the Kamelet 
spec itself. However, the generated source is marked as coming `FromKamelet`.
+// When mounting the sources, these generated sources won't be mounted as 
sources but as Kamelet instead.
 func (t *kameletsTrait) addKameletAsSource(e *Environment, kamelet 
*v1.Kamelet) error {
        sources := make([]v1.SourceSpec, 0)
 
@@ -241,7 +247,8 @@ func (t *kameletsTrait) addKameletAsSource(e *Environment, 
kamelet *v1.Kamelet)
                                Name:    fmt.Sprintf("%s.yaml", kamelet.Name),
                                Content: string(flowData),
                        },
-                       Language: v1.LanguageYaml,
+                       Language:    v1.LanguageYaml,
+                       FromKamelet: true,
                }
                flowSource, err = integrationSourceFromKameletSource(e, 
kamelet, flowSource, fmt.Sprintf("%s-kamelet-%s-template", e.Integration.Name, 
kamelet.Name))
                if err != nil {
@@ -363,18 +370,28 @@ func integrationSourceFromKameletSource(e *Environment, 
kamelet *v1.Kamelet, sou
        if err != nil {
                return v1.SourceSpec{}, err
        }
+       cm := initializeConfigmapKameletSource(source, hash, name, 
e.Integration.Namespace, e.Integration.Name, kamelet.Name)
+       e.Resources.Add(&cm)
 
-       cm := corev1.ConfigMap{
+       target := source.DeepCopy()
+       target.Content = ""
+       target.ContentRef = name
+       target.ContentKey = contentKey
+       return *target, nil
+}
+
+func initializeConfigmapKameletSource(source v1.SourceSpec, hash, name, 
namespace, itName, kamName string) corev1.ConfigMap {
+       return corev1.ConfigMap{
                TypeMeta: metav1.TypeMeta{
                        Kind:       "ConfigMap",
                        APIVersion: "v1",
                },
                ObjectMeta: metav1.ObjectMeta{
                        Name:      name,
-                       Namespace: e.Integration.Namespace,
+                       Namespace: namespace,
                        Labels: map[string]string{
-                               "camel.apache.org/integration": 
e.Integration.Name,
-                               "camel.apache.org/kamelet":     kamelet.Name,
+                               "camel.apache.org/integration": itName,
+                               "camel.apache.org/kamelet":     kamName,
                        },
                        Annotations: map[string]string{
                                "camel.apache.org/source.language":    
string(source.Language),
@@ -389,12 +406,4 @@ func integrationSourceFromKameletSource(e *Environment, 
kamelet *v1.Kamelet, sou
                        contentKey: source.Content,
                },
        }
-
-       e.Resources.Add(&cm)
-
-       target := source.DeepCopy()
-       target.Content = ""
-       target.ContentRef = name
-       target.ContentKey = contentKey
-       return *target, nil
 }
diff --git a/pkg/trait/kamelets_test.go b/pkg/trait/kamelets_test.go
index a91bc9c71..96a80b5a7 100644
--- a/pkg/trait/kamelets_test.go
+++ b/pkg/trait/kamelets_test.go
@@ -109,7 +109,7 @@ func TestKameletLookup(t *testing.T) {
        require.NoError(t, err)
        cm := environment.Resources.GetConfigMap(func(_ *corev1.ConfigMap) bool 
{ return true })
        assert.NotNil(t, cm)
-       assert.Equal(t, "it-kamelet-timer-template", cm.Name)
+       assert.Equal(t, "kamelets-bundle-it", cm.Name)
        assert.Equal(t, "test", cm.Namespace)
 
        assert.Len(t, environment.Integration.Status.GeneratedSources, 1)
@@ -209,7 +209,7 @@ func TestNonYAMLKameletLookup(t *testing.T) {
        require.NoError(t, err)
        cm := environment.Resources.GetConfigMap(func(_ *corev1.ConfigMap) bool 
{ return true })
        assert.NotNil(t, cm)
-       assert.Equal(t, "it-kamelet-timer-000", cm.Name)
+       assert.Equal(t, "kamelets-bundle-it", cm.Name)
        assert.Equal(t, "test", cm.Namespace)
 
        assert.Len(t, environment.Integration.Status.GeneratedSources, 1)
@@ -480,7 +480,7 @@ func TestKameletConditionFalse(t *testing.T) {
        assert.Equal(t, corev1.ConditionFalse, cond.Status)
        assert.Equal(t, v1.IntegrationConditionKameletsAvailableReason, 
cond.Reason)
        assert.Contains(t, cond.Message, "[timer] found")
-       assert.Contains(t, cond.Message, "[none] not found")
+       assert.Contains(t, cond.Message, "kamelets [none] not found")
 }
 
 func TestKameletConditionTrue(t *testing.T) {
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index 614f6fdc8..05ee587ce 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -419,6 +419,7 @@ func (e *Environment) computeApplicationProperties() 
(*corev1.ConfigMap, error)
                                Labels: map[string]string{
                                        v1.IntegrationLabel:                
e.Integration.Name,
                                        "camel.apache.org/properties.type": 
"application",
+                                       kubernetes.ConfigMapTypeLabel:      
"camel-properties",
                                },
                        },
                        Data: map[string]string{
@@ -436,7 +437,8 @@ func (e *Environment) addSourcesProperties() {
        }
        idx := 0
        for _, s := range e.Integration.Sources() {
-               if e.isEmbedded(s) {
+               // We don't process routes embedded (native) or Kamelets
+               if e.isEmbedded(s) || s.IsGeneratedFromKamelet() {
                        continue
                }
                srcName := strings.TrimPrefix(filepath.ToSlash(s.Name), "/")
@@ -481,14 +483,14 @@ func (e *Environment) addSourcesProperties() {
 }
 
 func (e *Environment) configureVolumesAndMounts(vols *[]corev1.Volume, mnts 
*[]corev1.VolumeMount) {
-       //
-       // Volumes :: Sources
-       //
+       // Sources
        idx := 0
        for _, s := range e.Integration.Sources() {
-               if e.isEmbedded(s) {
+               // We don't process routes embedded (native) or Kamelets
+               if e.isEmbedded(s) || s.IsGeneratedFromKamelet() {
                        continue
                }
+               // Routes are copied under /etc/camel/sources and discovered by 
the runtime accordingly
                cmName := fmt.Sprintf("%s-source-%03d", e.Integration.Name, idx)
                if s.ContentRef != "" {
                        cmName = s.ContentRef
@@ -507,24 +509,38 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
                *mnts = append(*mnts, *mnt)
                idx++
        }
-
+       // Resources (likely application properties or kamelets)
        if e.Resources != nil {
                e.Resources.VisitConfigMap(func(configMap *corev1.ConfigMap) {
-                       propertiesType := 
configMap.Labels["camel.apache.org/properties.type"]
-                       resName := propertiesType + ".properties"
-
-                       var mountPath string
-                       switch propertiesType {
-                       case "application":
-                               mountPath = filepath.Join(camel.BasePath, 
resName)
-                       case "user":
-                               mountPath = filepath.Join(camel.ConfDPath, 
resName)
-                       }
-
-                       if propertiesType != "" {
-                               refName := propertiesType + "-properties"
-                               vol := getVolume(refName, "configmap", 
configMap.Name, "application.properties", resName)
-                               mnt := getMount(refName, mountPath, resName, 
true)
+                       // Camel properties
+                       if configMap.Labels[kubernetes.ConfigMapTypeLabel] == 
"camel-properties" {
+                               propertiesType := 
configMap.Labels["camel.apache.org/properties.type"]
+                               resName := propertiesType + ".properties"
+
+                               var mountPath string
+                               switch propertiesType {
+                               case "application":
+                                       mountPath = 
filepath.Join(camel.BasePath, resName)
+                               case "user":
+                                       mountPath = 
filepath.Join(camel.ConfDPath, resName)
+                               }
+
+                               if propertiesType != "" {
+                                       refName := propertiesType + 
"-properties"
+                                       vol := getVolume(refName, "configmap", 
configMap.Name, "application.properties", resName)
+                                       mnt := getMount(refName, mountPath, 
resName, true)
+
+                                       *vols = append(*vols, *vol)
+                                       *mnts = append(*mnts, *mnt)
+                               } else {
+                                       log.WithValues("Function", 
"trait.configureVolumesAndMounts").Infof("Warning: could not determine camel 
properties type %s", propertiesType)
+                               }
+                       } else if 
configMap.Labels[kubernetes.ConfigMapTypeLabel] == "kamelets-bundle" {
+                               // Kamelets bundle configmap
+                               kameletMountPoint := 
strings.ReplaceAll(e.ApplicationProperties[KameletLocationProperty], "file:", 
"")
+                               refName := "kamelets-bundle"
+                               vol := getVolume(refName, "configmap", 
configMap.Name, "", "")
+                               mnt := getMount(refName, kameletMountPoint, "", 
true)
 
                                *vols = append(*vols, *vol)
                                *mnts = append(*mnts, *mnt)
@@ -532,9 +548,8 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
                })
        }
 
-       //
-       // Volumes :: Additional ConfigMaps
-       //
+       // Deprecated - should use mount trait
+       // User provided configmaps
        for _, configmaps := range e.collectConfigurations("configmap") {
                refName := kubernetes.SanitizeLabel(configmaps["value"])
                mountPath := getMountPoint(configmaps["value"], 
configmaps["resourceMountPoint"], "configmap", configmaps["resourceType"])
@@ -545,9 +560,8 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
                *mnts = append(*mnts, *mnt)
        }
 
-       //
-       // Volumes :: Additional Secrets
-       //
+       // Deprecated - should use mount trait
+       // User provided secrets
        for _, secret := range e.collectConfigurations("secret") {
                refName := kubernetes.SanitizeLabel(secret["value"])
                mountPath := getMountPoint(secret["value"], 
secret["resourceMountPoint"], "secret", secret["resourceType"])
@@ -568,10 +582,8 @@ func (e *Environment) configureVolumesAndMounts(vols 
*[]corev1.Volume, mnts *[]c
                *vols = append(*vols, *vol)
                *mnts = append(*mnts, *mnt)
        }
-
-       //
-       // Volumes :: Additional user provided volumes
-       //
+       // Deprecated - should use mount trait
+       // User provided volumes
        for _, volumeConfig := range e.collectConfigurationValues("volume") {
                configParts := strings.Split(volumeConfig, ":")
 
diff --git a/pkg/util/kubernetes/factory.go b/pkg/util/kubernetes/factory.go
index 1915c76d9..5bf26ce12 100644
--- a/pkg/util/kubernetes/factory.go
+++ b/pkg/util/kubernetes/factory.go
@@ -39,6 +39,9 @@ const ConfigMapAutogenLabel = "camel.apache.org/generated"
 // ConfigMapOriginalFileNameLabel -- .
 const ConfigMapOriginalFileNameLabel = "camel.apache.org/filename"
 
+// ConfigMapTypeLabel -- .
+const ConfigMapTypeLabel = "camel.apache.org/config.type"
+
 // NewTolerations build an array of Tolerations from an array of string.
 func NewTolerations(taints []string) ([]corev1.Toleration, error) {
        tolerations := make([]corev1.Toleration, 0)
diff --git a/resources/traits.yaml b/resources/traits.yaml
index 4489f2040..6b9357beb 100755
--- a/resources/traits.yaml
+++ b/resources/traits.yaml
@@ -909,6 +909,10 @@ traits:
   - name: list
     type: string
     description: Comma separated list of Kamelet names to load into the 
current integration
+  - name: mount-point
+    type: string
+    description: The directory where the application mounts and reads Kamelet 
spec
+      (default `/etc/camel/kamelets`)
 - name: keda
   platform: false
   profiles:


Reply via email to