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

pcongiusti pushed a commit to branch release-2.3.x
in repository https://gitbox.apache.org/repos/asf/camel-k.git


The following commit(s) were added to refs/heads/release-2.3.x by this push:
     new aa6202c51 fix(trait): remove imageWasKit
aa6202c51 is described below

commit aa6202c51726f953009054bdca38b03668c499ba
Author: Pasquale Congiusti <pasquale.congiu...@gmail.com>
AuthorDate: Wed Apr 24 17:18:43 2024 +0200

    fix(trait): remove imageWasKit
    
    As discussed in #5399 we need to clarify the intent of each IntegrationKit 
types.
    
    * removal of imageWasKit
    * usage of external IntegrationKit when we are certain that the image comes 
from an IK
    * usage of syntetic IntegrationKit when the image are coming from any 
container image
    * rework of promote command to clone an external IntegrationKit beside the 
Integration and use it accordingly.
    
    Closes #5408
---
 .../modules/ROOT/pages/running/camel-runtimes.adoc |   6 +-
 docs/modules/ROOT/pages/running/promoting.adoc     |  14 +-
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc  |  11 +-
 docs/modules/traits/pages/container.adoc           |   8 +-
 e2e/advanced/operator_id_filtering_test.go         |  34 +++-
 e2e/install/cli/global_test.go                     |  30 +---
 e2e/support/test_support.go                        |  10 ++
 helm/camel-k/crds/crd-integration-platform.yaml    |  24 +--
 helm/camel-k/crds/crd-integration-profile.yaml     |  24 +--
 helm/camel-k/crds/crd-integration.yaml             |  12 +-
 helm/camel-k/crds/crd-kamelet-binding.yaml         |  13 +-
 helm/camel-k/crds/crd-pipe.yaml                    |  13 +-
 pkg/apis/camel/v1/trait/container.go               |   6 +-
 pkg/apis/camel/v1/trait/zz_generated.deepcopy.go   |   5 -
 pkg/cmd/promote.go                                 | 104 +++++++++---
 pkg/cmd/promote_test.go                            | 181 ++++++++++++++++-----
 pkg/cmd/run.go                                     |   8 +
 .../camel.apache.org_integrationplatforms.yaml     |  24 +--
 .../camel.apache.org_integrationprofiles.yaml      |  24 +--
 .../crd/bases/camel.apache.org_integrations.yaml   |  12 +-
 .../bases/camel.apache.org_kameletbindings.yaml    |  13 +-
 .../config/crd/bases/camel.apache.org_pipes.yaml   |  13 +-
 pkg/trait/container.go                             |   3 -
 23 files changed, 390 insertions(+), 202 deletions(-)

diff --git a/docs/modules/ROOT/pages/running/camel-runtimes.adoc 
b/docs/modules/ROOT/pages/running/camel-runtimes.adoc
index e18dc3607..a3bc3b4e5 100644
--- a/docs/modules/ROOT/pages/running/camel-runtimes.adoc
+++ b/docs/modules/ROOT/pages/running/camel-runtimes.adoc
@@ -1,4 +1,4 @@
-= Camel Runtimes
+= Camel Runtimes (aka "sourceless" Integrations)
 
 Camel K can run any runtime available in Apache Camel. However, this is 
possible only when the Camel application was previously built and packaged into 
a container image. Also, if you run through this option, some of the features 
offered by the operator may not be available. For example, you won't be able to 
discover Camel capabilities because the source is not available to the operator 
but embedded in the container image.
 
@@ -15,9 +15,9 @@ You can have your own Camel application or just create a 
basic one for the purpo
 
 The step above is a very quick way to create a basic Camel application in any 
of the available runtime. Let's imagine we've done this for Camel Main or we 
have already a Camel application as a Maven project. As the build part is 
something we want to take care on our own, we create a pipeline to build, 
containerize and push the container to a registry (see as a reference 
https://github.com/tektoncd/catalog/blob/main/task/kamel-run/0.1/samples/run-external-build.yaml[Camel
 K Tekton example]).
 
-At this stage we do have a container image with our Camel application. We can 
use the `kamel` CLI to run our Camel application via `kamel run --image 
docker.io/my-org/my-app:1.0.0` tuning, if it's the case, with any of the trait 
or configuration required.
+At this stage we do have a container image with our Camel application. We can 
use the `kamel` CLI to run our Camel application via `kamel run --image 
docker.io/my-org/my-app:1.0.0` tuning, if it's the case, with any of the trait 
or configuration required. Mind that, when you run an Integration with this 
option, the operator will create a **synthetic** IntegrationKit.
 
-NOTE: Jvm trait won't be available when running an application built 
externally.
+NOTE: certain traits (ie, JVM) won't be available when running an application 
built externally.
 
 If all is good, in a few seconds (there is no build involved) you should have 
your application up and running and you can monitor and operate with Camel K as 
usual.
 
diff --git a/docs/modules/ROOT/pages/running/promoting.adoc 
b/docs/modules/ROOT/pages/running/promoting.adoc
index a835f6933..f7f5f4c35 100644
--- a/docs/modules/ROOT/pages/running/promoting.adoc
+++ b/docs/modules/ROOT/pages/running/promoting.adoc
@@ -3,11 +3,19 @@
 
 As soon as you have an Integration running in your cluster, you will be 
challenged to move that Integration to an higher environment. Ie, you can test 
your Integration in a **development** environment, and, as soon as you're happy 
with the result, you will need to move it into a **production** environment.
 
-Camel K has an opinionated way to achieve that goal through the usage of 
`kamel promote` command. With this command you will be able to easily move an 
Integration from one namespace to another without worrying about any low level 
detail such as resources needed by the Integration. You only need to make sure 
that both the source operator and the destination operator are using the same 
container registry and that the destination namespace provides the required 
Configmaps, Secrets or Kamele [...]
+== External IntegrationKits
 
-NOTE: in order to use the same container registry, you can use the 
`--registry` option during installation phase or change the IntegrationPlatform 
to reflect that accordingly.
+When you create an Integration, the operator takes care to use an existing 
IntegrationKit or creating one from scratch. When you're moving your 
Integration across environments you'll therefore need to create an 
IntegrationKit accordingly. The creation of the IntegrationKit, in this case, 
is a simple copy of the original IntegrationKit with the `.spec.image` coming 
from the `.status.image` of the original IntegrationKit. Additionally, it has 
to be labelled as `camel.apache.org/kit.type: e [...]
+
+NOTE: these two configuration are required to avoid the new IntegrationKit to 
kick off a new build operation.
+
+The copy is something you can do with any external tooling or using the `kamel 
promote` command as provided below:
 
-== Show me the code!
+== CLI `promote` command
+
+Camel K has an opinionated way to achieve the promotion goal through the usage 
of `kamel promote` command. With this command you will be able to easily move 
an Integration from one namespace to another without worrying about any low 
level detail such as resources needed by the Integration. You only need to make 
sure that both the source operator and the destination operator are using the 
same container registry and that the destination namespace provides the 
required Configmaps, Secrets  [...]
+
+NOTE: in order to use the same container registry, you can use the 
`--registry` option during installation phase or change the IntegrationPlatform 
to reflect that accordingly.
 
 Let's see a simple Integration that uses a Configmap to expose some message on 
an HTTP endpoint. We can start creating such an Integration and testing in a 
namespace called `development`:
 
diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc 
b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index f8586842d..b4d43c868 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -6521,14 +6521,9 @@ string
 |
 
 
-The main container image
-
-|`imageWasKit` +
-bool
-|
-
-
-A flag to mark the image used is coming from an IntegrationKit created 
externally.
+The main container image to use for the Integration. When using this parameter 
the operator will create a synthetic IntegrationKit which
+won't be able to execute traits requiring CamelCatalog. If the container image 
you're using is coming from an IntegrationKit, use instead
+Integration `.spec.integrationKit` parameter. If you're moving the Integration 
across environments, you will also need to create an "external" IntegrationKit.
 
 |`imagePullPolicy` +
 
*https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#pullpolicy-v1-core[Kubernetes
 core/v1.PullPolicy]*
diff --git a/docs/modules/traits/pages/container.adoc 
b/docs/modules/traits/pages/container.adoc
index 3be9861b6..ac11432d1 100755
--- a/docs/modules/traits/pages/container.adoc
+++ b/docs/modules/traits/pages/container.adoc
@@ -75,11 +75,9 @@ The following configuration options are available:
 
 | container.image
 | string
-| The main container image
-
-| container.image-was-kit
-| bool
-| A flag to mark the image used is coming from an IntegrationKit created 
externally.
+| The main container image to use for the Integration. When using this 
parameter the operator will create a synthetic IntegrationKit which
+won't be able to execute traits requiring CamelCatalog. If the container image 
you're using is coming from an IntegrationKit, use instead
+Integration `.spec.integrationKit` parameter. If you're moving the Integration 
across environments, you will also need to create an "external" IntegrationKit.
 
 | container.image-pull-policy
 | PullPolicy
diff --git a/e2e/advanced/operator_id_filtering_test.go 
b/e2e/advanced/operator_id_filtering_test.go
index c67e3677f..b8cafed3d 100644
--- a/e2e/advanced/operator_id_filtering_test.go
+++ b/e2e/advanced/operator_id_filtering_test.go
@@ -30,6 +30,7 @@ import (
 
        . "github.com/onsi/gomega"
        corev1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
        . "github.com/apache/camel-k/v2/e2e/support"
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -95,15 +96,31 @@ func TestOperatorIDFiltering(t *testing.T) {
                                })
 
                                t.Run("Operators can run scoped integrations 
with fixed image", func(t *testing.T) {
-                                       image := IntegrationPodImage(t, ctx, 
ns, "moving")()
-                                       g.Expect(image).NotTo(BeEmpty())
-                                       // Save resources by deleting "moving" 
integration
-                                       g.Expect(Kamel(t, ctx, "delete", 
"moving", "-n", ns).Execute()).To(Succeed())
-
-                                       g.Expect(KamelRunWithID(t, ctx, 
"operator-x", ns, "files/yaml.yaml", "--name", "pre-built", "--force", "-t", 
fmt.Sprintf("container.image=%s", image), "-t", 
"container.image-was-kit=true").Execute()).To(Succeed())
-                                       g.Consistently(IntegrationPhase(t, ctx, 
ns, "pre-built"), 10*time.Second).Should(BeEmpty())
-                                       g.Expect(AssignIntegrationToOperator(t, 
ctx, ns, "pre-built", operator2)).To(Succeed())
+                                       kitName := IntegrationKit(t, ctx, ns, 
"moving")()
+                                       g.Expect(kitName).NotTo(BeEmpty())
+                                       kitImage := KitImage(t, ctx, nsop2, 
kitName)()
+                                       g.Expect(kitImage).NotTo(BeEmpty())
+                                       // external kit creation
+                                       externalKit := v1.IntegrationKit{
+                                               ObjectMeta: metav1.ObjectMeta{
+                                                       Namespace: ns,
+                                                       Name:      "external",
+                                                       Labels: 
map[string]string{
+                                                               
"camel.apache.org/kit.type": v1.IntegrationKitTypeExternal,
+                                                       },
+                                                       Annotations: 
map[string]string{
+                                                               
"camel.apache.org/operator.id": operator2,
+                                                       },
+                                               },
+                                               Spec: v1.IntegrationKitSpec{
+                                                       Image: kitImage,
+                                               },
+                                       }
+                                       g.Expect(TestClient(t).Create(ctx, 
&externalKit)).Should(BeNil())
+                                       g.Expect(KamelRunWithID(t, ctx, 
operator2, ns, "files/yaml.yaml", "--name", "pre-built", "--kit", "external", 
"--force").Execute()).To(Succeed())
+                                       g.Consistently(IntegrationPhase(t, ctx, 
ns, "pre-built"), 
10*time.Second).ShouldNot(Equal(v1.IntegrationPhaseBuildingKit))
                                        g.Eventually(IntegrationPhase(t, ctx, 
ns, "pre-built"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
+                                       g.Eventually(IntegrationStatusImage(t, 
ctx, ns, "pre-built"), TestTimeoutShort).Should(Equal(kitImage))
                                        g.Eventually(IntegrationPodPhase(t, 
ctx, ns, "pre-built"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
                                        g.Eventually(IntegrationLogs(t, ctx, 
ns, "pre-built"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
                                        g.Expect(Kamel(t, ctx, "delete", 
"pre-built", "-n", ns).Execute()).To(Succeed())
@@ -112,7 +129,6 @@ func TestOperatorIDFiltering(t *testing.T) {
                                t.Run("Operators can run scoped Pipes", func(t 
*testing.T) {
                                        g.Expect(KamelBindWithID(t, ctx, 
"operator-x", ns, "timer-source?message=Hello", "log-sink", "--name", "klb", 
"--force").Execute()).To(Succeed())
                                        g.Consistently(Integration(t, ctx, ns, 
"klb"), 10*time.Second).Should(BeNil())
-
                                        g.Expect(AssignPipeToOperator(t, ctx, 
ns, "klb", operator1)).To(Succeed())
                                        g.Eventually(Integration(t, ctx, ns, 
"klb"), TestTimeoutShort).ShouldNot(BeNil())
                                        g.Eventually(IntegrationPhase(t, ctx, 
ns, "klb"), TestTimeoutMedium).Should(Equal(v1.IntegrationPhaseRunning))
diff --git a/e2e/install/cli/global_test.go b/e2e/install/cli/global_test.go
index 303ca07b9..cff223304 100644
--- a/e2e/install/cli/global_test.go
+++ b/e2e/install/cli/global_test.go
@@ -27,8 +27,7 @@ import (
        "fmt"
        "strings"
        "testing"
-
-       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+       "time"
 
        . "github.com/onsi/gomega"
        corev1 "k8s.io/api/core/v1"
@@ -120,6 +119,9 @@ func TestRunGlobalInstall(t *testing.T) {
                                g.Eventually(IntegrationLogs(t, ctx, ns5, 
"java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
                                
g.Expect(IntegrationConditionMessage(IntegrationCondition(t, ctx, ns5, "java", 
v1.IntegrationConditionPlatformAvailable)())).To(MatchRegexp(operatorNamespace 
+ "\\/.*"))
                                kit := IntegrationKit(t, ctx, ns5, "java")()
+                               g.Expect(kit).NotTo(BeEmpty())
+                               kitImage := KitImage(t, ctx, operatorNamespace, 
kit)()
+                               g.Expect(kitImage).NotTo(BeEmpty())
                                g.Expect(Kamel(t, ctx, "delete", "--all", "-n", 
ns5).Execute()).To(Succeed())
                                g.Expect(Kits(t, ctx, 
ns5)()).Should(WithTransform(integrationKitsToNamesTransform(), 
Not(ContainElement(kit))))
                                globalKits := Kits(t, ctx, operatorNamespace)()
@@ -135,12 +137,13 @@ func TestRunGlobalInstall(t *testing.T) {
                                                },
                                        },
                                        Spec: v1.IntegrationKitSpec{
-                                               Image: getKitImage(t, ctx, 
operatorNamespace, kit),
+                                               Image: kitImage,
                                        },
                                }
                                g.Expect(TestClient(t).Create(ctx, 
&externalKit)).Should(BeNil())
 
                                g.Expect(KamelRun(t, ctx, ns5, 
"files/Java.java", "--name", "ext", "--kit", 
"external").Execute()).To(Succeed())
+                               g.Consistently(IntegrationPhase(t, ctx, ns5, 
"ext"), 10*time.Second).ShouldNot(Equal(v1.IntegrationPhaseBuildingKit))
                                g.Eventually(IntegrationPodPhase(t, ctx, ns5, 
"ext"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
                                g.Eventually(IntegrationLogs(t, ctx, ns5, 
"ext"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
                                g.Expect(IntegrationKit(t, ctx, ns5, 
"ext")()).Should(Equal("external"))
@@ -165,24 +168,3 @@ func integrationKitsToNamesTransform() 
func([]v1.IntegrationKit) []string {
                return names
        }
 }
-
-func getKitImage(t *testing.T, ctx context.Context, ns string, name string) 
string {
-       get := v1.IntegrationKit{
-               TypeMeta: metav1.TypeMeta{
-                       Kind:       "IntegrationKit",
-                       APIVersion: v1.SchemeGroupVersion.String(),
-               },
-               ObjectMeta: metav1.ObjectMeta{
-                       Namespace: ns,
-                       Name:      name,
-               },
-       }
-       key := ctrl.ObjectKey{
-               Namespace: ns,
-               Name:      name,
-       }
-       if err := TestClient(t).Get(ctx, key, &get); err != nil {
-               return ""
-       }
-       return get.Status.Image
-}
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index d74dcbf94..e98b0895f 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -1154,6 +1154,16 @@ func KitPhase(t *testing.T, ctx context.Context, ns, 
name string) func() v1.Inte
        }
 }
 
+func KitImage(t *testing.T, ctx context.Context, ns, name string) func() 
string {
+       return func() string {
+               kit := Kit(t, ctx, ns, name)()
+               if kit == nil {
+                       return ""
+               }
+               return kit.Status.Image
+       }
+}
+
 func KitCondition(t *testing.T, ctx context.Context, ns string, name string, 
conditionType v1.IntegrationKitConditionType) func() 
*v1.IntegrationKitCondition {
        return func() *v1.IntegrationKitCondition {
                kt := Kit(t, ctx, ns, name)()
diff --git a/helm/camel-k/crds/crd-integration-platform.yaml 
b/helm/camel-k/crds/crd-integration-platform.yaml
index 12f95132a..72cc6d29c 100644
--- a/helm/camel-k/crds/crd-integration-platform.yaml
+++ b/helm/camel-k/crds/crd-integration-platform.yaml
@@ -692,7 +692,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -701,10 +707,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
@@ -2598,7 +2600,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -2607,10 +2615,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
diff --git a/helm/camel-k/crds/crd-integration-profile.yaml 
b/helm/camel-k/crds/crd-integration-profile.yaml
index c587cc5a6..c2ffd1c53 100644
--- a/helm/camel-k/crds/crd-integration-profile.yaml
+++ b/helm/camel-k/crds/crd-integration-profile.yaml
@@ -569,7 +569,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -578,10 +584,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
@@ -2358,7 +2360,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -2367,10 +2375,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
diff --git a/helm/camel-k/crds/crd-integration.yaml 
b/helm/camel-k/crds/crd-integration.yaml
index 0a4b17f32..3c7a2d36c 100644
--- a/helm/camel-k/crds/crd-integration.yaml
+++ b/helm/camel-k/crds/crd-integration.yaml
@@ -6588,7 +6588,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -6597,10 +6603,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
diff --git a/helm/camel-k/crds/crd-kamelet-binding.yaml 
b/helm/camel-k/crds/crd-kamelet-binding.yaml
index eb3476d63..3234861f5 100644
--- a/helm/camel-k/crds/crd-kamelet-binding.yaml
+++ b/helm/camel-k/crds/crd-kamelet-binding.yaml
@@ -6873,7 +6873,14 @@ spec:
                               kubernetes Service.
                             type: boolean
                           image:
-                            description: The main container image
+                            description: The main container image to use for 
the Integration.
+                              When using this parameter the operator will 
create a
+                              synthetic IntegrationKit which won't be able to 
execute
+                              traits requiring CamelCatalog. If the container 
image
+                              you're using is coming from an IntegrationKit, 
use instead
+                              Integration `.spec.integrationKit` parameter. If 
you're
+                              moving the Integration across environments, you 
will
+                              also need to create an "external" IntegrationKit.
                             type: string
                           imagePullPolicy:
                             description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -6882,10 +6889,6 @@ spec:
                             - Never
                             - IfNotPresent
                             type: string
-                          imageWasKit:
-                            description: A flag to mark the image used is 
coming from
-                              an IntegrationKit created externally.
-                            type: boolean
                           limitCPU:
                             description: The maximum amount of CPU required.
                             type: string
diff --git a/helm/camel-k/crds/crd-pipe.yaml b/helm/camel-k/crds/crd-pipe.yaml
index 8b7e891f6..aaa7cbbed 100644
--- a/helm/camel-k/crds/crd-pipe.yaml
+++ b/helm/camel-k/crds/crd-pipe.yaml
@@ -6871,7 +6871,14 @@ spec:
                               kubernetes Service.
                             type: boolean
                           image:
-                            description: The main container image
+                            description: The main container image to use for 
the Integration.
+                              When using this parameter the operator will 
create a
+                              synthetic IntegrationKit which won't be able to 
execute
+                              traits requiring CamelCatalog. If the container 
image
+                              you're using is coming from an IntegrationKit, 
use instead
+                              Integration `.spec.integrationKit` parameter. If 
you're
+                              moving the Integration across environments, you 
will
+                              also need to create an "external" IntegrationKit.
                             type: string
                           imagePullPolicy:
                             description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -6880,10 +6887,6 @@ spec:
                             - Never
                             - IfNotPresent
                             type: string
-                          imageWasKit:
-                            description: A flag to mark the image used is 
coming from
-                              an IntegrationKit created externally.
-                            type: boolean
                           limitCPU:
                             description: The maximum amount of CPU required.
                             type: string
diff --git a/pkg/apis/camel/v1/trait/container.go 
b/pkg/apis/camel/v1/trait/container.go
index 4d426993a..9706cfc6b 100644
--- a/pkg/apis/camel/v1/trait/container.go
+++ b/pkg/apis/camel/v1/trait/container.go
@@ -49,10 +49,10 @@ type ContainerTrait struct {
        ServicePortName string `property:"service-port-name" 
json:"servicePortName,omitempty"`
        // The main container name. It's named `integration` by default.
        Name string `property:"name" json:"name,omitempty"`
-       // The main container image
+       // The main container image to use for the Integration. When using this 
parameter the operator will create a synthetic IntegrationKit which
+       // won't be able to execute traits requiring CamelCatalog. If the 
container image you're using is coming from an IntegrationKit, use instead
+       // Integration `.spec.integrationKit` parameter. If you're moving the 
Integration across environments, you will also need to create an "external" 
IntegrationKit.
        Image string `property:"image" json:"image,omitempty"`
-       // A flag to mark the image used is coming from an IntegrationKit 
created externally.
-       ImageWasKit *bool `property:"image-was-kit" 
json:"imageWasKit,omitempty"`
        // The pull policy: Always|Never|IfNotPresent
        // +kubebuilder:validation:Enum=Always;Never;IfNotPresent
        ImagePullPolicy corev1.PullPolicy `property:"image-pull-policy" 
json:"imagePullPolicy,omitempty"`
diff --git a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go 
b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
index 5fc1d1964..3aa125359 100644
--- a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
@@ -186,11 +186,6 @@ func (in *ContainerTrait) DeepCopyInto(out 
*ContainerTrait) {
                *out = new(bool)
                **out = **in
        }
-       if in.ImageWasKit != nil {
-               in, out := &in.ImageWasKit, &out.ImageWasKit
-               *out = new(bool)
-               **out = **in
-       }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ContainerTrait.
diff --git a/pkg/cmd/promote.go b/pkg/cmd/promote.go
index a807191f4..6879f0ade 100644
--- a/pkg/cmd/promote.go
+++ b/pkg/cmd/promote.go
@@ -26,7 +26,6 @@ import (
        "strings"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-       traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
        "github.com/apache/camel-k/v2/pkg/client"
        "github.com/apache/camel-k/v2/pkg/trait"
        "github.com/apache/camel-k/v2/pkg/util/camel"
@@ -38,7 +37,6 @@ import (
        rbacv1 "k8s.io/api/rbac/v1"
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/utils/pointer"
        k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
@@ -130,7 +128,10 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
        if sourceIntegration.Status.Phase != v1.IntegrationPhaseRunning {
                return fmt.Errorf("could not promote an Integration in %s 
status", sourceIntegration.Status.Phase)
        }
-
+       sourceKit, err := o.getIntegrationKit(c, 
sourceIntegration.Status.IntegrationKit.Name)
+       if err != nil {
+               return err
+       }
        // Image only mode
        if o.Image {
                showImageOnly(cmd, sourceIntegration)
@@ -147,8 +148,12 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
 
        // Pipe promotion
        if promotePipe {
-               destPipe := o.editPipe(sourcePipe, sourceIntegration)
+               destPipe, destKit := o.editPipe(sourcePipe, sourceIntegration, 
sourceKit)
                if o.OutputFormat != "" {
+                       if err := showIntegrationKitOutput(cmd, destKit, 
o.OutputFormat); err != nil {
+                               return err
+                       }
+                       fmt.Fprintln(cmd.OutOrStdout(), `---`)
                        return showPipeOutput(cmd, destPipe, o.OutputFormat, 
c.GetScheme())
                }
                // Ensure the destination namespace has access to the source 
namespace images
@@ -156,18 +161,29 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
                if err != nil {
                        return err
                }
+               _, err = o.replaceResource(destKit)
+               if err != nil {
+                       return err
+               }
                replaced, err := o.replaceResource(destPipe)
+               if err != nil {
+                       return err
+               }
                if !replaced {
                        fmt.Fprintln(cmd.OutOrStdout(), `Promoted Pipe 
"`+name+`" created`)
                } else {
                        fmt.Fprintln(cmd.OutOrStdout(), `Promoted Pipe 
"`+name+`" updated`)
                }
-               return err
+               return nil
        }
 
        // Plain Integration promotion
-       destIntegration := o.editIntegration(sourceIntegration)
+       destIntegration, destKit := o.editIntegration(sourceIntegration, 
sourceKit)
        if o.OutputFormat != "" {
+               if err := showIntegrationKitOutput(cmd, destKit, 
o.OutputFormat); err != nil {
+                       return err
+               }
+               fmt.Fprintln(cmd.OutOrStdout(), `---`)
                return showIntegrationOutput(cmd, destIntegration, 
o.OutputFormat)
        }
        // Ensure the destination namespace has access to the source namespace 
images
@@ -175,13 +191,20 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
        if err != nil {
                return err
        }
+       _, err = o.replaceResource(destKit)
+       if err != nil {
+               return err
+       }
        replaced, err := o.replaceResource(destIntegration)
+       if err != nil {
+               return err
+       }
        if !replaced {
                fmt.Fprintln(cmd.OutOrStdout(), `Promoted Integration 
"`+name+`" created`)
        } else {
                fmt.Fprintln(cmd.OutOrStdout(), `Promoted Integration 
"`+name+`" updated`)
        }
-       return err
+       return nil
 }
 
 func checkOpsCompatibility(cmd *cobra.Command, source, dest map[string]string) 
error {
@@ -224,6 +247,19 @@ func (o *promoteCmdOptions) getIntegration(c 
client.Client, name string) (*v1.In
        return &it, nil
 }
 
+func (o *promoteCmdOptions) getIntegrationKit(c client.Client, name string) 
(*v1.IntegrationKit, error) {
+       ik := v1.NewIntegrationKit(o.Namespace, name)
+       key := k8sclient.ObjectKey{
+               Name:      name,
+               Namespace: o.Namespace,
+       }
+       if err := c.Get(o.Context, key, ik); err != nil {
+               return nil, err
+       }
+
+       return ik, nil
+}
+
 func (o *promoteCmdOptions) validateDestResources(c client.Client, it 
*v1.Integration) error {
        var configmaps []string
        var secrets []string
@@ -459,19 +495,27 @@ func existsKamelet(ctx context.Context, c client.Client, 
name string, namespace
        return true
 }
 
-func (o *promoteCmdOptions) editIntegration(it *v1.Integration) 
*v1.Integration {
-       dst := v1.NewIntegration(o.To, it.Name)
+func (o *promoteCmdOptions) editIntegration(it *v1.Integration, kit 
*v1.IntegrationKit) (*v1.Integration, *v1.IntegrationKit) {
        contImage := it.Status.Image
-       dst.Spec = *it.Spec.DeepCopy()
-       dst.Annotations = cloneAnnotations(it.Annotations, o.ToOperator)
-       dst.Labels = cloneLabels(it.Labels)
-       if dst.Spec.Traits.Container == nil {
-               dst.Spec.Traits.Container = &traitv1.ContainerTrait{}
-       }
-       dst.Spec.Traits.Container.Image = contImage
-       dst.Spec.Traits.Container.ImageWasKit = pointer.Bool(true)
-
-       return &dst
+       // IntegrationKit
+       dstKit := v1.NewIntegrationKit(o.To, kit.Name)
+       dstKit.Spec = *kit.Spec.DeepCopy()
+       dstKit.Annotations = cloneAnnotations(kit.Annotations, o.ToOperator)
+       dstKit.Labels = cloneLabels(kit.Labels)
+       dstKit.Labels["camel.apache.org/kit.type"] = 
v1.IntegrationKitTypeExternal
+       dstKit.Spec.Image = contImage
+       // Integration
+       dstIt := v1.NewIntegration(o.To, it.Name)
+       dstIt.Spec = *it.Spec.DeepCopy()
+       dstIt.Annotations = cloneAnnotations(it.Annotations, o.ToOperator)
+       dstIt.Labels = cloneLabels(it.Labels)
+       dstIt.Spec.IntegrationKit = &corev1.ObjectReference{
+               Namespace: dstKit.Namespace,
+               Name:      dstKit.Name,
+               Kind:      dstKit.Kind,
+       }
+
+       return &dstIt, dstKit
 }
 
 // Return all annotations overriding the operator Id if provided.
@@ -503,20 +547,28 @@ func cloneLabels(lbs map[string]string) map[string]string 
{
        return newMap
 }
 
-func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it *v1.Integration) *v1.Pipe 
{
+func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it *v1.Integration, kit 
*v1.IntegrationKit) (*v1.Pipe, *v1.IntegrationKit) {
+       contImage := it.Status.Image
+       // IntegrationKit
+       dstKit := v1.NewIntegrationKit(o.To, kit.Name)
+       dstKit.Spec = *kit.Spec.DeepCopy()
+       dstKit.Annotations = cloneAnnotations(kit.Annotations, o.ToOperator)
+       dstKit.Labels = cloneLabels(kit.Labels)
+       dstKit.Labels["camel.apache.org/kit.type"] = 
v1.IntegrationKitTypeExternal
+       dstKit.Spec.Image = contImage
+       // Pipe
        dst := v1.NewPipe(o.To, kb.Name)
        dst.Spec = *kb.Spec.DeepCopy()
        dst.Annotations = cloneAnnotations(kb.Annotations, o.ToOperator)
        dst.Labels = cloneLabels(kb.Labels)
-       contImage := it.Status.Image
        if dst.Spec.Integration == nil {
                dst.Spec.Integration = &v1.IntegrationSpec{}
        }
-       if dst.Spec.Integration.Traits.Container == nil {
-               dst.Spec.Integration.Traits.Container = 
&traitv1.ContainerTrait{}
+       dst.Spec.Integration.IntegrationKit = &corev1.ObjectReference{
+               Namespace: dstKit.Namespace,
+               Name:      dstKit.Name,
+               Kind:      dstKit.Kind,
        }
-       dst.Spec.Integration.Traits.Container.Image = contImage
-       dst.Spec.Integration.Traits.Container.ImageWasKit = pointer.Bool(true)
 
        if dst.Spec.Source.Ref != nil {
                dst.Spec.Source.Ref.Namespace = o.To
@@ -531,7 +583,7 @@ func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it 
*v1.Integration) *v1.Pipe {
                        }
                }
        }
-       return &dst
+       return &dst, dstKit
 }
 
 func (o *promoteCmdOptions) replaceResource(res k8sclient.Object) (bool, 
error) {
diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go
index 78779fb4e..24036478d 100644
--- a/pkg/cmd/promote_test.go
+++ b/pkg/cmd/promote_test.go
@@ -28,6 +28,7 @@ import (
        "github.com/spf13/cobra"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
+       corev1 "k8s.io/api/core/v1"
        "k8s.io/apimachinery/pkg/runtime"
 )
 
@@ -62,11 +63,11 @@ func TestIntegrationNotCompatible(t *testing.T) {
        dstPlatform.Status.Version = "0.0.1"
        dstPlatform.Status.Build.RuntimeVersion = "0.0.1"
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
-       defaultIntegration := nominalIntegration("my-it-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-it-test")
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
-       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultIntegration, &defaultKit, &srcCatalog, &dstCatalog)
        _, err := test.ExecuteCommand(promoteCmd, cmdPromote, "my-it-test", 
"--to", "prod-namespace", "-n", "default")
        require.Error(t, err)
        assert.Equal(t,
@@ -84,34 +85,54 @@ func TestIntegrationDryRun(t *testing.T) {
        dstPlatform.Status.Version = defaults.Version
        dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
-       defaultIntegration := nominalIntegration("my-it-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-it-test")
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
-       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &defaultKit, &srcCatalog, 
&dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-it-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
        assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
        require.NoError(t, err)
        assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: IntegrationKit
+metadata:
+  creationTimestamp: null
+  labels:
+    camel.apache.org/kit.type: external
+  name: my-it-test-kit
+  namespace: prod-namespace
+spec:
+  image: my-special-image
+  traits: {}
+status: {}
+---
+apiVersion: camel.apache.org/v1
 kind: Integration
 metadata:
   creationTimestamp: null
   name: my-it-test
   namespace: prod-namespace
 spec:
-  traits:
-    container:
-      image: my-special-image
-      imageWasKit: true
+  integrationKit:
+    kind: IntegrationKit
+    name: my-it-test-kit
+    namespace: prod-namespace
+  traits: {}
 status: {}
 `, output)
 }
 
-func nominalIntegration(name string) v1.Integration {
+func nominalIntegration(name string) (v1.Integration, v1.IntegrationKit) {
        it := v1.NewIntegration("default", name)
        it.Status.Phase = v1.IntegrationPhaseRunning
        it.Status.Image = "my-special-image"
-       return it
+       ik := v1.NewIntegrationKit("default", name+"-kit")
+       it.Status.IntegrationKit = &corev1.ObjectReference{
+               Namespace: ik.Namespace,
+               Name:      ik.Name,
+               Kind:      ik.Kind,
+       }
+       return it, *ik
 }
 
 func TestPipeDryRun(t *testing.T) {
@@ -124,15 +145,28 @@ func TestPipeDryRun(t *testing.T) {
        dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
        defaultKB := nominalPipe("my-kb-test")
-       defaultIntegration := nominalIntegration("my-kb-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-kb-test")
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
-       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultKB, &defaultIntegration, &srcCatalog, 
&dstCatalog)
+       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultKB, &defaultIntegration, &defaultKit, 
&srcCatalog, &dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-kb-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
        assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
        require.NoError(t, err)
        assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: IntegrationKit
+metadata:
+  creationTimestamp: null
+  labels:
+    camel.apache.org/kit.type: external
+  name: my-kb-test-kit
+  namespace: prod-namespace
+spec:
+  image: my-special-image
+  traits: {}
+status: {}
+---
+apiVersion: camel.apache.org/v1
 kind: Pipe
 metadata:
   creationTimestamp: null
@@ -140,10 +174,11 @@ metadata:
   namespace: prod-namespace
 spec:
   integration:
-    traits:
-      container:
-        image: my-special-image
-        imageWasKit: true
+    integrationKit:
+      kind: IntegrationKit
+      name: my-kb-test-kit
+      namespace: prod-namespace
+    traits: {}
   sink: {}
   source: {}
 status: {}
@@ -171,7 +206,7 @@ func TestIntegrationWithMetadataDryRun(t *testing.T) {
        dstPlatform.Status.Version = defaults.Version
        dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
-       defaultIntegration := nominalIntegration("my-it-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-it-test")
        defaultIntegration.Annotations = map[string]string{
                "camel.apache.org/operator.id": "camel-k",
                "my-annotation":                "my-value",
@@ -182,11 +217,24 @@ func TestIntegrationWithMetadataDryRun(t *testing.T) {
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
-       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &defaultKit, &srcCatalog, 
&dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-it-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
        assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
        require.NoError(t, err)
        assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: IntegrationKit
+metadata:
+  creationTimestamp: null
+  labels:
+    camel.apache.org/kit.type: external
+  name: my-it-test-kit
+  namespace: prod-namespace
+spec:
+  image: my-special-image
+  traits: {}
+status: {}
+---
+apiVersion: camel.apache.org/v1
 kind: Integration
 metadata:
   annotations:
@@ -197,10 +245,11 @@ metadata:
   name: my-it-test
   namespace: prod-namespace
 spec:
-  traits:
-    container:
-      image: my-special-image
-      imageWasKit: true
+  integrationKit:
+    kind: IntegrationKit
+    name: my-it-test-kit
+    namespace: prod-namespace
+  traits: {}
 status: {}
 `, output)
 }
@@ -222,15 +271,28 @@ func TestPipeWithMetadataDryRun(t *testing.T) {
        defaultKB.Labels = map[string]string{
                "my-label": "my-value",
        }
-       defaultIntegration := nominalIntegration("my-kb-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-kb-test")
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
-       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultKB, &defaultIntegration, &srcCatalog, 
&dstCatalog)
+       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultKB, &defaultIntegration, &defaultKit, 
&srcCatalog, &dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-kb-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
        assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
        require.NoError(t, err)
        assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: IntegrationKit
+metadata:
+  creationTimestamp: null
+  labels:
+    camel.apache.org/kit.type: external
+  name: my-kb-test-kit
+  namespace: prod-namespace
+spec:
+  image: my-special-image
+  traits: {}
+status: {}
+---
+apiVersion: camel.apache.org/v1
 kind: Pipe
 metadata:
   annotations:
@@ -242,10 +304,11 @@ metadata:
   namespace: prod-namespace
 spec:
   integration:
-    traits:
-      container:
-        image: my-special-image
-        imageWasKit: true
+    integrationKit:
+      kind: IntegrationKit
+      name: my-kb-test-kit
+      namespace: prod-namespace
+    traits: {}
   sink: {}
   source: {}
 status: {}
@@ -261,11 +324,11 @@ func TestItImageOnly(t *testing.T) {
        dstPlatform.Status.Version = defaults.Version
        dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
-       defaultIntegration := nominalIntegration("my-it-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-it-test")
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
-       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultIntegration, &defaultKit, &srcCatalog, &dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-it-test", "--to", "prod-namespace", "-i", "-n", "default")
        require.NoError(t, err)
        assert.Equal(t, "my-special-image\n", output)
@@ -281,11 +344,11 @@ func TestPipeImageOnly(t *testing.T) {
        dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
        defaultKB := nominalPipe("my-kb-test")
-       defaultIntegration := nominalIntegration("my-kb-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-kb-test")
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
-       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultKB, &defaultIntegration, &srcCatalog, &dstCatalog)
+       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultKB, &defaultIntegration, &defaultKit, &srcCatalog, 
&dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-kb-test", "--to", "prod-namespace", "-i", "-n", "default")
        require.NoError(t, err)
        assert.Equal(t, "my-special-image\n", output)
@@ -300,16 +363,31 @@ func TestIntegrationToOperatorId(t *testing.T) {
        dstPlatform.Status.Version = defaults.Version
        dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
-       defaultIntegration := nominalIntegration("my-it-test")
+       defaultIntegration, defaultKit := nominalIntegration("my-it-test")
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
        // Verify default (missing) operator Id
-       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &defaultKit, &srcCatalog, 
&dstCatalog)
        output, err := test.ExecuteCommand(promoteCmd, cmdPromote, 
"my-it-test", "-x", "my-prod-operator", "-o", "yaml", "--to", "prod")
        assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
        require.NoError(t, err)
        assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: IntegrationKit
+metadata:
+  annotations:
+    camel.apache.org/operator.id: my-prod-operator
+  creationTimestamp: null
+  labels:
+    camel.apache.org/kit.type: external
+  name: my-it-test-kit
+  namespace: prod
+spec:
+  image: my-special-image
+  traits: {}
+status: {}
+---
+apiVersion: camel.apache.org/v1
 kind: Integration
 metadata:
   annotations:
@@ -318,21 +396,37 @@ metadata:
   name: my-it-test
   namespace: prod
 spec:
-  traits:
-    container:
-      image: my-special-image
-      imageWasKit: true
+  integrationKit:
+    kind: IntegrationKit
+    name: my-it-test-kit
+    namespace: prod
+  traits: {}
 status: {}
 `, output)
        // Verify also when the operator Id is set in the integration
        defaultIntegration.Annotations = map[string]string{
                "camel.apache.org/operator.id": "camel-k",
        }
-       promoteCmdOptions, promoteCmd, _ = initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
+       promoteCmdOptions, promoteCmd, _ = initializePromoteCmdOptions(t, 
&srcPlatform, &dstPlatform, &defaultIntegration, &defaultKit, &srcCatalog, 
&dstCatalog)
        output, err = test.ExecuteCommand(promoteCmd, cmdPromote, "my-it-test", 
"-x", "my-prod-operator", "-o", "yaml", "--to", "prod")
        assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
        require.NoError(t, err)
        assert.Equal(t, `apiVersion: camel.apache.org/v1
+kind: IntegrationKit
+metadata:
+  annotations:
+    camel.apache.org/operator.id: my-prod-operator
+  creationTimestamp: null
+  labels:
+    camel.apache.org/kit.type: external
+  name: my-it-test-kit
+  namespace: prod
+spec:
+  image: my-special-image
+  traits: {}
+status: {}
+---
+apiVersion: camel.apache.org/v1
 kind: Integration
 metadata:
   annotations:
@@ -341,10 +435,11 @@ metadata:
   name: my-it-test
   namespace: prod
 spec:
-  traits:
-    container:
-      image: my-special-image
-      imageWasKit: true
+  integrationKit:
+    kind: IntegrationKit
+    name: my-it-test-kit
+    namespace: prod
+  traits: {}
 status: {}
 `, output)
 }
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 46f6cade3..8c89fa4be 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -609,6 +609,14 @@ func showIntegrationOutput(cmd *cobra.Command, integration 
*v1.Integration, outp
        return printer.PrintObj(integration, cmd.OutOrStdout())
 }
 
+func showIntegrationKitOutput(cmd *cobra.Command, integrationKit 
*v1.IntegrationKit, outputFormat string) error {
+       printer := printers.NewTypeSetter(scheme.Scheme)
+       printer.Delegate = &kubernetes.CLIPrinter{
+               Format: outputFormat,
+       }
+       return printer.PrintObj(integrationKit, cmd.OutOrStdout())
+}
+
 func (o *runCmdOptions) getIntegration(cmd *cobra.Command, c client.Client, 
namespace, name string) (*v1.Integration, *v1.Integration, error) {
        it := &v1.Integration{
                TypeMeta: metav1.TypeMeta{
diff --git 
a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
index 12f95132a..72cc6d29c 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
@@ -692,7 +692,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -701,10 +707,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
@@ -2598,7 +2600,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -2607,10 +2615,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
diff --git 
a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
index c587cc5a6..c2ffd1c53 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
@@ -569,7 +569,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -578,10 +584,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
@@ -2358,7 +2360,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -2367,10 +2375,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
index 0a4b17f32..3c7a2d36c 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
@@ -6588,7 +6588,13 @@ spec:
                           Service.
                         type: boolean
                       image:
-                        description: The main container image
+                        description: The main container image to use for the 
Integration.
+                          When using this parameter the operator will create a 
synthetic
+                          IntegrationKit which won't be able to execute traits 
requiring
+                          CamelCatalog. If the container image you're using is 
coming
+                          from an IntegrationKit, use instead Integration 
`.spec.integrationKit`
+                          parameter. If you're moving the Integration across 
environments,
+                          you will also need to create an "external" 
IntegrationKit.
                         type: string
                       imagePullPolicy:
                         description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -6597,10 +6603,6 @@ spec:
                         - Never
                         - IfNotPresent
                         type: string
-                      imageWasKit:
-                        description: A flag to mark the image used is coming 
from
-                          an IntegrationKit created externally.
-                        type: boolean
                       limitCPU:
                         description: The maximum amount of CPU required.
                         type: string
diff --git 
a/pkg/resources/config/crd/bases/camel.apache.org_kameletbindings.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_kameletbindings.yaml
index eb3476d63..3234861f5 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_kameletbindings.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_kameletbindings.yaml
@@ -6873,7 +6873,14 @@ spec:
                               kubernetes Service.
                             type: boolean
                           image:
-                            description: The main container image
+                            description: The main container image to use for 
the Integration.
+                              When using this parameter the operator will 
create a
+                              synthetic IntegrationKit which won't be able to 
execute
+                              traits requiring CamelCatalog. If the container 
image
+                              you're using is coming from an IntegrationKit, 
use instead
+                              Integration `.spec.integrationKit` parameter. If 
you're
+                              moving the Integration across environments, you 
will
+                              also need to create an "external" IntegrationKit.
                             type: string
                           imagePullPolicy:
                             description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -6882,10 +6889,6 @@ spec:
                             - Never
                             - IfNotPresent
                             type: string
-                          imageWasKit:
-                            description: A flag to mark the image used is 
coming from
-                              an IntegrationKit created externally.
-                            type: boolean
                           limitCPU:
                             description: The maximum amount of CPU required.
                             type: string
diff --git a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
index 8b7e891f6..aaa7cbbed 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
@@ -6871,7 +6871,14 @@ spec:
                               kubernetes Service.
                             type: boolean
                           image:
-                            description: The main container image
+                            description: The main container image to use for 
the Integration.
+                              When using this parameter the operator will 
create a
+                              synthetic IntegrationKit which won't be able to 
execute
+                              traits requiring CamelCatalog. If the container 
image
+                              you're using is coming from an IntegrationKit, 
use instead
+                              Integration `.spec.integrationKit` parameter. If 
you're
+                              moving the Integration across environments, you 
will
+                              also need to create an "external" IntegrationKit.
                             type: string
                           imagePullPolicy:
                             description: 'The pull policy: 
Always|Never|IfNotPresent'
@@ -6880,10 +6887,6 @@ spec:
                             - Never
                             - IfNotPresent
                             type: string
-                          imageWasKit:
-                            description: A flag to mark the image used is 
coming from
-                              an IntegrationKit created externally.
-                            type: boolean
                           limitCPU:
                             description: The maximum amount of CPU required.
                             type: string
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index 19ab28ee5..2beca4dfb 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -143,9 +143,6 @@ func (t *containerTrait) configureImageIntegrationKit(e 
*Environment) error {
                        kubernetes.CamelCreatorLabelNamespace: 
e.Integration.Namespace,
                        kubernetes.CamelCreatorLabelVersion:   
e.Integration.ResourceVersion,
                }
-               if pointer.BoolDeref(t.ImageWasKit, false) {
-                       kit.Labels[v1.IntegrationKitTypeLabel] = 
v1.IntegrationKitTypeExternal
-               }
 
                if v, ok := 
e.Integration.Annotations[v1.PlatformSelectorAnnotation]; ok {
                        v1.SetAnnotation(&kit.ObjectMeta, 
v1.PlatformSelectorAnnotation, v)

Reply via email to