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

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


The following commit(s) were added to refs/heads/main by this push:
     new 6dbded5ab feat(kamelets): bundling from jar
6dbded5ab is described below

commit 6dbded5abbda4d4edc1ce8a7bdca3ad37bacacce
Author: Pasquale Congiusti <pasquale.congiu...@gmail.com>
AuthorDate: Thu Sep 12 17:34:03 2024 +0200

    feat(kamelets): bundling from jar
    
    This is required to simplify the release process and leverage to 
distributed catalog as dependency
---
 build/Dockerfile                                   |   5 +-
 pkg/apis/camel/v1/integrationplatform_types.go     |   7 +-
 pkg/apis/camel/v1/kamelet_types_support.go         |   5 +
 pkg/cmd/reset.go                                   |  24 ---
 pkg/controller/catalog/initialize.go               |   1 -
 pkg/controller/integrationplatform/catalog.go      |  84 --------
 pkg/controller/integrationplatform/catalog_test.go | 235 ---------------------
 pkg/controller/integrationplatform/create.go       | 150 +++++++++++--
 pkg/controller/integrationplatform/create_test.go  | 189 ++++++++++++++---
 pkg/controller/integrationplatform/initialize.go   |  17 +-
 .../integrationplatform/initialize_test.go         |  81 ++++---
 .../integrationplatform_controller.go              |  15 +-
 pkg/controller/integrationplatform/kamelets.go     | 209 ++++++++++++++++++
 .../integrationplatform/kamelets_test.go           | 153 ++++++++++++++
 pkg/controller/integrationplatform/monitor.go      |  80 +++----
 pkg/controller/integrationplatform/monitor_test.go | 199 +++++++++++------
 pkg/install/kamelets.go                            | 136 ------------
 pkg/install/kamelets_test.go                       |  40 ----
 pkg/install/optional.go                            |  31 ---
 pkg/install/testdata/timer-source.kamelet.yaml     |  57 -----
 pkg/platform/defaults.go                           |  12 +-
 pkg/trait/kamelets.go                              |  28 ++-
 pkg/trait/kamelets_test.go                         |   1 -
 pkg/util/camel/camel_runtime.go                    |   3 +-
 release.adoc                                       |   1 -
 script/Makefile                                    |  19 +-
 script/bundle_kamelets.sh                          |  55 -----
 27 files changed, 935 insertions(+), 902 deletions(-)

diff --git a/build/Dockerfile b/build/Dockerfile
index 78ff6a3cd..f1523076c 100644
--- a/build/Dockerfile
+++ b/build/Dockerfile
@@ -43,20 +43,17 @@ ENV MAVEN_USER_HOME="${MAVEN_HOME}"
 RUN ${MVNW_DIR}/mvnw --version | grep "Maven home:" | sed 's/Maven home: //' 
>> ${MVNW_DIR}default \
     && cp -r /usr/share/maven/lib/. $(cat ${MVNW_DIR}default)/lib \
     && rm $(cat ${MVNW_DIR}default)/lib/maven-slf4j-provider* \
-    && rm $(cat ${MVNW_DIR}default)/lib/slf4j-api-1.* 
+    && rm $(cat ${MVNW_DIR}default)/lib/slf4j-api-1.*
 
 ENV MAVEN_OPTS="${MAVEN_OPTS} 
-Dlogback.configurationFile=${MAVEN_HOME}/conf/logback.xml"
 
 ADD build/_maven_output ${MVN_REPO}
 # Fix https://github.com/moby/moby/issues/37965
 RUN true
-ADD build/_kamelets /kamelets
 
 RUN chgrp -R 0 ${MVN_REPO} \
     && chown -R 1001:0 ${MVN_REPO} \
     && chmod -R 775 ${MVN_REPO} \
-    && chgrp -R 0 /kamelets \
-    && chmod -R g=u /kamelets \
     && chgrp -R 0 ${MAVEN_HOME} \
     && chown -R 1001:0 ${MAVEN_HOME} \
     && chmod -R 775 ${MAVEN_HOME}
diff --git a/pkg/apis/camel/v1/integrationplatform_types.go 
b/pkg/apis/camel/v1/integrationplatform_types.go
index 3cc8e3a65..6c211996b 100644
--- a/pkg/apis/camel/v1/integrationplatform_types.go
+++ b/pkg/apis/camel/v1/integrationplatform_types.go
@@ -192,6 +192,7 @@ const (
        // IntegrationPlatformPhaseError when the IntegrationPlatform had some 
error (see Conditions).
        IntegrationPlatformPhaseError IntegrationPlatformPhase = "Error"
        // IntegrationPlatformPhaseCreateCatalog when the IntegrationPlatform 
creates a new CamelCatalog.
+       // Deprecated no longer in use.
        IntegrationPlatformPhaseCreateCatalog IntegrationPlatformPhase = 
"CreateCatalog"
 
        // IntegrationPlatformConditionReady is the condition if the 
IntegrationPlatform is ready.
@@ -199,12 +200,12 @@ const (
        IntegrationPlatformConditionReady = "Ready"
        // IntegrationPlatformConditionTypeCreated is the condition if the 
IntegrationPlatform has been created.
        IntegrationPlatformConditionTypeCreated 
IntegrationPlatformConditionType = "Created"
-
        // IntegrationPlatformConditionTypeRegistryAvailable is the condition 
for the availability of a container registry.
        IntegrationPlatformConditionTypeRegistryAvailable 
IntegrationPlatformConditionType = "RegistryAvailable"
-
-       // IntegrationPlatformConditionCamelCatalogAvailable is the condition 
for the availability of a container registry.
+       // IntegrationPlatformConditionCamelCatalogAvailable is the condition 
for the availability of a the CamelCatalog.
        IntegrationPlatformConditionCamelCatalogAvailable 
IntegrationPlatformConditionType = "CamelCatalogAvailable"
+       // IntegrationPlatformConditionKameletCatalogAvailable is the condition 
for the availability of a Kamelet catalog.
+       IntegrationPlatformConditionKameletCatalogAvailable 
IntegrationPlatformConditionType = "KameletCatalogAvailable"
 
        // IntegrationPlatformConditionCreatedReason represents the reason that 
the IntegrationPlatform is created.
        IntegrationPlatformConditionCreatedReason = "IntegrationPlatformCreated"
diff --git a/pkg/apis/camel/v1/kamelet_types_support.go 
b/pkg/apis/camel/v1/kamelet_types_support.go
index bb22c998e..aa19fc2b9 100644
--- a/pkg/apis/camel/v1/kamelet_types_support.go
+++ b/pkg/apis/camel/v1/kamelet_types_support.go
@@ -178,6 +178,11 @@ func (k *Kamelet) SortedTypesKeys() []TypeSlot {
        return res
 }
 
+// IsBundled returns true if the Kamelet is coming from a pre-bundled 
installation.
+func (k *Kamelet) IsBundled() bool {
+       return k.Labels != nil && k.Labels[KameletBundledLabel] == "true"
+}
+
 func ValidKameletName(name string) bool {
        return !reservedKameletNames[name]
 }
diff --git a/pkg/cmd/reset.go b/pkg/cmd/reset.go
index 02a6f414e..c32112e5d 100644
--- a/pkg/cmd/reset.go
+++ b/pkg/cmd/reset.go
@@ -18,7 +18,6 @@ limitations under the License.
 package cmd
 
 import (
-       "errors"
        "fmt"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -93,13 +92,6 @@ func (o *resetCmdOptions) reset(cmd *cobra.Command, _ 
[]string) {
                }
                fmt.Fprintln(cmd.OutOrStdout(), n, "integration kits deleted 
from namespace", o.Namespace)
        }
-
-       if err = o.resetIntegrationPlatform(c); err != nil {
-               fmt.Fprintln(cmd.ErrOrStderr(), err)
-               return
-       }
-
-       fmt.Fprintln(cmd.OutOrStdout(), "Camel K platform has been reset 
successfully!")
 }
 
 func (o *resetCmdOptions) deleteAllIntegrations(c client.Client) (int, error) {
@@ -163,22 +155,6 @@ func (o *resetCmdOptions) deleteAllKameletBindings(c 
client.Client) (int, error)
        return len(list.Items), nil
 }
 
-func (o *resetCmdOptions) resetIntegrationPlatform(c client.Client) error {
-       list := v1.NewIntegrationPlatformList()
-       if err := c.List(o.Context, &list, k8sclient.InNamespace(o.Namespace)); 
err != nil {
-               return fmt.Errorf("could not retrieve integration platform from 
namespace %s: %w", o.Namespace, err)
-       }
-       if len(list.Items) > 1 {
-               return fmt.Errorf("expected 1 integration platform in the 
namespace, found: %d", len(list.Items))
-       } else if len(list.Items) == 0 {
-               return errors.New("no integration platforms found in the 
namespace")
-       }
-       platform := list.Items[0]
-       // Let's reset the status
-       platform.Status = v1.IntegrationPlatformStatus{}
-       return c.Status().Update(o.Context, &platform)
-}
-
 func isIntegrationOwned(it v1.Integration) bool {
        for _, ref := range it.OwnerReferences {
                gv, err := schema.ParseGroupVersion(ref.APIVersion)
diff --git a/pkg/controller/catalog/initialize.go 
b/pkg/controller/catalog/initialize.go
index 3aac6ab65..d5f3c7a4a 100644
--- a/pkg/controller/catalog/initialize.go
+++ b/pkg/controller/catalog/initialize.go
@@ -45,7 +45,6 @@ func (action *initializeAction) CanHandle(catalog 
*v1.CamelCatalog) bool {
 
 func (action *initializeAction) Handle(ctx context.Context, catalog 
*v1.CamelCatalog) (*v1.CamelCatalog, error) {
        action.L.Info("Initializing CamelCatalog")
-
        platform, err := platformutil.GetForName(ctx, action.client, 
catalog.Namespace, defaults.OperatorID())
 
        if err != nil {
diff --git a/pkg/controller/integrationplatform/catalog.go 
b/pkg/controller/integrationplatform/catalog.go
deleted file mode 100644
index ea1406f1f..000000000
--- a/pkg/controller/integrationplatform/catalog.go
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-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 integrationplatform
-
-import (
-       "context"
-       "fmt"
-
-       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-       "github.com/apache/camel-k/v2/pkg/util/camel"
-
-       corev1 "k8s.io/api/core/v1"
-)
-
-// NewCreateCatalogAction returns an action to create a new CamelCatalog.
-func NewCreateCatalogAction() Action {
-       return &catalogAction{}
-}
-
-type catalogAction struct {
-       baseAction
-}
-
-func (action *catalogAction) Name() string {
-       return "catalog"
-}
-
-func (action *catalogAction) CanHandle(platform *v1.IntegrationPlatform) bool {
-       return platform.Status.Phase == v1.IntegrationPlatformPhaseCreateCatalog
-}
-
-func (action *catalogAction) Handle(ctx context.Context, platform 
*v1.IntegrationPlatform) (*v1.IntegrationPlatform, error) {
-       // New runtime version set - check that catalog exists and create it if 
it does not exist
-       runtimeSpec := v1.RuntimeSpec{
-               Version:  platform.Status.Build.RuntimeVersion,
-               Provider: v1.RuntimeProviderQuarkus,
-       }
-
-       catalog, err := camel.LoadCatalog(ctx, action.client, 
platform.Namespace, runtimeSpec)
-       if err != nil {
-               action.L.Error(err, "IntegrationPlatform unable to load Camel 
catalog",
-                       "runtime-version", runtimeSpec.Version, 
"runtime-provider", runtimeSpec.Provider)
-               return platform, nil
-       } else if catalog == nil {
-               if catalog, err = camel.CreateCatalog(ctx, action.client, 
platform.Namespace, platform, runtimeSpec); err != nil {
-                       action.L.Error(err, "IntegrationPlatform unable to 
create Camel catalog",
-                               "runtime-version", runtimeSpec.Version, 
"runtime-provider", runtimeSpec.Provider)
-
-                       platform.Status.Phase = v1.IntegrationPlatformPhaseError
-                       platform.Status.SetCondition(
-                               
v1.IntegrationPlatformConditionCamelCatalogAvailable,
-                               corev1.ConditionFalse,
-                               
v1.IntegrationPlatformConditionCamelCatalogAvailableReason,
-                               fmt.Sprintf("camel catalog %s not available, 
please review given runtime version. Error: %s", runtimeSpec.Version, err))
-
-                       return platform, nil
-               }
-       }
-
-       platform.Status.Phase = v1.IntegrationPlatformPhaseReady
-       platform.Status.SetCondition(
-               v1.IntegrationPlatformConditionCamelCatalogAvailable,
-               corev1.ConditionTrue,
-               v1.IntegrationPlatformConditionCamelCatalogAvailableReason,
-               fmt.Sprintf("camel catalog %s available", runtimeSpec.Version))
-       platform.Status.Build.RuntimeCoreVersion = 
catalog.Runtime.Metadata["camel.version"]
-
-       return platform, nil
-}
diff --git a/pkg/controller/integrationplatform/catalog_test.go 
b/pkg/controller/integrationplatform/catalog_test.go
deleted file mode 100644
index f2c526508..000000000
--- a/pkg/controller/integrationplatform/catalog_test.go
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
-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 integrationplatform
-
-import (
-       "context"
-       "errors"
-       "fmt"
-       "os"
-       "strings"
-       "testing"
-
-       "github.com/apache/camel-k/v2/pkg/util/boolean"
-
-       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-       "github.com/apache/camel-k/v2/pkg/platform"
-       "github.com/apache/camel-k/v2/pkg/resources"
-       "github.com/apache/camel-k/v2/pkg/util/defaults"
-       "github.com/apache/camel-k/v2/pkg/util/log"
-       "github.com/apache/camel-k/v2/pkg/util/maven"
-       "github.com/apache/camel-k/v2/pkg/util/test"
-       "github.com/rs/xid"
-       "github.com/stretchr/testify/assert"
-       "github.com/stretchr/testify/require"
-
-       corev1 "k8s.io/api/core/v1"
-       "k8s.io/apimachinery/pkg/runtime"
-       k8stesting "k8s.io/client-go/testing"
-       k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func TestCanHandlePhaseCreateCatalog(t *testing.T) {
-       ip := v1.IntegrationPlatform{}
-       ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       ip.Spec.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
-
-       ip.Status.Phase = v1.IntegrationPlatformPhaseCreateCatalog
-
-       c, err := test.NewFakeClient(&ip)
-       require.NoError(t, err)
-
-       action := NewCreateCatalogAction()
-       action.InjectLogger(log.Log)
-       action.InjectClient(c)
-
-       answer := action.CanHandle(&ip)
-       assert.True(t, answer)
-
-       ip.Status.Phase = v1.IntegrationPlatformPhaseError
-       answer = action.CanHandle(&ip)
-       assert.False(t, answer)
-
-       ip.Status.Phase = v1.IntegrationPlatformPhaseReady
-       answer = action.CanHandle(&ip)
-       assert.False(t, answer)
-}
-
-func TestCreateCatalog(t *testing.T) {
-       ip := v1.IntegrationPlatform{}
-       ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       ip.Status.Phase = v1.IntegrationPlatformPhaseCreateCatalog
-       ip.Spec.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
-       if strings.Contains(ip.Spec.Build.RuntimeVersion, "SNAPSHOT") {
-               maven.DefaultMavenRepositories += 
",https://repository.apache.org/content/repositories/snapshots-group@snapshots@id=apache-snapshots";
-       }
-
-       c, err := test.NewFakeClient(&ip)
-       require.NoError(t, err)
-
-       // use local Maven executable in tests
-       t.Setenv("MAVEN_WRAPPER", boolean.FalseString)
-       _, ok := os.LookupEnv("MAVEN_CMD")
-       if !ok {
-               t.Setenv("MAVEN_CMD", "mvn")
-       }
-
-       fakeClient := c.(*test.FakeClient) //nolint
-       fakeClient.AddReactor("create", "*", func(action k8stesting.Action) 
(bool, runtime.Object, error) {
-               createAction := action.(k8stesting.CreateAction) //nolint
-
-               assert.Equal(t, "ns", createAction.GetNamespace())
-
-               return true, createAction.GetObject(), nil
-       })
-
-       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
-       require.NoError(t, err)
-
-       action := NewCreateCatalogAction()
-       action.InjectLogger(log.Log)
-       action.InjectClient(c)
-
-       answer, err := action.Handle(context.TODO(), &ip)
-       require.NoError(t, err)
-       assert.NotNil(t, answer)
-
-       assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase, 
"Error", answer.Status.Conditions[0].Message)
-       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
-       // We don't know exactly which is the core version, it is enough to 
check is not empty in the test
-       assert.NotEqual(t, "", answer.Status.Build.RuntimeCoreVersion)
-
-       list := v1.NewCamelCatalogList()
-       err = c.List(context.TODO(), &list, k8sclient.InNamespace(ip.Namespace))
-
-       require.NoError(t, err)
-       assert.NotEmpty(t, list.Items)
-
-       items, err := resources.WithPrefix("/camel-catelog-")
-       require.NoError(t, err)
-
-       for _, k := range items {
-               found := false
-
-               for _, c := range list.Items {
-                       n := strings.TrimSuffix(k, ".yaml")
-                       n = strings.ToLower(n)
-
-                       if c.Name == n {
-                               found = true
-                       }
-               }
-
-               assert.True(t, found)
-       }
-}
-
-func TestCatalogAlreadyPresent(t *testing.T) {
-       ip := v1.IntegrationPlatform{}
-       ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       ip.Status.Phase = v1.IntegrationPlatformPhaseCreateCatalog
-
-       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
defaults.DefaultRuntimeVersion))
-       catalog.Spec.Runtime.Version = defaults.DefaultRuntimeVersion
-       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
-       catalog.Spec.Runtime.Metadata = map[string]string{
-               "camel.version": "4.4.0",
-       }
-
-       c, err := test.NewFakeClient(&ip, &catalog)
-       require.NoError(t, err)
-
-       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
-       require.NoError(t, err)
-
-       action := NewMonitorAction()
-       action.InjectLogger(log.Log)
-       action.InjectClient(c)
-
-       answer, err := action.Handle(context.TODO(), &ip)
-       require.NoError(t, err)
-       assert.NotNil(t, answer)
-
-       assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase)
-       assert.Equal(t, "4.4.0", answer.Status.Build.RuntimeCoreVersion)
-       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
-}
-
-func TestCreateCatalogError(t *testing.T) {
-       ip := v1.IntegrationPlatform{}
-       ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       ip.Status.Phase = v1.IntegrationPlatformPhaseCreateCatalog
-
-       // force catalog build to fail
-       ip.Spec.Build.RuntimeVersion = "0.0.0"
-
-       c, err := test.NewFakeClient(&ip)
-       require.NoError(t, err)
-
-       // use local Maven executable in tests
-       t.Setenv("MAVEN_WRAPPER", boolean.FalseString)
-       _, ok := os.LookupEnv("MAVEN_CMD")
-       if !ok {
-               t.Setenv("MAVEN_CMD", "mvn")
-       }
-
-       fakeClient := c.(*test.FakeClient) //nolint
-       fakeClient.AddReactor("create", "*", func(action k8stesting.Action) 
(bool, runtime.Object, error) {
-               createAction := action.(k8stesting.CreateAction) //nolint
-
-               assert.Equal(t, "ns", createAction.GetNamespace())
-
-               return true, nil, errors.New("failed to create catalog for some 
reason")
-       })
-
-       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
-       require.NoError(t, err)
-
-       action := NewCreateCatalogAction()
-       action.InjectLogger(log.Log)
-       action.InjectClient(c)
-
-       answer, err := action.Handle(context.TODO(), &ip)
-       require.NoError(t, err)
-       assert.NotNil(t, answer)
-
-       assert.Equal(t, v1.IntegrationPlatformPhaseError, answer.Status.Phase)
-       assert.Equal(t, corev1.ConditionFalse, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
-       assert.Equal(t, 
v1.IntegrationPlatformConditionCamelCatalogAvailableReason, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Reason)
-       assert.Contains(t, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Message,
 "camel catalog 0.0.0 not available, please review given runtime version. 
Error:")
-}
diff --git a/pkg/controller/integrationplatform/create.go 
b/pkg/controller/integrationplatform/create.go
index 8471ca5e5..85edbf94a 100644
--- a/pkg/controller/integrationplatform/create.go
+++ b/pkg/controller/integrationplatform/create.go
@@ -19,14 +19,17 @@ package integrationplatform
 
 import (
        "context"
+       "fmt"
 
+       "gopkg.in/yaml.v2"
        corev1 "k8s.io/api/core/v1"
-       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-       "github.com/apache/camel-k/v2/pkg/install"
+       "github.com/apache/camel-k/v2/pkg/client"
        "github.com/apache/camel-k/v2/pkg/resources"
+       "github.com/apache/camel-k/v2/pkg/util/camel"
        "github.com/apache/camel-k/v2/pkg/util/defaults"
+       k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 // NewCreateAction returns the action that creates resources needed by the 
platform.
@@ -47,38 +50,141 @@ func (action *createAction) CanHandle(platform 
*v1.IntegrationPlatform) bool {
 }
 
 func (action *createAction) Handle(ctx context.Context, platform 
*v1.IntegrationPlatform) (*v1.IntegrationPlatform, error) {
-       paths, err := resources.WithPrefix("/resources/camel-catalog-")
+       runtimeSpec := v1.RuntimeSpec{
+               Version:  platform.Status.Build.RuntimeVersion,
+               Provider: platform.Status.Build.RuntimeProvider,
+       }
+       catalog, err := loadCatalog(ctx, action.client, platform.Namespace, 
runtimeSpec)
        if err != nil {
                return nil, err
        }
 
-       for _, k := range paths {
-               action.L.Infof("Installing camel catalog: %s", k)
-               err := install.Resources(ctx, action.client, 
platform.Namespace, true,
-                       func(object ctrl.Object) ctrl.Object {
-                               action.L.Infof("Copying platform annotations to 
catalog: %s", object.GetName())
-                               object.SetAnnotations(platform.Annotations)
-                               return object
-                       },
-                       k)
+       // if bundled version, load catalog spec from resources
+       if platform.Status.Build.RuntimeVersion == 
defaults.DefaultRuntimeVersion {
+               if platform, err = action.handleBundledCatalog(ctx, platform, 
catalog); err != nil {
+                       return platform, err
+               }
+       } else {
+               // otherwise get the catalog from external dependency
+               if platform, err = action.handleNewCatalog(ctx, platform, 
catalog, runtimeSpec); err != nil {
+                       return platform, err
+               }
+       }
+
+       platform.Status.Phase = v1.IntegrationPlatformPhaseReady
+       platform.Status.SetCondition(
+               v1.IntegrationPlatformConditionCamelCatalogAvailable,
+               corev1.ConditionTrue,
+               v1.IntegrationPlatformConditionCamelCatalogAvailableReason,
+               fmt.Sprintf("camel catalog %s available", 
platform.Status.Build.RuntimeVersion))
+
+       if platform.Status.Build.RuntimeCoreVersion != "" {
+               action.L.Infof("IntegrationPlatform is about to install Apache 
Kamelet Catalog version %s", platform.Status.Build.RuntimeCoreVersion)
+               return installKamelets(ctx, action.client, platform)
+       } else {
+               action.L.Info("IntegrationPlatform has no Camel core version. " 
+
+                       "It is likely an unsupported specification, please, 
update to the latest one")
+       }
+
+       return platform, nil
+}
+
+func loadCatalog(ctx context.Context, c client.Client, namespace string, 
runtimeSpec v1.RuntimeSpec) (*v1.CamelCatalog, error) {
+       options := []k8sclient.ListOption{
+               k8sclient.InNamespace(namespace),
+       }
+       list := v1.NewCamelCatalogList()
+       if err := c.List(ctx, &list, options...); err != nil {
+               return nil, err
+       }
+       for _, cc := range list.Items {
+               if cc.Spec.Runtime.Provider == runtimeSpec.Provider && 
cc.Spec.Runtime.Version == runtimeSpec.Version {
+                       return &cc, nil
+               }
+       }
+
+       return nil, nil
+}
+
+func (action *createAction) handleBundledCatalog(ctx context.Context, platform 
*v1.IntegrationPlatform, catalog *v1.CamelCatalog) (*v1.IntegrationPlatform, 
error) {
+       var camelVersion string
+       // Create the catalog only if it was not yet created
+       if catalog == nil {
+               camelCatalogData, err := 
resources.Resource(fmt.Sprintf("/resources/camel-catalog-%s.yaml", 
platform.Status.Build.RuntimeVersion))
                if err != nil {
                        return nil, err
                }
+               var cat v1.CamelCatalog
+               if err = yaml.Unmarshal(camelCatalogData, &cat); err != nil {
+                       return nil, err
+               }
+               // Copy platform annotations to the catalog
+               cat.SetAnnotations(platform.Annotations)
+               cat.SetNamespace(platform.Namespace)
+               action.L.Infof("Installing bundled camel catalog: %s", 
platform.Status.Build.RuntimeVersion)
+               if err = action.client.Create(ctx, &cat); err != nil {
+                       return nil, err
+               }
+               camelVersion = cat.Spec.GetCamelVersion()
+       } else {
+               camelVersion = catalog.Spec.GetCamelVersion()
        }
+       platform.Status.Build.RuntimeCoreVersion = camelVersion
 
-       if defaults.InstallDefaultKamelets() {
-               // Kamelet Catalog installed on platform reconciliation for 
cases where users install a global operator
-               if err := install.KameletCatalog(ctx, action.client, 
platform.Namespace); err != nil {
-                       return nil, err
+       return platform, nil
+}
+
+func (action *createAction) handleNewCatalog(ctx context.Context, platform 
*v1.IntegrationPlatform,
+       catalog *v1.CamelCatalog, runtimeSpec v1.RuntimeSpec) 
(*v1.IntegrationPlatform, error) {
+       var camelVersion string
+       if catalog == nil {
+               cat, err := camel.CreateCatalog(ctx, action.client, 
platform.Namespace, platform, runtimeSpec)
+               if err != nil {
+                       action.L.Error(err, "IntegrationPlatform unable to 
create Camel catalog",
+                               "runtime-version", runtimeSpec.Version, 
"runtime-provider", runtimeSpec.Provider)
+
+                       platform.Status.Phase = v1.IntegrationPlatformPhaseError
+                       platform.Status.SetCondition(
+                               
v1.IntegrationPlatformConditionCamelCatalogAvailable,
+                               corev1.ConditionFalse,
+                               
v1.IntegrationPlatformConditionCamelCatalogAvailableReason,
+                               fmt.Sprintf("camel catalog %s not available, 
please review given runtime version. Error: %s", runtimeSpec.Version, err))
+
+                       return platform, err
                }
+               camelVersion = cat.GetCamelVersion()
+       } else {
+               camelVersion = catalog.Spec.GetCamelVersion()
        }
+       platform.Status.Build.RuntimeCoreVersion = camelVersion
 
-       platform.Status.SetCondition(
-               v1.IntegrationPlatformConditionTypeCreated,
-               corev1.ConditionTrue,
-               v1.IntegrationPlatformConditionCreatedReason,
-               "integration platform created")
+       return platform, nil
+}
+
+func installKamelets(ctx context.Context, c client.Client, platform 
*v1.IntegrationPlatform) (*v1.IntegrationPlatform, error) {
+       // We bundle the Kamelets driven by the catalog
+       if defaults.InstallDefaultKamelets() {
+               camelVersion := platform.Status.Build.RuntimeCoreVersion
+               installedKam, erroredKam, err := installKameletCatalog(ctx, c, 
platform, camelVersion)
+               if err != nil {
+                       platform.Status.Phase = v1.IntegrationPlatformPhaseError
+                       platform.Status.SetCondition(
+                               
v1.IntegrationPlatformConditionKameletCatalogAvailable,
+                               corev1.ConditionFalse,
+                               "IntegrationPlatformKameletCatalogAvailable",
+                               fmt.Sprintf("kamelet catalog %s not available, 
please review given camel version. Error: %s", camelVersion, err),
+                       )
+
+                       return platform, nil
+               }
+               platform.Status.SetCondition(
+                       v1.IntegrationPlatformConditionKameletCatalogAvailable,
+                       corev1.ConditionTrue,
+                       "IntegrationPlatformKameletCatalogAvailable",
+                       fmt.Sprintf("successfully installed Kamelet catalog 
version %s: success %d Kamelets, failed %d Kamelets",
+                               camelVersion, installedKam, erroredKam),
+               )
+       }
 
-       platform.Status.Phase = v1.IntegrationPlatformPhaseReady
        return platform, nil
 }
diff --git a/pkg/controller/integrationplatform/create_test.go 
b/pkg/controller/integrationplatform/create_test.go
index 55230f024..c47532070 100644
--- a/pkg/controller/integrationplatform/create_test.go
+++ b/pkg/controller/integrationplatform/create_test.go
@@ -19,67 +19,206 @@ package integrationplatform
 
 import (
        "context"
+       "errors"
+       "fmt"
+       "os"
        "strings"
        "testing"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        "github.com/apache/camel-k/v2/pkg/platform"
-       "github.com/apache/camel-k/v2/pkg/resources"
+       "github.com/apache/camel-k/v2/pkg/util/boolean"
+       "github.com/apache/camel-k/v2/pkg/util/defaults"
        "github.com/apache/camel-k/v2/pkg/util/log"
+       "github.com/apache/camel-k/v2/pkg/util/maven"
        "github.com/apache/camel-k/v2/pkg/util/test"
-       "github.com/rs/xid"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
+       corev1 "k8s.io/api/core/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       k8stesting "k8s.io/client-go/testing"
        k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 func TestCreate(t *testing.T) {
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
+       ip.Name = "ck"
+       ip.Status = v1.IntegrationPlatformStatus{
+               IntegrationPlatformSpec: v1.IntegrationPlatformSpec{
+                       Build: v1.IntegrationPlatformBuildSpec{
+                               RuntimeProvider: v1.RuntimeProviderQuarkus,
+                               RuntimeVersion:  defaults.DefaultRuntimeVersion,
+                       },
+               },
+       }
+       c, err := test.NewFakeClient(&ip)
+       require.NoError(t, err)
+
+       h := NewCreateAction()
+       h.InjectLogger(log.Log)
+       h.InjectClient(c)
+       // We don't want to test the installation procedure here
+       os.Setenv("KAMEL_INSTALL_DEFAULT_KAMELETS", "false")
+       answer, err := h.Handle(context.TODO(), &ip)
+
+       require.NoError(t, err)
+       assert.NotNil(t, answer)
+       assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase)
+       assert.Equal(t, defaults.DefaultRuntimeVersion, 
answer.Status.Build.RuntimeVersion)
+       assert.Equal(t, v1.RuntimeProviderQuarkus, 
answer.Status.Build.RuntimeProvider)
+       assert.NotEqual(t, "", answer.Status.Build.RuntimeCoreVersion)
+       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
+
+       list := v1.NewCamelCatalogList()
+       err = c.List(context.TODO(), &list, k8sclient.InNamespace(ip.Namespace))
+       require.NoError(t, err)
+       assert.NotEmpty(t, list.Items)
+}
+
+func TestCatalogAlreadyPresent(t *testing.T) {
+       ip := v1.IntegrationPlatform{}
+       ip.Namespace = "ns"
+       ip.Name = "ck"
+       ip.Status = v1.IntegrationPlatformStatus{
+               IntegrationPlatformSpec: v1.IntegrationPlatformSpec{
+                       Build: v1.IntegrationPlatformBuildSpec{
+                               RuntimeProvider: v1.RuntimeProviderQuarkus,
+                               RuntimeVersion:  defaults.DefaultRuntimeVersion,
+                       },
+               },
+       }
+
+       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
defaults.DefaultRuntimeVersion))
+       catalog.Spec.Runtime.Version = defaults.DefaultRuntimeVersion
+       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
+       catalog.Spec.Runtime.Metadata = map[string]string{
+               "camel.version": "4.4.0",
+       }
+
+       c, err := test.NewFakeClient(&ip, &catalog)
+       require.NoError(t, err)
+
+       action := NewCreateAction()
+       action.InjectLogger(log.Log)
+       action.InjectClient(c)
+
+       // We don't want to test the installation procedure here
+       os.Setenv("KAMEL_INSTALL_DEFAULT_KAMELETS", "false")
+       answer, err := action.Handle(context.TODO(), &ip)
+       os.Unsetenv("KAMEL_INSTALL_DEFAULT_KAMELETS")
+       require.NoError(t, err)
+       assert.NotNil(t, answer)
+
+       assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase)
+       assert.Equal(t, "4.4.0", answer.Status.Build.RuntimeCoreVersion)
+       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
+}
+
+func TestCreateNewCatalog(t *testing.T) {
+       ip := v1.IntegrationPlatform{}
+       ip.Namespace = "ns"
+       ip.Name = "ck"
+       ip.Status = v1.IntegrationPlatformStatus{
+               IntegrationPlatformSpec: v1.IntegrationPlatformSpec{
+                       Build: v1.IntegrationPlatformBuildSpec{
+                               RuntimeProvider: v1.RuntimeProviderQuarkus,
+                               RuntimeVersion:  defaults.DefaultRuntimeVersion,
+                       },
+               },
+       }
+       if strings.Contains(ip.Spec.Build.RuntimeVersion, "SNAPSHOT") {
+               maven.DefaultMavenRepositories += 
",https://repository.apache.org/content/repositories/snapshots-group@snapshots@id=apache-snapshots";
+       }
 
        c, err := test.NewFakeClient(&ip)
        require.NoError(t, err)
 
+       // use local Maven executable in tests
+       t.Setenv("MAVEN_WRAPPER", boolean.FalseString)
+       _, ok := os.LookupEnv("MAVEN_CMD")
+       if !ok {
+               t.Setenv("MAVEN_CMD", "mvn")
+       }
+
+       fakeClient := c.(*test.FakeClient) //nolint
+       fakeClient.AddReactor("create", "*", func(action k8stesting.Action) 
(bool, runtime.Object, error) {
+               createAction := action.(k8stesting.CreateAction) //nolint
+
+               assert.Equal(t, "ns", createAction.GetNamespace())
+
+               return true, createAction.GetObject(), nil
+       })
+
        err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
        require.NoError(t, err)
 
-       h := NewCreateAction()
-       h.InjectLogger(log.Log)
-       h.InjectClient(c)
+       action := NewCreateAction()
+       action.InjectLogger(log.Log)
+       action.InjectClient(c)
 
-       answer, err := h.Handle(context.TODO(), &ip)
+       // Set the folder where to install testing kamelets
+       tmpDir, err := os.MkdirTemp("/tmp", "kamelets*")
+       assert.NoError(t, err)
+       os.Setenv(kameletDirEnv, tmpDir)
+       answer, err := action.Handle(context.TODO(), &ip)
+       os.Unsetenv(kameletDirEnv)
        require.NoError(t, err)
        assert.NotNil(t, answer)
 
+       assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase)
+       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
+       // We don't know exactly which is the core version, it is enough to 
check is not empty in the test
+       assert.NotEqual(t, "", answer.Status.Build.RuntimeCoreVersion)
+       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionKameletCatalogAvailable).Status)
+       assert.Contains(t, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionKameletCatalogAvailable).Message,
+               fmt.Sprintf("successfully installed Kamelet catalog version 
%s", answer.Status.Build.RuntimeCoreVersion),
+               "failed 0 Kamelets")
+
        list := v1.NewCamelCatalogList()
        err = c.List(context.TODO(), &list, k8sclient.InNamespace(ip.Namespace))
 
        require.NoError(t, err)
        assert.NotEmpty(t, list.Items)
+}
 
-       items, err := resources.WithPrefix("/resources/camel-catalog-")
+func TestCreateCatalogError(t *testing.T) {
+       ip := v1.IntegrationPlatform{}
+       ip.Namespace = "ns"
+       ip.Name = "ck"
+       ip.Spec.Build.RuntimeVersion = "0.0.0"
+       c, err := test.NewFakeClient(&ip)
        require.NoError(t, err)
 
-       foundOverall := 0
-       for _, k := range items {
-               found := false
+       // use local Maven executable in tests
+       t.Setenv("MAVEN_WRAPPER", boolean.FalseString)
+       _, ok := os.LookupEnv("MAVEN_CMD")
+       if !ok {
+               t.Setenv("MAVEN_CMD", "mvn")
+       }
+
+       fakeClient := c.(*test.FakeClient) //nolint
+       fakeClient.AddReactor("create", "*", func(action k8stesting.Action) 
(bool, runtime.Object, error) {
+               createAction := action.(k8stesting.CreateAction) //nolint
 
-               for _, c := range list.Items {
-                       n := strings.TrimSuffix(k, ".yaml")
-                       n = strings.TrimPrefix(n, "resources/")
-                       n = strings.ToLower(n)
+               assert.Equal(t, "ns", createAction.GetNamespace())
 
-                       if c.Name == n {
-                               found = true
-                               foundOverall++
-                       }
-               }
+               return true, nil, errors.New("failed to create catalog for some 
reason")
+       })
 
-               assert.True(t, found)
-       }
+       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
+       require.NoError(t, err)
+
+       action := NewCreateAction()
+       action.InjectLogger(log.Log)
+       action.InjectClient(c)
+
+       answer, err := action.Handle(context.TODO(), &ip)
+       require.Error(t, err)
+       assert.NotNil(t, answer)
 
-       assert.Equal(t, 1, foundOverall)
+       assert.Equal(t, v1.IntegrationPlatformPhaseError, answer.Status.Phase)
+       assert.Equal(t, corev1.ConditionFalse, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
+       assert.Equal(t, 
v1.IntegrationPlatformConditionCamelCatalogAvailableReason, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Reason)
+       assert.Contains(t, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Message,
 "camel catalog 0.0.0 not available, please review given runtime version. 
Error:")
 }
diff --git a/pkg/controller/integrationplatform/initialize.go 
b/pkg/controller/integrationplatform/initialize.go
index 4b68c2ff9..9a0141f26 100644
--- a/pkg/controller/integrationplatform/initialize.go
+++ b/pkg/controller/integrationplatform/initialize.go
@@ -19,10 +19,11 @@ package integrationplatform
 
 import (
        "context"
+       "fmt"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        platformutil "github.com/apache/camel-k/v2/pkg/platform"
-       "github.com/apache/camel-k/v2/pkg/util/defaults"
+       corev1 "k8s.io/api/core/v1"
 )
 
 // NewInitializeAction returns the action that initializes the integration 
platform when not provided by the user.
@@ -47,8 +48,18 @@ func (action *initializeAction) Handle(ctx context.Context, 
platform *v1.Integra
        if err := platformutil.ConfigureDefaults(ctx, action.client, platform, 
true); err != nil {
                return nil, err
        }
-       platform.Status.Phase = v1.IntegrationPlatformPhaseCreating
-       platform.Status.Version = defaults.Version
+       if platform.Status.Build.RuntimeVersion == "" {
+               platform.Status.Phase = v1.IntegrationPlatformPhaseError
+               platform.Status.SetCondition(
+                       v1.IntegrationPlatformConditionTypeCreated,
+                       corev1.ConditionFalse,
+                       "MissingRuntimeVersionSpec",
+                       "Runtime version missing from build spec")
+
+               return platform, fmt.Errorf("runtime version missing from build 
spec")
+       } else {
+               platform.Status.Phase = v1.IntegrationPlatformPhaseCreating
+       }
 
        return platform, nil
 }
diff --git a/pkg/controller/integrationplatform/initialize_test.go 
b/pkg/controller/integrationplatform/initialize_test.go
index b7b396053..14a66deeb 100644
--- a/pkg/controller/integrationplatform/initialize_test.go
+++ b/pkg/controller/integrationplatform/initialize_test.go
@@ -22,28 +22,66 @@ import (
        "testing"
        "time"
 
-       "github.com/rs/xid"
-
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        "github.com/apache/camel-k/v2/pkg/platform"
+       "github.com/apache/camel-k/v2/pkg/util/defaults"
        "github.com/apache/camel-k/v2/pkg/util/log"
        "github.com/apache/camel-k/v2/pkg/util/test"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-func TestTimeouts_Default(t *testing.T) {
+func TestDefaultRuntimeSpec(t *testing.T) {
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
+       ip.Name = "ck"
+       c, err := test.NewFakeClient(&ip)
+       require.NoError(t, err)
+
+       h := NewInitializeAction()
+       h.InjectLogger(log.Log)
+       h.InjectClient(c)
+
+       answer, err := h.Handle(context.TODO(), &ip)
+       require.NoError(t, err)
+       assert.Equal(t, v1.IntegrationPlatformPhaseCreating, 
answer.Status.Phase)
+       assert.Equal(t, defaults.DefaultRuntimeVersion, 
answer.Status.Build.RuntimeVersion)
+       assert.Equal(t, v1.RuntimeProviderQuarkus, 
answer.Status.Build.RuntimeProvider)
+}
 
+func TestUserRuntimeSpec(t *testing.T) {
+       ip := v1.IntegrationPlatform{}
+       ip.Namespace = "ns"
+       ip.Name = "ck"
+       ip.Spec = v1.IntegrationPlatformSpec{
+               Build: v1.IntegrationPlatformBuildSpec{
+                       RuntimeVersion:  "1.2.3",
+                       RuntimeProvider: "MyProvider",
+               },
+       }
        c, err := test.NewFakeClient(&ip)
        require.NoError(t, err)
 
+       h := NewInitializeAction()
+       h.InjectLogger(log.Log)
+       h.InjectClient(c)
+
+       answer, err := h.Handle(context.TODO(), &ip)
+       require.NoError(t, err)
+       assert.Equal(t, v1.IntegrationPlatformPhaseCreating, 
answer.Status.Phase)
+       assert.Equal(t, "1.2.3", answer.Status.Build.RuntimeVersion)
+       assert.Equal(t, v1.RuntimeProvider("MyProvider"), 
answer.Status.Build.RuntimeProvider)
+}
+
+func TestDefaultTimeouts(t *testing.T) {
+       ip := v1.IntegrationPlatform{}
+       ip.Namespace = "ns"
+       ip.Name = "ck"
+       c, err := test.NewFakeClient(&ip)
+
+       require.NoError(t, err)
        require.NoError(t, platform.ConfigureDefaults(context.TODO(), c, &ip, 
false))
 
        h := NewInitializeAction()
@@ -52,67 +90,50 @@ func TestTimeouts_Default(t *testing.T) {
 
        answer, err := h.Handle(context.TODO(), &ip)
        require.NoError(t, err)
-       assert.NotNil(t, answer)
-
+       assert.Equal(t, v1.IntegrationPlatformPhaseCreating, 
answer.Status.Phase)
        assert.Equal(t, 5*time.Minute, 
answer.Status.Build.GetTimeout().Duration)
 }
 
-func TestTimeouts_MavenComputedFromBuild(t *testing.T) {
+func TestMavenComputedFromBuildTimeouts(t *testing.T) {
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-
+       ip.Name = "ck"
        timeout, err := time.ParseDuration("1m1ms")
        require.NoError(t, err)
-
        ip.Spec.Build.Timeout = &metav1.Duration{
                Duration: timeout,
        }
-
        c, err := test.NewFakeClient(&ip)
        require.NoError(t, err)
 
-       require.NoError(t, platform.ConfigureDefaults(context.TODO(), c, &ip, 
false))
-
        h := NewInitializeAction()
        h.InjectLogger(log.Log)
        h.InjectClient(c)
-
        answer, err := h.Handle(context.TODO(), &ip)
+
        require.NoError(t, err)
        assert.NotNil(t, answer)
-
        assert.Equal(t, 1*time.Minute, 
answer.Status.Build.GetTimeout().Duration)
 }
 
-func TestTimeouts_Truncated(t *testing.T) {
+func TestTruncatedTimeouts(t *testing.T) {
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-
+       ip.Name = "ck"
        bt, err := time.ParseDuration("5m1ms")
        require.NoError(t, err)
-
        ip.Spec.Build.Timeout = &metav1.Duration{
                Duration: bt,
        }
-
        c, err := test.NewFakeClient(&ip)
        require.NoError(t, err)
 
-       require.NoError(t, platform.ConfigureDefaults(context.TODO(), c, &ip, 
false))
-
        h := NewInitializeAction()
        h.InjectLogger(log.Log)
        h.InjectClient(c)
-
        answer, err := h.Handle(context.TODO(), &ip)
+
        require.NoError(t, err)
        assert.NotNil(t, answer)
-
        assert.Equal(t, 5*time.Minute, 
answer.Status.Build.GetTimeout().Duration)
 }
diff --git 
a/pkg/controller/integrationplatform/integrationplatform_controller.go 
b/pkg/controller/integrationplatform/integrationplatform_controller.go
index 99197df4a..ba48423da 100644
--- a/pkg/controller/integrationplatform/integrationplatform_controller.go
+++ b/pkg/controller/integrationplatform/integrationplatform_controller.go
@@ -19,7 +19,6 @@ package integrationplatform
 
 import (
        "context"
-       "time"
 
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/apimachinery/pkg/runtime"
@@ -41,10 +40,6 @@ import (
        "github.com/apache/camel-k/v2/pkg/util/monitoring"
 )
 
-const (
-       requeueAfterDuration = 5 * time.Second
-)
-
 // Add creates a new IntegrationPlatform Controller and adds it to the 
Manager. The Manager will set fields
 // on the Controller and Start it when the Manager is Started.
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
@@ -161,7 +156,6 @@ func (r *reconcileIntegrationPlatform) Reconcile(ctx 
context.Context, request re
                NewInitializeAction(),
                NewCreateAction(),
                NewMonitorAction(),
-               NewCreateCatalogAction(),
        }
 
        var targetPhase v1.IntegrationPlatformPhase
@@ -214,12 +208,5 @@ func (r *reconcileIntegrationPlatform) Reconcile(ctx 
context.Context, request re
                break
        }
 
-       if targetPhase == v1.IntegrationPlatformPhaseReady {
-               return reconcile.Result{}, nil
-       }
-
-       // Requeue
-       return reconcile.Result{
-               RequeueAfter: requeueAfterDuration,
-       }, nil
+       return reconcile.Result{}, nil
 }
diff --git a/pkg/controller/integrationplatform/kamelets.go 
b/pkg/controller/integrationplatform/kamelets.go
new file mode 100644
index 000000000..370f464e0
--- /dev/null
+++ b/pkg/controller/integrationplatform/kamelets.go
@@ -0,0 +1,209 @@
+/*
+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 integrationplatform
+
+import (
+       "context"
+       "encoding/json"
+       "fmt"
+       "io/fs"
+       "os"
+       "os/exec"
+       "path"
+       "path/filepath"
+       "strings"
+
+       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+       "github.com/apache/camel-k/v2/pkg/install"
+       "github.com/apache/camel-k/v2/pkg/platform"
+       "knative.dev/pkg/ptr"
+
+       "github.com/apache/camel-k/v2/pkg/client"
+       "github.com/apache/camel-k/v2/pkg/util"
+       "github.com/apache/camel-k/v2/pkg/util/defaults"
+       "github.com/apache/camel-k/v2/pkg/util/log"
+       "github.com/apache/camel-k/v2/pkg/util/maven"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       k8syaml "k8s.io/apimachinery/pkg/util/yaml"
+)
+
+const (
+       kameletDirEnv          = "KAMELET_CATALOG_DIR"
+       defaultKameletDir      = "/tmp/kamelets/"
+       kamelVersionAnnotation = "camel.apache.org/version"
+)
+
+// installKameletCatalog installs the version Apache Kamelet Catalog into the 
specified namespace. It returns the number of Kamelets installed and errored
+// if successful.
+func installKameletCatalog(ctx context.Context, c client.Client, platform 
*v1.IntegrationPlatform, version string) (int, int, error) {
+       // Prepare proper privileges for Kamelets installed globally
+       if err := prepareKameletsPermissions(ctx, c, platform.Namespace); err 
!= nil {
+               return -1, -1, err
+       }
+       // Prepare directory to contains kamelets
+       kameletDir := prepareKameletDirectory()
+       // Download Kamelet dependency
+       if err := downloadKameletDependency(ctx, version, kameletDir); err != 
nil {
+               return -1, -1, err
+       }
+       // Extract Kamelets files
+       if err := extractKameletsFromDependency(ctx, version, kameletDir); err 
!= nil {
+               return -1, -1, err
+       }
+
+       // Store Kamelets as Kubernetes resources
+       return applyKamelets(ctx, c, platform, kameletDir)
+}
+
+func prepareKameletsPermissions(ctx context.Context, c client.Client, 
installingNamespace string) error {
+       watchOperatorNamespace := platform.GetOperatorWatchNamespace()
+       operatorNamespace := platform.GetOperatorNamespace()
+       if watchOperatorNamespace == "" && operatorNamespace == 
installingNamespace {
+               // Kamelets installed into the global operator namespace
+               // They need to be visible publicly
+               if err := kameletViewerRole(ctx, c, installingNamespace); err 
!= nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func prepareKameletDirectory() string {
+       kameletDir := os.Getenv(kameletDirEnv)
+       if kameletDir == "" {
+               kameletDir = defaultKameletDir
+       }
+
+       return kameletDir
+}
+
+func downloadKameletDependency(ctx context.Context, version, kameletsDir 
string) error {
+       // TODO: we may want to add the maven settings coming from the platform
+       // in order to cover any user security setting in place
+       p := maven.NewProjectWithGAV("org.apache.camel.k.kamelets", 
"kamelets-catalog", defaults.Version)
+       mc := maven.NewContext(kameletsDir)
+       mc.AddArgument("-q")
+       mc.AddArgument("dependency:copy")
+       
mc.AddArgument(fmt.Sprintf("-Dartifact=org.apache.camel.kamelets:camel-kamelets:%s:jar",
 version))
+       mc.AddArgument("-Dmdep.useBaseVersion=true")
+       mc.AddArgument(fmt.Sprintf("-DoutputDirectory=%s", kameletsDir))
+
+       return p.Command(mc).Do(ctx)
+}
+
+func extractKameletsFromDependency(ctx context.Context, version, kameletsDir 
string) error {
+       args := strings.Split(
+               fmt.Sprintf("-xf camel-kamelets-%s.jar kamelets/", version), " 
")
+       cmd := exec.CommandContext(ctx, "jar", args...)
+       cmd.Dir = kameletsDir
+       return util.RunAndLog(ctx, cmd, maven.LogHandler, maven.LogHandler)
+}
+
+func applyKamelets(ctx context.Context, c client.Client, platform 
*v1.IntegrationPlatform, kameletDir string) (int, int, error) {
+       appliedKam := 0
+       erroredKam := 0
+       applier := c.ServerOrClientSideApplier()
+       dir := path.Join(kameletDir, "kamelets")
+
+       err := filepath.WalkDir(dir, func(p string, f fs.DirEntry, err error) 
error {
+               if err != nil {
+                       return err
+               }
+               if !(strings.HasSuffix(f.Name(), ".yaml") || 
strings.HasSuffix(f.Name(), ".yml")) {
+                       return nil
+               }
+               kamelet, err := loadKamelet(filepath.Join(dir, f.Name()), 
platform)
+               // We cannot return if an error happen, otherwise the creation 
of the IntegrationPlatform would result
+               // in a failure. We better report in conditions.
+               if err != nil {
+                       erroredKam++
+                       log.Errorf(err, "Error occurred whilst loading a 
bundled kamelet named %s", f.Name())
+                       return nil
+               }
+               err = applier.Apply(ctx, kamelet)
+               if err != nil {
+                       erroredKam++
+                       log.Error(err, "Error occurred whilst applying a 
bundled kamelet named %s", kamelet.GetName())
+                       return nil
+               }
+               appliedKam++
+
+               return nil
+       })
+       if err != nil {
+               return appliedKam, erroredKam, err
+       }
+
+       return appliedKam, erroredKam, nil
+}
+
+func loadKamelet(path string, platform *v1.IntegrationPlatform) (*v1.Kamelet, 
error) {
+       yamlContent, err := util.ReadFile(path)
+       if err != nil {
+               return nil, err
+       }
+       // Kamelet spec contains raw object spec, for which we need to convert 
to json
+       // for a proper serde
+       jsonContent, err := k8syaml.ToJSON(yamlContent)
+       if err != nil {
+               return nil, err
+       }
+       var kamelet *v1.Kamelet
+       if err = json.Unmarshal(jsonContent, &kamelet); err != nil {
+               return nil, err
+       }
+       kamelet.SetNamespace(platform.Namespace)
+       annotations := kamelet.GetAnnotations()
+       if annotations == nil {
+               annotations = make(map[string]string)
+       }
+       annotations[kamelVersionAnnotation] = defaults.Version
+       kamelet.SetAnnotations(annotations)
+       labels := kamelet.GetLabels()
+       if labels == nil {
+               labels = make(map[string]string)
+       }
+       labels[v1.KameletBundledLabel] = "true"
+       labels[v1.KameletReadOnlyLabel] = "true"
+
+       // The Kamelet will be owned by the IntegrationPlatform
+       references := []metav1.OwnerReference{
+               {
+                       APIVersion:         platform.APIVersion,
+                       Kind:               platform.Kind,
+                       Name:               platform.Name,
+                       UID:                platform.UID,
+                       Controller:         ptr.Bool(true),
+                       BlockOwnerDeletion: ptr.Bool(true),
+               },
+       }
+       kamelet.SetOwnerReferences(references)
+
+       return kamelet, nil
+}
+
+// kameletViewerRole installs the role that allows any user ro access kamelets 
in the global namespace.
+func kameletViewerRole(ctx context.Context, c client.Client, namespace string) 
error {
+       if err := install.Resource(ctx, c, namespace, true, 
install.IdentityResourceCustomizer,
+               "/resources/viewer/user-global-kamelet-viewer-role.yaml"); err 
!= nil {
+               return err
+       }
+       return install.Resource(ctx, c, namespace, true, 
install.IdentityResourceCustomizer,
+               
"/resources/viewer/user-global-kamelet-viewer-role-binding.yaml")
+}
diff --git a/pkg/controller/integrationplatform/kamelets_test.go 
b/pkg/controller/integrationplatform/kamelets_test.go
new file mode 100644
index 000000000..7a1a79aa6
--- /dev/null
+++ b/pkg/controller/integrationplatform/kamelets_test.go
@@ -0,0 +1,153 @@
+/*
+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 integrationplatform
+
+import (
+       "context"
+       "fmt"
+       "io/fs"
+       "os"
+       "path"
+       "path/filepath"
+       "strings"
+       "testing"
+
+       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+       "github.com/apache/camel-k/v2/pkg/util/boolean"
+       "github.com/apache/camel-k/v2/pkg/util/camel"
+       "github.com/apache/camel-k/v2/pkg/util/test"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestLoadKamelet(t *testing.T) {
+       itp := v1.NewIntegrationPlatform("itp-ns", "my-itp")
+       var tmpKameletFile *os.File
+       var err error
+       tmpKameletFile, err = os.CreateTemp("/tmp", 
"timer-source-*.kamelet.yaml")
+       require.NoError(t, err)
+       require.NoError(t, tmpKameletFile.Close())
+       require.NoError(t, os.WriteFile(tmpKameletFile.Name(), 
[]byte(`apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+  name: timer-source
+  annotations:
+    camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,XYZABC123"
+  labels:
+    camel.apache.org/kamelet.type: "source"
+spec:
+  definition:
+    title: "Timer Source"
+    description: "Produces periodic events with a custom payload"
+    required:
+      - message
+    properties:
+      period:
+        title: Period
+        description: The interval between two events
+        type: integer
+        default: 1000
+      message:
+        title: Message
+        description: The message to generate
+        type: string
+        example: "hello world"
+  dataTypes:
+    out:
+      default: text
+      types:
+        text:
+          mediaType: text/plain
+  template:
+    from:
+      uri: timer:tick
+      parameters:
+        period: "{{period}}"
+      steps:
+      - setBody:
+          constant: "{{message}}"
+      - to: "kamelet:sink"
+`), 0o400))
+
+       kamelet, err := loadKamelet(tmpKameletFile.Name(), &itp)
+
+       assert.NotNil(t, kamelet)
+       require.NoError(t, err)
+       assert.Equal(t, "timer-source", kamelet.GetName())
+       assert.Equal(t, "itp-ns", kamelet.GetNamespace())
+       assert.Len(t, kamelet.GetLabels(), 3)
+       assert.Equal(t, "true", kamelet.GetLabels()[v1.KameletBundledLabel])
+       assert.Equal(t, "true", kamelet.GetLabels()[v1.KameletReadOnlyLabel])
+       assert.Len(t, kamelet.GetAnnotations(), 2)
+       assert.NotNil(t, kamelet.GetAnnotations()[kamelVersionAnnotation])
+       assert.Equal(t, "my-itp", kamelet.GetOwnerReferences()[0].Name)
+}
+
+func TestPrepareKameletsPermissions(t *testing.T) {
+       c, err := test.NewFakeClient()
+       assert.NoError(t, err)
+       err = prepareKameletsPermissions(context.TODO(), c, "camel-k")
+       assert.NoError(t, err)
+}
+
+func TestPrepareKameletsDirectory(t *testing.T) {
+       kameletDir := prepareKameletDirectory()
+       assert.Equal(t, defaultKameletDir, kameletDir)
+}
+
+func TestDownloadKameletDependencyAndExtract(t *testing.T) {
+       // use local Maven executable in tests
+       t.Setenv("MAVEN_WRAPPER", boolean.FalseString)
+       _, ok := os.LookupEnv("MAVEN_CMD")
+       if !ok {
+               t.Setenv("MAVEN_CMD", "mvn")
+       }
+
+       tmpDir, err := os.MkdirTemp("/tmp", "kamelets*")
+       assert.NoError(t, err)
+       // Load default catalog in order to get the default Camel version
+       c, err := camel.DefaultCatalog()
+       assert.NoError(t, err)
+       camelVersion := c.Runtime.Metadata["camel.version"]
+       assert.NotEqual(t, "", camelVersion)
+       err = downloadKameletDependency(context.TODO(), camelVersion, tmpDir)
+       assert.NoError(t, err)
+       downloadedDependency, err := os.Stat(path.Join(tmpDir, 
fmt.Sprintf("camel-kamelets-%s.jar", camelVersion)))
+       assert.NoError(t, err)
+
+       assert.Equal(t, fmt.Sprintf("camel-kamelets-%s.jar", camelVersion), 
downloadedDependency.Name())
+
+       // We can extract the Kamelets now
+       err = extractKameletsFromDependency(context.TODO(), camelVersion, 
tmpDir)
+       assert.NoError(t, err)
+       kameletsDir, err := os.Stat(path.Join(tmpDir, "kamelets"))
+       assert.NoError(t, err)
+       assert.True(t, kameletsDir.IsDir())
+       count := 0
+       err = filepath.WalkDir(path.Join(tmpDir, "kamelets"), func(p string, f 
fs.DirEntry, err error) error {
+               if err != nil {
+                       return err
+               }
+               if strings.HasSuffix(f.Name(), ".yaml") || 
strings.HasSuffix(f.Name(), ".yml") {
+                       count++
+               }
+               return nil
+       })
+       assert.NoError(t, err)
+       assert.True(t, count > 0)
+}
diff --git a/pkg/controller/integrationplatform/monitor.go 
b/pkg/controller/integrationplatform/monitor.go
index 474fe2934..d615525d9 100644
--- a/pkg/controller/integrationplatform/monitor.go
+++ b/pkg/controller/integrationplatform/monitor.go
@@ -24,7 +24,6 @@ import (
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        platformutil "github.com/apache/camel-k/v2/pkg/platform"
-       "github.com/apache/camel-k/v2/pkg/util/camel"
        "github.com/apache/camel-k/v2/pkg/util/defaults"
        "github.com/apache/camel-k/v2/pkg/util/openshift"
        corev1 "k8s.io/api/core/v1"
@@ -47,22 +46,37 @@ func (action *monitorAction) CanHandle(platform 
*v1.IntegrationPlatform) bool {
        return platform.Status.Phase == v1.IntegrationPlatformPhaseReady || 
platform.Status.Phase == v1.IntegrationPlatformPhaseError
 }
 
-//nolint:nestif
 func (action *monitorAction) Handle(ctx context.Context, platform 
*v1.IntegrationPlatform) (*v1.IntegrationPlatform, error) {
-       // Just track the version of the operator in the platform resource
-       if platform.Status.Version != defaults.Version {
-               platform.Status.Version = defaults.Version
-               action.L.Info("IntegrationPlatform version updated", "version", 
platform.Status.Version)
-       }
-
-       // TODO: refactor the phase transition as it is hard to reason
-       platformPhase := v1.IntegrationPlatformPhaseReady
+       runtimeVersion := specOrDefault(platform.Spec.Build.RuntimeVersion)
+       if platform.Status.Build.RuntimeVersion != runtimeVersion {
+               action.L.Infof("IntegrationPlatform version updated from %s to 
%s", platform.Status.Build.RuntimeVersion, runtimeVersion)
+               // Reset the status to reinitialize the resource
+               platform.Status = v1.IntegrationPlatformStatus{}
 
-       // Refresh applied configuration
+               return platform, nil
+       }
+       // Sync status configuration
        if err := platformutil.ConfigureDefaults(ctx, action.client, platform, 
false); err != nil {
                return nil, err
        }
+       // Get the information about Camel version in the catalog
+       runtimeSpec := v1.RuntimeSpec{
+               Version:  platform.Status.Build.RuntimeVersion,
+               Provider: platform.Status.Build.RuntimeProvider,
+       }
+       catalog, err := loadCatalog(ctx, action.client, platform.Namespace, 
runtimeSpec)
+       if catalog == nil || err != nil {
+               // error, a catalog must be available
+               platform.Status.Phase = v1.IntegrationPlatformPhaseError
+               platform.Status.SetCondition(
+                       v1.IntegrationPlatformConditionCamelCatalogAvailable,
+                       corev1.ConditionFalse,
+                       
v1.IntegrationPlatformConditionCamelCatalogAvailableReason,
+                       fmt.Sprintf("camel catalog %s not available, please 
review given runtime version", runtimeSpec.Version))
 
+               return platform, err
+       }
+       platform.Status.Build.RuntimeCoreVersion = 
catalog.Spec.GetCamelVersion()
        // Registry condition
        isOpenshift, err := openshift.IsOpenShift(action.client)
        if err != nil {
@@ -77,7 +91,7 @@ func (action *monitorAction) Handle(ctx context.Context, 
platform *v1.Integratio
        } else {
                if platform.Status.Build.Registry.Address == "" {
                        // error, we need a registry if we're not on Openshift
-                       platformPhase = v1.IntegrationPlatformPhaseError
+                       platform.Status.Phase = v1.IntegrationPlatformPhaseError
                        platform.Status.SetCondition(
                                
v1.IntegrationPlatformConditionTypeRegistryAvailable,
                                corev1.ConditionFalse,
@@ -91,41 +105,6 @@ func (action *monitorAction) Handle(ctx context.Context, 
platform *v1.Integratio
                                fmt.Sprintf("registry available at %s", 
platform.Status.Build.Registry.Address))
                }
        }
-
-       if platformPhase == v1.IntegrationPlatformPhaseReady {
-               // Camel catalog condition
-               runtimeSpec := v1.RuntimeSpec{
-                       Version:  platform.Status.Build.RuntimeVersion,
-                       Provider: v1.RuntimeProviderQuarkus,
-               }
-               if catalog, err := camel.LoadCatalog(ctx, action.client, 
platform.Namespace, runtimeSpec); err != nil {
-                       action.L.Error(err, "IntegrationPlatform unable to load 
Camel catalog",
-                               "runtime-version", runtimeSpec.Version, 
"runtime-provider", runtimeSpec.Provider)
-               } else if catalog == nil {
-                       if platform.Status.Phase != 
v1.IntegrationPlatformPhaseError {
-                               platformPhase = 
v1.IntegrationPlatformPhaseCreateCatalog
-                       } else {
-                               // IntegrationPlatform is in error phase for 
some reason - that error state must be resolved before we move into create 
catalog phase
-                               // avoids to run into endless loop of error and 
catalog creation phase ping pong
-                               platformPhase = v1.IntegrationPlatformPhaseError
-                       }
-
-                       platform.Status.SetCondition(
-                               
v1.IntegrationPlatformConditionCamelCatalogAvailable,
-                               corev1.ConditionFalse,
-                               
v1.IntegrationPlatformConditionCamelCatalogAvailableReason,
-                               fmt.Sprintf("camel catalog %s not available, 
please review given runtime version", runtimeSpec.Version))
-               } else {
-                       platform.Status.SetCondition(
-                               
v1.IntegrationPlatformConditionCamelCatalogAvailable,
-                               corev1.ConditionTrue,
-                               
v1.IntegrationPlatformConditionCamelCatalogAvailableReason,
-                               fmt.Sprintf("camel catalog %s available", 
runtimeSpec.Version))
-                       platform.Status.Build.RuntimeCoreVersion = 
catalog.Runtime.Metadata["camel.version"]
-               }
-       }
-
-       platform.Status.Phase = platformPhase
        action.checkTraitAnnotationsDeprecatedNotice(platform)
 
        return platform, nil
@@ -151,3 +130,10 @@ func (action *monitorAction) 
checkTraitAnnotationsDeprecatedNotice(platform *v1.
                }
        }
 }
+
+func specOrDefault(runtimeVersionSpec string) string {
+       if runtimeVersionSpec == "" {
+               return defaults.DefaultRuntimeVersion
+       }
+       return runtimeVersionSpec
+}
diff --git a/pkg/controller/integrationplatform/monitor_test.go 
b/pkg/controller/integrationplatform/monitor_test.go
index 875c237f8..ddbcc1bdf 100644
--- a/pkg/controller/integrationplatform/monitor_test.go
+++ b/pkg/controller/integrationplatform/monitor_test.go
@@ -23,11 +23,10 @@ import (
        "testing"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-       "github.com/apache/camel-k/v2/pkg/platform"
+       "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
        "github.com/apache/camel-k/v2/pkg/util/defaults"
        "github.com/apache/camel-k/v2/pkg/util/log"
        "github.com/apache/camel-k/v2/pkg/util/test"
-       "github.com/rs/xid"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
 
@@ -37,15 +36,8 @@ import (
 func TestCanHandlePhaseReadyOrError(t *testing.T) {
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       ip.Spec.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
-
+       ip.Name = "ck"
        ip.Status.Phase = v1.IntegrationPlatformPhaseReady
-
        c, err := test.NewFakeClient(&ip)
        require.NoError(t, err)
 
@@ -60,29 +52,31 @@ func TestCanHandlePhaseReadyOrError(t *testing.T) {
        answer = action.CanHandle(&ip)
        assert.True(t, answer)
 
-       ip.Status.Phase = v1.IntegrationPlatformPhaseCreateCatalog
+       ip.Status.Phase = v1.IntegrationPlatformPhaseCreating
        answer = action.CanHandle(&ip)
        assert.False(t, answer)
 }
 
-func TestMonitor(t *testing.T) {
+func TestMonitorReady(t *testing.T) {
+       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
"1.2.3"))
+       catalog.Spec.Runtime.Version = "1.2.3"
+       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
+       catalog.Spec.Runtime.Metadata = map[string]string{
+               "camel.version": "3.2.1",
+       }
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
defaults.DefaultRuntimeVersion))
-       catalog.Spec.Runtime.Version = defaults.DefaultRuntimeVersion
-       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
-
+       ip.Name = "ck"
+       ip.Spec.Build.Registry.Address = "1.2.3.4"
+       ip.Spec.Build.RuntimeVersion = "1.2.3"
+       ip.Spec.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+       ip.Status.Build.RuntimeVersion = "1.2.3"
+       ip.Status.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+       ip.Status.Build.Registry.Address = "1.2.3.4"
+       ip.Status.Phase = v1.IntegrationPlatformPhaseReady
        c, err := test.NewFakeClient(&ip, &catalog)
        require.NoError(t, err)
 
-       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
-       require.NoError(t, err)
-
        action := NewMonitorAction()
        action.InjectLogger(log.Log)
        action.InjectClient(c)
@@ -93,25 +87,22 @@ func TestMonitor(t *testing.T) {
 
        assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase)
        assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionTypeRegistryAvailable).Status)
-       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
+       assert.Equal(t, "3.2.1", answer.Status.Build.RuntimeCoreVersion)
 }
 
-func TestMonitorTransitionToCreateCatalog(t *testing.T) {
+func TestMonitorDriftRuntime(t *testing.T) {
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       ip.Spec.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
-
+       ip.Name = "ck"
+       ip.Spec.Build.RuntimeVersion = "3.2.1"
+       ip.Spec.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+       ip.Status.Build.RuntimeVersion = "1.2.3"
+       ip.Status.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+       ip.Status.Build.Registry.Address = "1.2.3.4"
+       ip.Status.Phase = v1.IntegrationPlatformPhaseReady
        c, err := test.NewFakeClient(&ip)
        require.NoError(t, err)
 
-       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
-       require.NoError(t, err)
-
        action := NewMonitorAction()
        action.InjectLogger(log.Log)
        action.InjectClient(c)
@@ -120,29 +111,77 @@ func TestMonitorTransitionToCreateCatalog(t *testing.T) {
        require.NoError(t, err)
        assert.NotNil(t, answer)
 
-       assert.Equal(t, v1.IntegrationPlatformPhaseCreateCatalog, 
answer.Status.Phase)
-       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionTypeRegistryAvailable).Status)
-       assert.Equal(t, corev1.ConditionFalse, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
-       assert.Equal(t, 
v1.IntegrationPlatformConditionCamelCatalogAvailableReason, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Reason)
-       assert.Equal(t, fmt.Sprintf("camel catalog %s not available, please 
review given runtime version", defaults.DefaultRuntimeVersion), 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Message)
+       assert.Equal(t, v1.IntegrationPlatformPhaseNone, answer.Status.Phase)
 }
 
-func TestMonitorRetainErrorState(t *testing.T) {
+func TestMonitorDriftDefault(t *testing.T) {
+       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
defaults.DefaultRuntimeVersion))
+       catalog.Spec.Runtime.Version = defaults.DefaultRuntimeVersion
+       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
+       catalog.Spec.Runtime.Metadata = map[string]string{
+               "camel.version": "3.2.1",
+       }
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-       ip.Spec.Build.Registry.Address = defaults.OpenShiftRegistryAddress
-
-       ip.Spec.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
+       ip.Name = "ck"
+       ip.Spec.Build.Registry.Address = "1.2.3.4"
+       ip.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
+       ip.Status.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+       ip.Status.Build.Registry.Address = "1.2.3.4"
+       ip.Status.Phase = v1.IntegrationPlatformPhaseReady
+       c, err := test.NewFakeClient(&ip, &catalog)
+       require.NoError(t, err)
 
-       ip.Status.Phase = v1.IntegrationPlatformPhaseError
+       action := NewMonitorAction()
+       action.InjectLogger(log.Log)
+       action.InjectClient(c)
 
-       c, err := test.NewFakeClient(&ip)
+       answer, err := action.Handle(context.TODO(), &ip)
        require.NoError(t, err)
+       assert.NotNil(t, answer)
+
+       assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase)
+       assert.Equal(t, "3.2.1", answer.Status.Build.RuntimeCoreVersion)
+}
 
-       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
+func TestMonitorDriftConfiguration(t *testing.T) {
+       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
defaults.DefaultRuntimeVersion))
+       catalog.Spec.Runtime.Version = defaults.DefaultRuntimeVersion
+       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
+       catalog.Spec.Runtime.Metadata = map[string]string{
+               "camel.version": "3.2.1",
+       }
+       ip := v1.IntegrationPlatform{
+               Spec: v1.IntegrationPlatformSpec{
+                       Build: v1.IntegrationPlatformBuildSpec{
+                               Registry: v1.RegistrySpec{
+                                       Address: "1.2.3.4",
+                               },
+                       },
+                       Traits: v1.Traits{
+                               Container: &trait.ContainerTrait{
+                                       Name: "override",
+                               },
+                       },
+                       Profile: v1.TraitProfileKnative,
+               },
+               Status: v1.IntegrationPlatformStatus{
+                       IntegrationPlatformSpec: v1.IntegrationPlatformSpec{
+                               Build: v1.IntegrationPlatformBuildSpec{
+                                       RuntimeVersion:     
defaults.DefaultRuntimeVersion,
+                                       RuntimeProvider:    
v1.RuntimeProviderQuarkus,
+                                       RuntimeCoreVersion: "3.2.1",
+                                       Registry: v1.RegistrySpec{
+                                               Address: "1.2.3.4",
+                                       },
+                               },
+                       },
+                       Phase: v1.IntegrationPlatformPhaseReady,
+               },
+       }
+       ip.Namespace = "ns"
+       ip.Name = "ck"
+       c, err := test.NewFakeClient(&ip, &catalog)
        require.NoError(t, err)
 
        action := NewMonitorAction()
@@ -153,30 +192,30 @@ func TestMonitorRetainErrorState(t *testing.T) {
        require.NoError(t, err)
        assert.NotNil(t, answer)
 
-       assert.Equal(t, v1.IntegrationPlatformPhaseError, answer.Status.Phase)
-       assert.Equal(t, corev1.ConditionTrue, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionTypeRegistryAvailable).Status)
-       assert.Equal(t, corev1.ConditionFalse, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
-       assert.Equal(t, 
v1.IntegrationPlatformConditionCamelCatalogAvailableReason, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Reason)
-       assert.Equal(t, fmt.Sprintf("camel catalog %s not available, please 
review given runtime version", defaults.DefaultRuntimeVersion), 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Message)
+       // It should not change the phase, however, it should change the values
+       assert.Equal(t, v1.IntegrationPlatformPhaseReady, answer.Status.Phase)
+       assert.Equal(t, defaults.Version, answer.Status.Version)
+       assert.Equal(t, defaults.DefaultRuntimeVersion, 
answer.Status.Build.RuntimeVersion)
+       assert.Equal(t, v1.RuntimeProviderQuarkus, 
answer.Status.Build.RuntimeProvider)
+       assert.Equal(t, "3.2.1", answer.Status.Build.RuntimeCoreVersion)
+       assert.Equal(t, v1.TraitProfileKnative, answer.Status.Profile)
+       assert.Equal(t, "override", answer.Status.Traits.Container.Name)
 }
 
 func TestMonitorMissingRegistryError(t *testing.T) {
+       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
"1.2.3"))
+       catalog.Spec.Runtime.Version = "1.2.3"
+       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
        ip := v1.IntegrationPlatform{}
        ip.Namespace = "ns"
-       ip.Name = xid.New().String()
-       ip.Spec.Cluster = v1.IntegrationPlatformClusterOpenShift
-       ip.Spec.Profile = v1.TraitProfileOpenShift
-
-       catalog := v1.NewCamelCatalog("ns", fmt.Sprintf("camel-catalog-%s", 
defaults.DefaultRuntimeVersion))
-       catalog.Spec.Runtime.Version = defaults.DefaultRuntimeVersion
-       catalog.Spec.Runtime.Provider = v1.RuntimeProviderQuarkus
-
+       ip.Name = "ck"
+       ip.Spec.Build.RuntimeVersion = "1.2.3"
+       ip.Spec.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+       ip.Status.Build.RuntimeVersion = "1.2.3"
+       ip.Status.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
        c, err := test.NewFakeClient(&ip, &catalog)
        require.NoError(t, err)
 
-       err = platform.ConfigureDefaults(context.TODO(), c, &ip, false)
-       require.NoError(t, err)
-
        action := NewMonitorAction()
        action.InjectLogger(log.Log)
        action.InjectClient(c)
@@ -190,3 +229,29 @@ func TestMonitorMissingRegistryError(t *testing.T) {
        assert.Equal(t, 
v1.IntegrationPlatformConditionTypeRegistryAvailableReason, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionTypeRegistryAvailable).Reason)
        assert.Equal(t, "registry address not available, you need to set one", 
answer.Status.GetCondition(v1.IntegrationPlatformConditionTypeRegistryAvailable).Message)
 }
+
+func TestMonitorMissingCatalogError(t *testing.T) {
+       ip := v1.IntegrationPlatform{}
+       ip.Namespace = "ns"
+       ip.Name = "ck"
+       ip.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
+       ip.Status.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+       c, err := test.NewFakeClient(&ip)
+       require.NoError(t, err)
+
+       action := NewMonitorAction()
+       action.InjectLogger(log.Log)
+       action.InjectClient(c)
+
+       answer, err := action.Handle(context.TODO(), &ip)
+       require.NoError(t, err)
+       assert.NotNil(t, answer)
+
+       assert.Equal(t, v1.IntegrationPlatformPhaseError, answer.Status.Phase)
+       assert.Equal(t, corev1.ConditionFalse, 
answer.Status.GetCondition(v1.IntegrationPlatformConditionCamelCatalogAvailable).Status)
+       assert.Equal(t, 
v1.IntegrationPlatformConditionCamelCatalogAvailableReason, 
answer.Status.GetCondition(
+               v1.IntegrationPlatformConditionCamelCatalogAvailable).Reason)
+       assert.Equal(t, fmt.Sprintf("camel catalog %s not available, please 
review given runtime version",
+               defaults.DefaultRuntimeVersion), answer.Status.GetCondition(
+               v1.IntegrationPlatformConditionCamelCatalogAvailable).Message)
+}
diff --git a/pkg/install/kamelets.go b/pkg/install/kamelets.go
deleted file mode 100644
index daaa7894e..000000000
--- a/pkg/install/kamelets.go
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-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 install
-
-import (
-       "context"
-       "fmt"
-       "io/fs"
-       "os"
-       "path/filepath"
-       "strings"
-
-       "golang.org/x/sync/errgroup"
-
-       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
-
-       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-
-       "github.com/apache/camel-k/v2/pkg/client"
-       "github.com/apache/camel-k/v2/pkg/util"
-       "github.com/apache/camel-k/v2/pkg/util/defaults"
-       "github.com/apache/camel-k/v2/pkg/util/kubernetes"
-       "github.com/apache/camel-k/v2/pkg/util/log"
-)
-
-const (
-       kameletDirEnv     = "KAMELET_CATALOG_DIR"
-       defaultKameletDir = "/kamelets/"
-)
-
-// KameletCatalog installs the bundled Kamelets into the specified namespace.
-func KameletCatalog(ctx context.Context, c client.Client, namespace string) 
error {
-       kameletDir := os.Getenv(kameletDirEnv)
-       if kameletDir == "" {
-               kameletDir = defaultKameletDir
-       }
-       d, err := os.Stat(kameletDir)
-       switch {
-       case err != nil && os.IsNotExist(err):
-               return nil
-       case err != nil:
-               return err
-       case !d.IsDir():
-               return fmt.Errorf("kamelet directory %q is a file", kameletDir)
-       }
-
-       g, gCtx := errgroup.WithContext(ctx)
-       applier := c.ServerOrClientSideApplier()
-
-       err = filepath.WalkDir(kameletDir, func(p string, f fs.DirEntry, err 
error) error {
-               if err != nil {
-                       return err
-               }
-               if f.IsDir() && f.Name() != d.Name() {
-                       return fs.SkipDir
-               }
-               if !(strings.HasSuffix(f.Name(), ".yaml") || 
strings.HasSuffix(f.Name(), ".yml")) {
-                       return nil
-               }
-               // We may want to throttle the creation of Go routines if the 
number of bundled Kamelets increases.
-               g.Go(func() error {
-                       kamelet, err := loadKamelet(filepath.Join(kameletDir, 
f.Name()), namespace)
-                       if err != nil {
-                               return err
-                       }
-                       err = applier.Apply(gCtx, kamelet)
-                       // We only log the error. If we returned the error, the 
creation of the ITP would have stopped
-                       if err != nil {
-                               log.Error(err, "Error occurred whilst applying 
bundled kamelet")
-                       }
-                       return nil
-               })
-               return nil
-       })
-       if err != nil {
-               return err
-       }
-
-       return g.Wait()
-}
-
-func loadKamelet(path string, namespace string) (ctrl.Object, error) {
-       content, err := util.ReadFile(path)
-       if err != nil {
-               return nil, err
-       }
-
-       kamelet, err := kubernetes.LoadUnstructuredFromYaml(string(content))
-       if err != nil {
-               return nil, err
-       }
-       gvk := kamelet.GetObjectKind().GroupVersionKind()
-       if gvk.Group != v1.SchemeGroupVersion.Group || gvk.Kind != "Kamelet" {
-               return nil, fmt.Errorf("file %q does not define a Kamelet", 
path)
-       }
-
-       kamelet.SetNamespace(namespace)
-
-       annotations := kamelet.GetAnnotations()
-       if annotations == nil {
-               annotations = make(map[string]string)
-       }
-       annotations[kamelVersionAnnotation] = defaults.Version
-       kamelet.SetAnnotations(annotations)
-
-       labels := kamelet.GetLabels()
-       if labels == nil {
-               labels = make(map[string]string)
-       }
-       labels[v1.KameletBundledLabel] = "true"
-       labels[v1.KameletReadOnlyLabel] = "true"
-
-       kamelet.SetLabels(labels)
-
-       return kamelet, nil
-}
-
-// KameletViewerRole installs the role that allows any user ro access kamelets 
in the global namespace.
-func KameletViewerRole(ctx context.Context, c client.Client, namespace string) 
error {
-       return Resource(ctx, c, namespace, true, IdentityResourceCustomizer, 
"/resources/viewer/user-global-kamelet-viewer-role-binding.yaml")
-}
diff --git a/pkg/install/kamelets_test.go b/pkg/install/kamelets_test.go
deleted file mode 100644
index 67d0cb577..000000000
--- a/pkg/install/kamelets_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-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 install
-
-import (
-       "testing"
-
-       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-       "github.com/stretchr/testify/assert"
-       "github.com/stretchr/testify/require"
-)
-
-func TestLoadKamelet(t *testing.T) {
-       kamelet, err := loadKamelet("testdata/timer-source.kamelet.yaml", 
"some-namespace")
-
-       assert.NotNil(t, kamelet)
-       require.NoError(t, err)
-       assert.Equal(t, "timer-source", kamelet.GetName())
-       assert.Equal(t, "some-namespace", kamelet.GetNamespace())
-       assert.Len(t, kamelet.GetLabels(), 3)
-       assert.Equal(t, "true", kamelet.GetLabels()[v1.KameletBundledLabel])
-       assert.Equal(t, "true", kamelet.GetLabels()[v1.KameletReadOnlyLabel])
-       assert.Len(t, kamelet.GetAnnotations(), 2)
-       assert.NotNil(t, kamelet.GetAnnotations()[kamelVersionAnnotation])
-}
diff --git a/pkg/install/optional.go b/pkg/install/optional.go
index eaa5999f7..ddef6f740 100644
--- a/pkg/install/optional.go
+++ b/pkg/install/optional.go
@@ -19,10 +19,8 @@ package install
 
 import (
        "context"
-       "strings"
 
        "github.com/apache/camel-k/v2/pkg/client"
-       "github.com/apache/camel-k/v2/pkg/util/defaults"
        logutil "github.com/apache/camel-k/v2/pkg/util/log"
 )
 
@@ -33,33 +31,4 @@ func OperatorStartupOptionalTools(ctx context.Context, c 
client.Client, namespac
                log.Info("Cannot install OpenShift CLI download link: 
skipping.")
                log.Debug("Error while installing OpenShift CLI download link", 
"error", err)
        }
-
-       // Try to install Kamelet Catalog automatically
-       var kameletNamespace string
-       globalOperator := false
-       if namespace != "" && !strings.Contains(namespace, ",") {
-               kameletNamespace = namespace
-       } else {
-               kameletNamespace = operatorNamespace
-               globalOperator = true
-       }
-
-       if kameletNamespace != "" {
-               if defaults.InstallDefaultKamelets() {
-                       if err := KameletCatalog(ctx, c, kameletNamespace); err 
!= nil {
-                               log.Info("Cannot install bundled Kamelet 
Catalog: skipping.")
-                               log.Debug("Error while installing bundled 
Kamelet Catalog", "error", err)
-                       }
-               } else {
-                       log.Info("Kamelet Catalog installation is disabled")
-               }
-
-               if globalOperator {
-                       // Make sure that Kamelets installed in operator 
namespace can be used by others
-                       if err := KameletViewerRole(ctx, c, kameletNamespace); 
err != nil {
-                               log.Info("Cannot install global Kamelet viewer 
role: skipping.")
-                               log.Debug("Error while installing global 
Kamelet viewer role", "error", err)
-                       }
-               }
-       }
 }
diff --git a/pkg/install/testdata/timer-source.kamelet.yaml 
b/pkg/install/testdata/timer-source.kamelet.yaml
deleted file mode 100644
index 3058964c2..000000000
--- a/pkg/install/testdata/timer-source.kamelet.yaml
+++ /dev/null
@@ -1,57 +0,0 @@
-# ---------------------------------------------------------------------------
-# 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.
-# ---------------------------------------------------------------------------
-
-apiVersion: camel.apache.org/v1alpha1
-kind: Kamelet
-metadata:
-  name: timer-source
-  annotations:
-    camel.apache.org/kamelet.icon: 
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gU3ZnIFZlY3RvciBJY29ucyA6IGh0dHA6Ly93d3cub25saW5ld2ViZm9udHMuY29tL2ljb24gLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm
 [...]
-  labels:
-    camel.apache.org/kamelet.type: "source"
-spec:
-  definition:
-    title: "Timer Source"
-    description: "Produces periodic events with a custom payload"
-    required:
-      - message
-    properties:
-      period:
-        title: Period
-        description: The interval between two events
-        type: integer
-        default: 1000
-      message:
-        title: Message
-        description: The message to generate
-        type: string
-        example: "hello world"
-  dataTypes:
-    out:
-      default: text
-      types:
-        text:
-          mediaType: text/plain
-  template:
-    from:
-      uri: timer:tick
-      parameters:
-        period: "{{period}}"
-      steps:
-      - setBody:
-          constant: "{{message}}"
-      - to: "kamelet:sink"
diff --git a/pkg/platform/defaults.go b/pkg/platform/defaults.go
index 3b6e89a60..66398013a 100644
--- a/pkg/platform/defaults.go
+++ b/pkg/platform/defaults.go
@@ -53,12 +53,22 @@ const (
 func ConfigureDefaults(ctx context.Context, c client.Client, p 
*v1.IntegrationPlatform, verbose bool) error {
        // Reset the state to initial values
        p.ResyncStatusFullConfig()
-
+       // Set the operator version controlling this resource
+       p.Status.Version = defaults.Version
        // Apply settings from global integration platform that is bound to 
this operator
        if err := applyGlobalPlatformDefaults(ctx, c, p); err != nil {
                return err
        }
 
+       if p.Status.Build.RuntimeProvider == "" {
+               p.Status.Build.RuntimeProvider = v1.RuntimeProviderQuarkus
+               log.Debugf("Integration Platform %s [%s]: setting default 
runtime provider %s", p.Name, p.Namespace, v1.RuntimeProviderQuarkus)
+       }
+       if p.Status.Build.RuntimeVersion == "" {
+               p.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
+               log.Debugf("Integration Platform %s [%s]: setting default 
runtime version %s", p.Name, p.Namespace, p.Status.Build.PublishStrategy)
+       }
+
        // update missing fields in the resource
        if p.Status.Cluster == "" {
                log.Debugf("Integration Platform %s [%s]: setting cluster 
status", p.Name, p.Namespace)
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index 8e861c5d3..fd764264b 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -121,6 +121,7 @@ func (t *kameletsTrait) collectKamelets(e *Environment) 
(map[string]*v1.Kamelet,
        kamelets := make(map[string]*v1.Kamelet)
        missingKamelets := make([]string, 0)
        availableKamelets := make([]string, 0)
+       bundledKamelets := make([]string, 0)
 
        for _, kml := range strings.Split(t.List, ",") {
                name := getKameletKey(kml, false)
@@ -138,6 +139,10 @@ func (t *kameletsTrait) collectKamelets(e *Environment) 
(map[string]*v1.Kamelet,
                } else {
                        availableKamelets = append(availableKamelets, name)
                }
+               if kamelet.IsBundled() {
+                       bundledKamelets = append(bundledKamelets, name)
+               }
+               // We control which version to use (if any is specified)
                clonedKamelet, err := 
kamelet.CloneWithVersion(getKameletVersion(kml))
                if err != nil {
                        return nil, err
@@ -147,13 +152,12 @@ func (t *kameletsTrait) collectKamelets(e *Environment) 
(map[string]*v1.Kamelet,
 
        sort.Strings(availableKamelets)
        sort.Strings(missingKamelets)
+       sort.Strings(bundledKamelets)
 
        if len(missingKamelets) > 0 {
-               message := fmt.Sprintf("kamelets [%s] found, kamelets [%s] not 
found in %s repositories",
-                       strings.Join(availableKamelets, ","),
+               message := fmt.Sprintf("kamelets [%s] not found in %s 
repositories",
                        strings.Join(missingKamelets, ","),
                        repo.String())
-
                e.Integration.Status.SetCondition(
                        v1.IntegrationConditionKameletsAvailable,
                        corev1.ConditionFalse,
@@ -164,6 +168,24 @@ func (t *kameletsTrait) collectKamelets(e *Environment) 
(map[string]*v1.Kamelet,
                return nil, errors.New(message)
        }
 
+       // TODO:
+       // We list the Kamelets coming from a bundle. We want to warn the user
+       // that in the future we'll use the specification coming from the 
dependency runtime
+       // instead of using the one installed in the cluster.
+       // It may be a good idea in the future to let the user specify the 
catalog dependency to use
+       // in order to override the one coming from Apache catalog
+       if len(bundledKamelets) > 0 {
+               message := fmt.Sprintf("using bundled kamelets [%s]: make sure 
the Kamelet specifications is compatible with this Integration runtime."+
+                       " This feature is deprecated as in the future we will 
use directly the specification coming from the Kamelet catalog dependency jar.",
+                       strings.Join(bundledKamelets, ","))
+               e.Integration.Status.SetCondition(
+                       
v1.IntegrationConditionType("KameletsDeprecationNotice"),
+                       corev1.ConditionTrue,
+                       "KameletsDeprecationNotice",
+                       message,
+               )
+       }
+
        e.Integration.Status.SetCondition(
                v1.IntegrationConditionKameletsAvailable,
                corev1.ConditionTrue,
diff --git a/pkg/trait/kamelets_test.go b/pkg/trait/kamelets_test.go
index 161ac3714..ac7ad9411 100644
--- a/pkg/trait/kamelets_test.go
+++ b/pkg/trait/kamelets_test.go
@@ -506,7 +506,6 @@ func TestKameletConditionFalse(t *testing.T) {
        cond := 
environment.Integration.Status.GetCondition(v1.IntegrationConditionKameletsAvailable)
        assert.Equal(t, corev1.ConditionFalse, cond.Status)
        assert.Equal(t, v1.IntegrationConditionKameletsAvailableReason, 
cond.Reason)
-       assert.Contains(t, cond.Message, "[timer] found")
        assert.Contains(t, cond.Message, "kamelets [none] not found")
 }
 
diff --git a/pkg/util/camel/camel_runtime.go b/pkg/util/camel/camel_runtime.go
index 063a30a22..753c54801 100644
--- a/pkg/util/camel/camel_runtime.go
+++ b/pkg/util/camel/camel_runtime.go
@@ -33,7 +33,8 @@ import (
 )
 
 // CreateCatalog --.
-func CreateCatalog(ctx context.Context, client client.Client, namespace 
string, platform *v1.IntegrationPlatform, runtime v1.RuntimeSpec) 
(*RuntimeCatalog, error) {
+func CreateCatalog(ctx context.Context, client client.Client, namespace 
string, platform *v1.IntegrationPlatform,
+       runtime v1.RuntimeSpec) (*RuntimeCatalog, error) {
        ctx, cancel := context.WithTimeout(ctx, 
platform.Status.Build.GetTimeout().Duration)
        defer cancel()
        catalog, err := GenerateCatalog(ctx, client, namespace, 
platform.Status.Build.Maven, runtime, []maven.Dependency{})
diff --git a/release.adoc b/release.adoc
index 6f5407a9b..a54dc6979 100644
--- a/release.adoc
+++ b/release.adoc
@@ -1,4 +1,3 @@
-
 = Releasing Apache Camel K
 
 This procedure describes all the steps required to release a new version of 
Apache Camel K.
diff --git a/script/Makefile b/script/Makefile
index 6a952deab..3f6a8b1d1 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -90,12 +90,7 @@ OPM := opm
 
 # Used to push pre-release artifacts
 STAGING_IMAGE := docker.io/camelk/camel-k
-
-# Kamelets options
 INSTALL_DEFAULT_KAMELETS ?= true
-KAMELET_CATALOG_REPO := https://github.com/apache/camel-kamelets.git
-# Make sure to use a released tag or empty if you want to get the latest 
development bits
-KAMELET_CATALOG_REPO_TAG := v4.4.1
 
 # When performing integration tests, it is not necessary to always execute 
build, especially
 # in e2e tests when lots of tests are being executed sequentially & the build 
has already taken place.
@@ -356,16 +351,6 @@ endif
 build-resources:
        ./script/get_catalog.sh $(DEFAULT_RUNTIME_VERSION)
 
-bundle-kamelets:
-       @echo "Preparing Kamelets bundle resource..."
-ifneq (,$(findstring release,$(MAKECMDGOALS)))
-ifneq (,$(findstring $(KAMELET_CATALOG_REPO_TAG), main))
-       @echo "You cannot set 
KAMELET_CATALOG_REPO_TAG=$(KAMELET_CATALOG_REPO_TAG) when doing a release"
-       @exit 1
-endif
-endif
-       ./script/bundle_kamelets.sh $(KAMELET_CATALOG_REPO) 
$(KAMELET_CATALOG_REPO_TAG)
-
 build-compile-integration-tests:
        @echo "####### Compiling integration tests..."
        export CAMEL_K_E2E_JUST_COMPILE="true"; \
@@ -445,7 +430,7 @@ endif
 
 DOCKER_TAG := $(CUSTOM_IMAGE):$(CUSTOM_VERSION)-$(IMAGE_ARCH)
 
-images: build maven-overlay bundle-kamelets image-build build-kamel-platform
+images: build maven-overlay image-build build-kamel-platform
 
 image-build:
 ifneq (,$(findstring SNAPSHOT,$(DEFAULT_RUNTIME_VERSION)))
@@ -550,7 +535,7 @@ release-kustomize:
        RELEASE_NAME=$(PACKAGE) \
        ./script/release_kustomize.sh
 
-.PHONY: do-build build build-kamel build-kamel-platform build-resources dep 
codegen images images-push images-push-staging image-build test check clean 
release cross-compile package-examples set-version git-tag check-licenses 
build-resources release-helm release-staging release-nightly get-staging-repo 
get-version bundle-kamelets
+.PHONY: do-build build build-kamel build-kamel-platform build-resources dep 
codegen images images-push images-push-staging image-build test check clean 
release cross-compile package-examples set-version git-tag check-licenses 
build-resources release-helm release-staging release-nightly get-staging-repo 
get-version
 .PHONY: controller-gen kubectl kustomize operator-sdk opm
 
 # find or download controller-gen if necessary
diff --git a/script/bundle_kamelets.sh b/script/bundle_kamelets.sh
deleted file mode 100755
index 2d94ab91e..000000000
--- a/script/bundle_kamelets.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/sh
-
-# 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.
-
-location=$(dirname $0)
-rootdir=$location/../
-
-set -e
-
-repo=$1
-tag=$2
-
-cd $rootdir
-target=./build/_kamelets
-
-# Always recreate the dir
-rm -rf $target
-mkdir $target
-
-if [ "$repo" = "" ]; then
-       echo "no kamelet catalog defined: skipping"
-       exit 0
-fi
-
-if [ "$tag" = "" ]; then
-       echo "ERROR: no kamelet catalog version defined"
-       exit 1
-fi
-
-echo "Cloning repository $repo from tag $tag to bundle kamelets..."
-
-rm -rf ./tmp_kamelet_catalog
-git clone -q -c advice.detachedHead=false -b $tag --single-branch --depth 1 
$repo ./tmp_kamelet_catalog
-
-cp ./tmp_kamelet_catalog/kamelets/*.kamelet.yaml $target
-
-rm -rf ./tmp_kamelet_catalog
-
-#
-# Check that all the kamelets have licences
-#
-./script/add_license.sh $target ./script/headers/yaml.txt


Reply via email to