You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2021/06/08 19:21:22 UTC

[camel-k] branch camel-main updated (4dcbe4a -> 621e557)

This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a change to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-k.git.


    from 4dcbe4a  Updated CHANGELOG.md
     new 230df00  kamelet binding: use the Kamelet EIP for steps #2370
     new fad493b  languages: support kamelet eip #2375
     new 621e557  kameletbinding: remove the need of allocation some intermediate slices

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 pkg/controller/kameletbinding/common.go            | 94 ++++++++++++++-------
 pkg/resources/resources.go                         |  4 +-
 pkg/trait/kamelets.go                              | 24 +-----
 pkg/util/bindings/api.go                           |  2 +
 pkg/util/bindings/kamelet.go                       | 23 +++--
 pkg/util/bindings/kamelet_test.go                  | 92 ++++++++++++++++++++
 pkg/util/source/inspector.go                       | 12 +++
 pkg/util/source/inspector_groovy.go                | 10 +++
 pkg/util/source/inspector_groovy_test.go           | 97 ++++++++++++++++++++++
 pkg/util/source/inspector_java_script.go           | 10 +++
 pkg/util/source/inspector_java_script_test.go      | 81 ++++++++++++++++++
 pkg/util/source/inspector_java_source.go           | 10 +++
 pkg/util/source/inspector_java_source_test.go      | 81 ++++++++++++++++++
 .../common.go => util/source/inspector_kamelet.go} | 38 ++++-----
 pkg/util/source/inspector_kotlin.go                | 10 +++
 pkg/util/source/inspector_kotlin_test.go           | 81 ++++++++++++++++++
 pkg/util/source/inspector_xml.go                   |  7 ++
 pkg/util/source/inspector_xml_test.go              | 90 ++++++++++++++++++++
 pkg/util/source/inspector_yaml.go                  |  8 ++
 pkg/util/source/inspector_yaml_test.go             | 92 ++++++++++++++++++++
 pkg/util/source/types.go                           |  2 +
 21 files changed, 787 insertions(+), 81 deletions(-)
 create mode 100644 pkg/util/bindings/kamelet_test.go
 create mode 100644 pkg/util/source/inspector_groovy_test.go
 create mode 100644 pkg/util/source/inspector_java_script_test.go
 create mode 100644 pkg/util/source/inspector_java_source_test.go
 copy pkg/{kamelet/repository/common.go => util/source/inspector_kamelet.go} (54%)
 create mode 100644 pkg/util/source/inspector_kotlin_test.go
 create mode 100644 pkg/util/source/inspector_xml_test.go

[camel-k] 01/03: kamelet binding: use the Kamelet EIP for steps #2370

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 230df00404a0650369e656aa0d8a1a183534a649
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Tue Jun 8 12:18:54 2021 +0200

    kamelet binding: use the Kamelet EIP for steps #2370
---
 pkg/controller/kameletbinding/common.go | 42 ++++++++++++---
 pkg/resources/resources.go              |  8 ---
 pkg/util/bindings/api.go                |  2 +
 pkg/util/bindings/kamelet.go            | 23 +++++----
 pkg/util/bindings/kamelet_test.go       | 92 +++++++++++++++++++++++++++++++++
 5 files changed, 142 insertions(+), 25 deletions(-)

diff --git a/pkg/controller/kameletbinding/common.go b/pkg/controller/kameletbinding/common.go
index 4ad94ba..bd952ab 100644
--- a/pkg/controller/kameletbinding/common.go
+++ b/pkg/controller/kameletbinding/common.go
@@ -36,6 +36,9 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+var endpointTypeSourceContext = bindings.EndpointContext{Type: v1alpha1.EndpointTypeSource}
+var endpointTypeSinkContext = bindings.EndpointContext{Type: v1alpha1.EndpointTypeSink}
+
 func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *v1alpha1.KameletBinding) (*v1.Integration, error) {
 	controller := true
 	blockOwnerDeletion := true
@@ -83,11 +86,11 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 		Profile:   profile,
 	}
 
-	from, err := bindings.Translate(bindingContext, bindings.EndpointContext{Type: v1alpha1.EndpointTypeSource}, kameletbinding.Spec.Source)
+	from, err := bindings.Translate(bindingContext, endpointTypeSourceContext, kameletbinding.Spec.Source)
 	if err != nil {
 		return nil, errors.Wrap(err, "could not determine source URI")
 	}
-	to, err := bindings.Translate(bindingContext, bindings.EndpointContext{Type: v1alpha1.EndpointTypeSink}, kameletbinding.Spec.Sink)
+	to, err := bindings.Translate(bindingContext, endpointTypeSinkContext, kameletbinding.Spec.Sink)
 	if err != nil {
 		return nil, errors.Wrap(err, "could not determine sink URI")
 	}
@@ -110,6 +113,18 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 		steps = append(steps, stepBinding)
 	}
 
+	if to.Step == nil && to.URI == "" {
+		return nil, errors.Errorf("illegal step definition for sink step: either Step or URI should be provided")
+	}
+	if from.URI == "" {
+		return nil, errors.Errorf("illegal step definition for source step: URI should be provided")
+	}
+	for index, step := range steps {
+		if step.Step == nil && step.URI == "" {
+			return nil, errors.Errorf("illegal step definition for step %d: either Step or URI should be provided", index)
+		}
+	}
+
 	allBindings := make([]*bindings.Binding, 0, len(steps)+3)
 	allBindings = append(allBindings, from)
 	allBindings = append(allBindings, steps...)
@@ -141,13 +156,24 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 
 	dslSteps := make([]map[string]interface{}, 0)
 	for _, step := range steps {
-		dslSteps = append(dslSteps, map[string]interface{}{
-			"to": step.URI,
-		})
+		s := step.Step
+		if s == nil {
+			s = map[string]interface{}{
+				"to": step.URI,
+			}
+		}
+
+		dslSteps = append(dslSteps, s)
+	}
+
+	s := to.Step
+	if s == nil {
+		s = map[string]interface{}{
+			"to": to.URI,
+		}
 	}
-	dslSteps = append(dslSteps, map[string]interface{}{
-		"to": to.URI,
-	})
+
+	dslSteps = append(dslSteps, s)
 
 	flowFrom := map[string]interface{}{
 		"from": map[string]interface{}{
diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index 87305c1..ad5e8eb 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -464,13 +464,6 @@ var assets = func() http.FileSystem {
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x4b\x77\xdb\x3a\x96\xee\x3c\xbf\x82\xeb\x64\xd2\xbd\x6e\x09\x75\x4e\x52\xb7\x4f\xdf\xdc\x91\x2d\xc7\x89\x1d\xcb\x71\x22\x57\x92\xaa\xc9\x59\x10\x09\x51\xb0\x48\x82\x06\x40\x59\xce\xaf\xef\x85\x07\x9f\x52\x36\x1f\x06\xd4\x1a\x88\x20\xb1\xf1\x6d\xec\x0f\x0f\x12\xef\xd7\xc1\xcc\xdd\xef\xd5\xeb\xe0\x86\x86\x24\x13\x24\x0a\x24\x0b\xe4\x86\x04\x67\x39\x0e\x37\x24\x58\xb2\xb5\x7c\xc2\x9c\x04\x97\xac\xc8\x22\x2c\x29\x [...]
 		},
-		"/camel-catalog-1.9.0-SNAPSHOT.yaml": &vfsgen۰CompressedFileInfo{
-			name:             "camel-catalog-1.9.0-SNAPSHOT.yaml",
-			modTime:          time.Time{},
-			uncompressedSize: 89713,
-
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x5b\x77\xdb\x38\xb6\xe6\x7b\x7e\x05\x57\xe5\xe5\x9c\x35\x2d\x74\x55\xaa\xe7\xd4\x4c\xcd\x93\x23\xc7\x89\x1d\xcb\x71\x22\x77\x92\xee\x97\x5a\x10\x09\x49\xb0\x48\x82\x06\x40\x59\xce\xaf\x9f\x05\x10\xbc\x4a\xd9\xbc\x78\xc3\xad\x07\xf1\x82\x8d\x6f\x63\x7f\xb8\x10\x77\xbc\x0e\x66\x78\xbf\x57\xaf\x83\x6b\x1e\xb2\x54\xb1\x28\xd0\x22\xd0\x5b\x16\x9c\x65\x34\xdc\xb2\x60\x29\xd6\xfa\x91\x4a\x16\x5c\x88\x3c\x8d\xa8\xe6\x [...]
-		},
 		"/traits.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "traits.yaml",
 			modTime:          time.Time{},
@@ -482,7 +475,6 @@ var assets = func() http.FileSystem {
 	fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
 		fs["/addons"].(os.FileInfo),
 		fs["/camel-catalog-1.7.0.yaml"].(os.FileInfo),
-		fs["/camel-catalog-1.9.0-SNAPSHOT.yaml"].(os.FileInfo),
 		fs["/crd"].(os.FileInfo),
 		fs["/default"].(os.FileInfo),
 		fs["/manager"].(os.FileInfo),
diff --git a/pkg/util/bindings/api.go b/pkg/util/bindings/api.go
index 14f09b8..c844d1e 100644
--- a/pkg/util/bindings/api.go
+++ b/pkg/util/bindings/api.go
@@ -37,6 +37,8 @@ const (
 type Binding struct {
 	// URI is the Camel URI equivalent
 	URI string
+	// Step is to support complex mapping such as Camel's EIPs
+	Step map[string]interface{}
 	// Traits is a partial trait specification that should be merged into the integration
 	Traits map[string]v1.TraitSpec
 	// ApplicationProperties contain properties that should be set on the integration for the binding to work
diff --git a/pkg/util/bindings/kamelet.go b/pkg/util/bindings/kamelet.go
index 9d3f596..d52f144 100644
--- a/pkg/util/bindings/kamelet.go
+++ b/pkg/util/bindings/kamelet.go
@@ -44,7 +44,6 @@ func (k KameletBindingProvider) Translate(ctx BindingContext, endpointCtx Endpoi
 	// it translates only Kamelet refs
 	if e.Ref.Kind == v1alpha1.KameletKind && gv.Group == v1alpha1.SchemeGroupVersion.Group {
 		kameletName := url.PathEscape(e.Ref.Name)
-		kameletURI := fmt.Sprintf("kamelet:%s", kameletName)
 
 		props, err := e.Properties.GetPropertyMap()
 		if err != nil {
@@ -57,21 +56,27 @@ func (k KameletBindingProvider) Translate(ctx BindingContext, endpointCtx Endpoi
 		} else {
 			id = endpointCtx.GenerateID()
 		}
-		kameletURI = fmt.Sprintf("%s/%s", kameletURI, url.PathEscape(id))
 
-		var applicationProperties map[string]string
+		binding := Binding{}
+		if endpointCtx.Type == v1alpha1.EndpointTypeAction {
+			binding.Step = map[string]interface{}{
+				"kamelet": map[string]interface{}{
+					"name": fmt.Sprintf("%s/%s", kameletName, url.PathEscape(id)),
+				},
+			}
+		} else {
+			binding.URI = fmt.Sprintf("kamelet:%s/%s", kameletName, url.PathEscape(id))
+		}
+
 		if len(props) > 0 {
-			applicationProperties = make(map[string]string, len(props))
+			binding.ApplicationProperties = make(map[string]string, len(props))
 			for k, v := range props {
 				propKey := fmt.Sprintf("camel.kamelet.%s.%s.%s", kameletName, id, k)
-				applicationProperties[propKey] = v
+				binding.ApplicationProperties[propKey] = v
 			}
 		}
 
-		return &Binding{
-			URI:                   kameletURI,
-			ApplicationProperties: applicationProperties,
-		}, nil
+		return &binding, nil
 	}
 	return nil, nil
 }
diff --git a/pkg/util/bindings/kamelet_test.go b/pkg/util/bindings/kamelet_test.go
new file mode 100644
index 0000000..53d7887
--- /dev/null
+++ b/pkg/util/bindings/kamelet_test.go
@@ -0,0 +1,92 @@
+/*
+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 bindings
+
+import (
+	"context"
+	"fmt"
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	corev1 "k8s.io/api/core/v1"
+
+	camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/pkg/util/test"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestKameletBindingProvider(t *testing.T) {
+	testcases := []struct {
+		endpointType v1alpha1.EndpointType
+		uri          string
+		step         map[string]interface{}
+	}{
+		{
+			endpointType: v1alpha1.EndpointTypeSource,
+			uri:          "kamelet:mykamelet/source",
+			step:         nil,
+		},
+		{
+			endpointType: v1alpha1.EndpointTypeAction,
+			uri:          "",
+			step: map[string]interface{}{
+				"kamelet": map[string]interface{}{
+					"name": "mykamelet/action",
+				},
+			},
+		},
+		{
+			endpointType: v1alpha1.EndpointTypeSink,
+			uri:          "kamelet:mykamelet/sink",
+			step:         nil,
+		},
+	}
+
+	for i, tc := range testcases {
+		t.Run(fmt.Sprintf("test-%d-%s", i, tc.uri), func(t *testing.T) {
+			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
+
+			client, err := test.NewFakeClient()
+			assert.NoError(t, err)
+
+			endpoint := v1alpha1.Endpoint{
+				Ref: &corev1.ObjectReference{
+					Kind:       "Kamelet",
+					APIVersion: "camel.apache.org/v1any1",
+					Name:       "mykamelet",
+				},
+			}
+
+			binding, err := KameletBindingProvider{}.Translate(
+				BindingContext{
+					Ctx:       ctx,
+					Client:    client,
+					Namespace: "test",
+					Profile:   camelv1.TraitProfileKubernetes,
+				},
+				EndpointContext{Type: tc.endpointType},
+				endpoint)
+
+			assert.NoError(t, err)
+			assert.NotNil(t, binding)
+			assert.Equal(t, tc.step, binding.Step)
+			assert.Equal(t, tc.uri, binding.URI)
+		})
+	}
+
+}

[camel-k] 03/03: kameletbinding: remove the need of allocation some intermediate slices

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 621e5578996957ab9aa771c6eaf15e8dda56e687
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Tue Jun 8 17:07:01 2021 +0200

    kameletbinding: remove the need of allocation some intermediate slices
---
 pkg/controller/kameletbinding/common.go | 60 +++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 26 deletions(-)

diff --git a/pkg/controller/kameletbinding/common.go b/pkg/controller/kameletbinding/common.go
index bd952ab..c68e312 100644
--- a/pkg/controller/kameletbinding/common.go
+++ b/pkg/controller/kameletbinding/common.go
@@ -125,32 +125,20 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 		}
 	}
 
-	allBindings := make([]*bindings.Binding, 0, len(steps)+3)
-	allBindings = append(allBindings, from)
-	allBindings = append(allBindings, steps...)
-	allBindings = append(allBindings, to)
-	if errorHandler != nil {
-		allBindings = append(allBindings, errorHandler)
-	}
-
-	propList := make([]string, 0)
-	for _, b := range allBindings {
-		if it.Spec.Traits == nil {
-			it.Spec.Traits = make(map[string]v1.TraitSpec)
-		}
-		for k, v := range b.Traits {
-			it.Spec.Traits[k] = v
-		}
-		for k, v := range b.ApplicationProperties {
-			propList = append(propList, fmt.Sprintf("%s=%s", k, v))
-		}
-	}
-
-	sort.Strings(propList)
-	for _, p := range propList {
-		it.Spec.Configuration = append(it.Spec.Configuration, v1.ConfigurationSpec{
-			Type:  "property",
-			Value: p,
+	configureBinding(&it, from)
+	configureBinding(&it, steps...)
+	configureBinding(&it, to)
+	configureBinding(&it, errorHandler)
+
+	if it.Spec.Configuration != nil {
+		sort.SliceStable(it.Spec.Configuration, func(i, j int) bool {
+			mi, mj := it.Spec.Configuration[i], it.Spec.Configuration[j]
+			switch {
+			case mi.Type != mj.Type:
+				return mi.Type < mj.Type
+			default:
+				return mi.Value < mj.Value
+			}
 		})
 	}
 
@@ -190,6 +178,26 @@ func createIntegrationFor(ctx context.Context, c client.Client, kameletbinding *
 	return &it, nil
 }
 
+func configureBinding(integration *v1.Integration, bindings ...*bindings.Binding) {
+	for _, b := range bindings {
+		if b == nil {
+			continue
+		}
+		if integration.Spec.Traits == nil {
+			integration.Spec.Traits = make(map[string]v1.TraitSpec)
+		}
+		for k, v := range b.Traits {
+			integration.Spec.Traits[k] = v
+		}
+		for k, v := range b.ApplicationProperties {
+			integration.Spec.Configuration = append(integration.Spec.Configuration, v1.ConfigurationSpec{
+				Type:  "property",
+				Value: fmt.Sprintf("%s=%s", k, v),
+			})
+		}
+	}
+}
+
 func determineProfile(ctx context.Context, c client.Client, binding *v1alpha1.KameletBinding) (v1.TraitProfile, error) {
 	if binding.Spec.Integration != nil && binding.Spec.Integration.Profile != "" {
 		return binding.Spec.Integration.Profile, nil

[camel-k] 02/03: languages: support kamelet eip #2375

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit fad493bccce782f3db638df4d4c7da13b7f5ff0c
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Tue Jun 8 15:02:03 2021 +0200

    languages: support kamelet eip #2375
---
 pkg/resources/resources.go                    |  8 +++
 pkg/trait/kamelets.go                         | 24 +------
 pkg/util/source/inspector.go                  | 12 ++++
 pkg/util/source/inspector_groovy.go           | 10 +++
 pkg/util/source/inspector_groovy_test.go      | 97 +++++++++++++++++++++++++++
 pkg/util/source/inspector_java_script.go      | 10 +++
 pkg/util/source/inspector_java_script_test.go | 81 ++++++++++++++++++++++
 pkg/util/source/inspector_java_source.go      | 10 +++
 pkg/util/source/inspector_java_source_test.go | 81 ++++++++++++++++++++++
 pkg/util/source/inspector_kamelet.go          | 50 ++++++++++++++
 pkg/util/source/inspector_kotlin.go           | 10 +++
 pkg/util/source/inspector_kotlin_test.go      | 81 ++++++++++++++++++++++
 pkg/util/source/inspector_xml.go              |  7 ++
 pkg/util/source/inspector_xml_test.go         | 90 +++++++++++++++++++++++++
 pkg/util/source/inspector_yaml.go             |  8 +++
 pkg/util/source/inspector_yaml_test.go        | 92 +++++++++++++++++++++++++
 pkg/util/source/types.go                      |  2 +
 17 files changed, 652 insertions(+), 21 deletions(-)

diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index ad5e8eb..0a7b203 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -464,6 +464,13 @@ var assets = func() http.FileSystem {
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x4b\x77\xdb\x3a\x96\xee\x3c\xbf\x82\xeb\x64\xd2\xbd\x6e\x09\x75\x4e\x52\xb7\x4f\xdf\xdc\x91\x2d\xc7\x89\x1d\xcb\x71\x22\x57\x92\xaa\xc9\x59\x10\x09\x51\xb0\x48\x82\x06\x40\x59\xce\xaf\xef\x85\x07\x9f\x52\x36\x1f\x06\xd4\x1a\x88\x20\xb1\xf1\x6d\xec\x0f\x0f\x12\xef\xd7\xc1\xcc\xdd\xef\xd5\xeb\xe0\x86\x86\x24\x13\x24\x0a\x24\x0b\xe4\x86\x04\x67\x39\x0e\x37\x24\x58\xb2\xb5\x7c\xc2\x9c\x04\x97\xac\xc8\x22\x2c\x29\x [...]
 		},
+		"/camel-catalog-1.9.0-SNAPSHOT.yaml": &vfsgen۰CompressedFileInfo{
+			name:             "camel-catalog-1.9.0-SNAPSHOT.yaml",
+			modTime:          time.Time{},
+			uncompressedSize: 89731,
+
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x5b\x77\xdb\x38\xb6\xe6\x7b\x7e\x05\x57\xe5\xe5\x9c\x35\x2d\x74\x55\xaa\xe7\xd4\x4c\xcd\x93\x23\xc7\x89\x1d\xcb\x71\x22\x77\x92\xee\x97\x5a\x10\x09\x49\xb0\x48\x82\x06\x40\x59\xce\xaf\x9f\x05\x10\xbc\x4a\xd9\xbc\x78\xc3\xad\x07\xf1\x82\x8d\x6f\x63\x7f\xb8\x10\x77\xbc\x0e\x66\x78\xbf\x57\xaf\x83\x6b\x1e\xb2\x54\xb1\x28\xd0\x22\xd0\x5b\x16\x9c\x65\x34\xdc\xb2\x60\x29\xd6\xfa\x91\x4a\x16\x5c\x88\x3c\x8d\xa8\xe6\x [...]
+		},
 		"/traits.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "traits.yaml",
 			modTime:          time.Time{},
@@ -475,6 +482,7 @@ var assets = func() http.FileSystem {
 	fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
 		fs["/addons"].(os.FileInfo),
 		fs["/camel-catalog-1.7.0.yaml"].(os.FileInfo),
+		fs["/camel-catalog-1.9.0-SNAPSHOT.yaml"].(os.FileInfo),
 		fs["/crd"].(os.FileInfo),
 		fs["/default"].(os.FileInfo),
 		fs["/manager"].(os.FileInfo),
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index 8ef161d..1f3cdef 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -20,6 +20,7 @@ package trait
 import (
 	"errors"
 	"fmt"
+	"github.com/apache/camel-k/pkg/util/source"
 	"regexp"
 	"sort"
 	"strconv"
@@ -102,8 +103,7 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 				return false, err
 			}
 			metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
-				util.StringSliceUniqueConcat(&kamelets, extractKamelets(meta.FromURIs))
-				util.StringSliceUniqueConcat(&kamelets, extractKamelets(meta.ToURIs))
+				util.StringSliceUniqueConcat(&kamelets, meta.Kamelets)
 				return true
 			})
 		}
@@ -111,7 +111,7 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 		defaultErrorHandlerURI := e.Integration.Spec.GetConfigurationProperty(v1alpha1.ErrorHandlerAppPropertiesPrefix + ".deadLetterUri")
 		if defaultErrorHandlerURI != "" {
 			if strings.HasPrefix(defaultErrorHandlerURI, "kamelet:") {
-				kamelets = append(kamelets, extractKamelet(defaultErrorHandlerURI))
+				kamelets = append(kamelets, source.ExtractKamelet(defaultErrorHandlerURI))
 			}
 		}
 
@@ -444,21 +444,3 @@ func integrationSourceFromKameletSource(e *Environment, kamelet *v1alpha1.Kamele
 	target.ContentKey = contentKey
 	return *target, nil
 }
-
-func extractKamelets(uris []string) (kamelets []string) {
-	for _, uri := range uris {
-		kamelet := extractKamelet(uri)
-		if kamelet != "" {
-			kamelets = append(kamelets, kamelet)
-		}
-	}
-	return
-}
-
-func extractKamelet(uri string) (kamelet string) {
-	matches := kameletNameRegexp.FindStringSubmatch(uri)
-	if len(matches) > 1 {
-		return matches[1]
-	}
-	return ""
-}
diff --git a/pkg/util/source/inspector.go b/pkg/util/source/inspector.go
index 550d334..c2f80fd 100644
--- a/pkg/util/source/inspector.go
+++ b/pkg/util/source/inspector.go
@@ -58,6 +58,8 @@ var (
 	xqueryRegexp            = regexp.MustCompile(`.*\.xquery\s*\(.*\).*`)
 	xpathRegexp             = regexp.MustCompile(`.*\.?xpath\s*\(.*\).*`)
 	xtokenizeRegexp         = regexp.MustCompile(`.*\.xtokenize\s*\(.*\).*`)
+	singleQuotedKameletEip  = regexp.MustCompile(`kamelet\s*\(\s*'(?://)?([a-z0-9-.]+(/[a-z0-9-.]+)?)(?:$|[^a-z0-9-.].*)'`)
+	doubleQuotedKameletEip  = regexp.MustCompile(`kamelet\s*\(\s*"(?://)?([a-z0-9-.]+(/[a-z0-9-.]+)?)(?:$|[^a-z0-9-.].*)"`)
 
 	sourceCapabilities = map[*regexp.Regexp][]string{
 		circuitBreakerRegexp: {v1.CapabilityCircuitBreaker},
@@ -287,6 +289,16 @@ func (i *baseInspector) discoverDependencies(source v1.SourceSpec, meta *Metadat
 	}
 }
 
+// discoverDependencies inspects endpoints and extract kamelets
+func (i *baseInspector) discoverKamelets(source v1.SourceSpec, meta *Metadata) {
+	for _, uri := range meta.FromURIs {
+		AddKamelet(meta, uri)
+	}
+	for _, uri := range meta.ToURIs {
+		AddKamelet(meta, uri)
+	}
+}
+
 func (i *baseInspector) addDependency(dependency string, meta *Metadata) {
 	meta.Dependencies.Add(dependency)
 }
diff --git a/pkg/util/source/inspector_groovy.go b/pkg/util/source/inspector_groovy.go
index 1a49f71..3181078 100644
--- a/pkg/util/source/inspector_groovy.go
+++ b/pkg/util/source/inspector_groovy.go
@@ -47,8 +47,18 @@ func (i GroovyInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content) || restClosureRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_groovy_test.go b/pkg/util/source/inspector_groovy_test.go
new file mode 100644
index 0000000..b69aa28
--- /dev/null
+++ b/pkg/util/source/inspector_groovy_test.go
@@ -0,0 +1,97 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const GroovyKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const GroovyKameletEip_SingleQuote = `
+from("direct:start")
+    .kamelet('foo/bar?baz=test')
+`
+const GroovyKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+const GroovyKameletEndpoint_SingleQuote = `
+from("direct:start")
+    .to('kamelet:foo/bar?baz=test')
+`
+
+func TestGroovyKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   GroovyKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   GroovyKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   GroovyKameletEip_SingleQuote,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   GroovyKameletEndpoint_SingleQuote,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestGroovyKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := GroovyInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_java_script.go b/pkg/util/source/inspector_java_script.go
index dfc4b04..d8679e0 100644
--- a/pkg/util/source/inspector_java_script.go
+++ b/pkg/util/source/inspector_java_script.go
@@ -47,8 +47,18 @@ func (i JavaScriptInspector) Extract(source v1.SourceSpec, meta *Metadata) error
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_java_script_test.go b/pkg/util/source/inspector_java_script_test.go
new file mode 100644
index 0000000..20f0a7b
--- /dev/null
+++ b/pkg/util/source/inspector_java_script_test.go
@@ -0,0 +1,81 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const JavaScriptKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const JavaScriptKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+
+func TestJavaScriptKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   JavaScriptKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   JavaScriptKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestJavaScriptKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := JavaScriptInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_java_source.go b/pkg/util/source/inspector_java_source.go
index 354370f..80981e7 100644
--- a/pkg/util/source/inspector_java_source.go
+++ b/pkg/util/source/inspector_java_source.go
@@ -42,8 +42,18 @@ func (i JavaSourceInspector) Extract(source v1.SourceSpec, meta *Metadata) error
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_java_source_test.go b/pkg/util/source/inspector_java_source_test.go
new file mode 100644
index 0000000..52a7bf0
--- /dev/null
+++ b/pkg/util/source/inspector_java_source_test.go
@@ -0,0 +1,81 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const JavaSourceKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const JavaSourceKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+
+func TestJavaSourceKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   JavaSourceKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   JavaSourceKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestJavaSourceKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := JavaSourceInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_kamelet.go b/pkg/util/source/inspector_kamelet.go
new file mode 100644
index 0000000..3ae82a3
--- /dev/null
+++ b/pkg/util/source/inspector_kamelet.go
@@ -0,0 +1,50 @@
+/*
+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 source
+
+import (
+	"regexp"
+)
+
+var (
+	kameletNameRegexp = regexp.MustCompile("kamelet:(?://)?([a-z0-9-.]+(/[a-z0-9-.]+)?)(?:$|[^a-z0-9-.].*)")
+)
+
+func ExtractKamelets(uris []string) (kamelets []string) {
+	for _, uri := range uris {
+		kamelet := ExtractKamelet(uri)
+		if kamelet != "" {
+			kamelets = append(kamelets, kamelet)
+		}
+	}
+	return
+}
+
+func ExtractKamelet(uri string) (kamelet string) {
+	matches := kameletNameRegexp.FindStringSubmatch(uri)
+	if len(matches) > 1 {
+		return matches[1]
+	}
+	return ""
+}
+
+func AddKamelet(meta *Metadata, content string) {
+	if maybeKamelet := ExtractKamelet(content); maybeKamelet != "" {
+		meta.Kamelets = append(meta.Kamelets, maybeKamelet)
+	}
+}
diff --git a/pkg/util/source/inspector_kotlin.go b/pkg/util/source/inspector_kotlin.go
index 6de0a23..b2485c2 100644
--- a/pkg/util/source/inspector_kotlin.go
+++ b/pkg/util/source/inspector_kotlin.go
@@ -42,8 +42,18 @@ func (i KotlinInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content) || restClosureRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_kotlin_test.go b/pkg/util/source/inspector_kotlin_test.go
new file mode 100644
index 0000000..bd4c7ce
--- /dev/null
+++ b/pkg/util/source/inspector_kotlin_test.go
@@ -0,0 +1,81 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const KotlinKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const KotlinKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+
+func TestKotlinKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   KotlinKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   KotlinKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestKotlinKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := KotlinInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_xml.go b/pkg/util/source/inspector_xml.go
index a1f1a9c..40c5489 100644
--- a/pkg/util/source/inspector_xml.go
+++ b/pkg/util/source/inspector_xml.go
@@ -68,6 +68,12 @@ func (i XMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 						meta.ToURIs = append(meta.ToURIs, a.Value)
 					}
 				}
+			case "kamelet":
+				for _, a := range se.Attr {
+					if a.Name.Local == "name" {
+						AddKamelet(meta, "kamelet:"+a.Value)
+					}
+				}
 			}
 
 			if dependency, ok := i.catalog.GetLanguageDependency(se.Name.Local); ok {
@@ -78,6 +84,7 @@ func (i XMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	meta.ExposesHTTPServices = meta.ExposesHTTPServices || i.containsHTTPURIs(meta.FromURIs)
 	meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs)
diff --git a/pkg/util/source/inspector_xml_test.go b/pkg/util/source/inspector_xml_test.go
new file mode 100644
index 0000000..75102a4
--- /dev/null
+++ b/pkg/util/source/inspector_xml_test.go
@@ -0,0 +1,90 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const XMLKameletEip = `
+<camelContext xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="direct:start"/>
+    <kamelet name="foo/bar?baz=test"/>
+    <to uri="mock:result"/>
+  </route>
+</camelContext>
+`
+const XMLKameletEndpoint = `
+<camelContext xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="direct:start"/>
+    <to uri="kamelet:foo/bar?baz=test"/>
+  </route>
+</camelContext>
+`
+
+func TestXMLKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   XMLKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   XMLKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestXMLKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := XMLInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_yaml.go b/pkg/util/source/inspector_yaml.go
index 04a00f7..b5f9846 100644
--- a/pkg/util/source/inspector_yaml.go
+++ b/pkg/util/source/inspector_yaml.go
@@ -48,6 +48,7 @@ func (i YAMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	meta.ExposesHTTPServices = meta.ExposesHTTPServices || i.containsHTTPURIs(meta.FromURIs)
 	meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs)
@@ -87,6 +88,13 @@ func (i YAMLInspector) parseStep(key string, content interface{}, meta *Metadata
 				}
 			}
 		}
+	case "kamelet":
+		switch t := content.(type) {
+		case string:
+			AddKamelet(meta, "kamelet:"+t)
+		case map[interface{}]interface{}:
+			AddKamelet(meta, "kamelet:"+t["name"].(string))
+		}
 	}
 
 	var maybeURI string
diff --git a/pkg/util/source/inspector_yaml_test.go b/pkg/util/source/inspector_yaml_test.go
index 5858309..69ed703 100644
--- a/pkg/util/source/inspector_yaml_test.go
+++ b/pkg/util/source/inspector_yaml_test.go
@@ -327,3 +327,95 @@ func TestYAMLJson(t *testing.T) {
 		})
 	}
 }
+
+const YAMLKameletEipNoId = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: "foo"
+`
+
+const YAMLKameletEipInline = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: "foo/bar?baz=test"
+`
+const YAMLKameletEipMap = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: 
+        name: "foo/bar?baz=test"
+`
+const YAMLKameletEipMapWithParams = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: 
+        name: "foo/bar"
+        parameters:
+          baz:test
+`
+const YAMLKameletEndpoint = `
+- from:
+    uri: timer:tick
+    steps:
+    - to: "kamelet:foo/bar?baz=test"
+`
+
+func TestYAMLKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   YAMLKameletEipNoId,
+			kamelets: []string{"foo"},
+		},
+		{
+			source:   YAMLKameletEipInline,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   YAMLKameletEipMap,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   YAMLKameletEipMapWithParams,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   YAMLKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestYAMLKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := YAMLInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/types.go b/pkg/util/source/types.go
index f6f15e0..9bbbaa5 100644
--- a/pkg/util/source/types.go
+++ b/pkg/util/source/types.go
@@ -37,6 +37,8 @@ type Metadata struct {
 	// RequiredCapabilities lists the capabilities required by the integration
 	// to run
 	RequiredCapabilities *strset.Set
+	// All kamelets
+	Kamelets []string
 }
 
 // NewMetadata --