Repository: apache/camel-k
Pull request #4320 (2023-05-04 01:00:57)

chore(deps): bump github.com/prometheus/client_golang from 1.15.0 to 1.15.1
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.15.0 to 1.15.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/prometheus/client_golang/releases">github.com/prometheus/client_golang's releases</a>.</em></p>
<blockquote>
<h2>v1.15.1</h2>
<h2>Changes</h2>
<ul>
<li>[BUGFIX] Fixed promhttp.Instrument* handlers wrongly trying to attach exemplar to unsupported metrics (e.g. summary), <br />
causing panics <a href="https://redirect.github.com/prometheus/client_golang/issues/1253">#1253</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/prometheus/client_golang/compare/v1.15.0...v1.15.1">https://github.com/prometheus/client_golang/compare/v1.15.0...v1.15.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md">github.com/prometheus/client_golang's changelog</a>.</em></p>
<blockquote>
<h2>Unreleased</h2>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/prometheus/client_golang/commit/4bbb297e54556fd1bcec279b355d049a50fb316e"><code>4bbb297</code></a> Cut 1.15.1 (<a href="https://redirect.github.com/prometheus/client_golang/issues/1266">#1266</a>)</li>
<li><a href="https://github.com/prometheus/client_golang/commit/2eaffbdb02d256183a31d189ca4a271dd30da462"><code>2eaffbd</code></a> Merge pull request <a href="https://redirect.github.com/prometheus/client_golang/issues/1253">#1253</a> from prometheus/fixpro</li>
<li><a href="https://github.com/prometheus/client_golang/commit/b8fdd239b2f259fef654e4890706fad162bc40e9"><code>b8fdd23</code></a> Added clarification.</li>
<li><a href="https://github.com/prometheus/client_golang/commit/2ea234eef0564aef9d949a0f2f21a1d920ce3b24"><code>2ea234e</code></a> Revert &quot;Remove unnecessary check if label is nil in observeWithExemplar (<a href="https://redirect.github.com/prometheus/client_golang/issues/1235">#1235</a>)&quot;</li>
<li>See full diff in <a href="https://github.com/prometheus/client_golang/compare/v1.15.0...v1.15.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/prometheus/client_golang&package-manager=go_modules&previous-version=1.15.0&new-version=1.15.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54813544e..a678f89f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 - Maximum number of running builds \(0\) exceeded [\#4290](https://github.com/apache/camel-k/issues/4290)
 - Should uninstall --all remove PersistentVolumeClaim? [\#4285](https://github.com/apache/camel-k/issues/4285)
 - Add statical check if integration refers to components supported by Camel K [\#4283](https://github.com/apache/camel-k/issues/4283)
+- Camel K 2.0 release process [\#4282](https://github.com/apache/camel-k/issues/4282)
 - Camel-k install and uninstall on a fresh kind cluster in Linux [\#4277](https://github.com/apache/camel-k/issues/4277)
 - Kamelet redis-source not working [\#4276](https://github.com/apache/camel-k/issues/4276)
 - Failed to fetch data from Mysql database using camel-k [\#4264](https://github.com/apache/camel-k/issues/4264)
@@ -39,12 +40,14 @@
 - Unused parameter [\#4152](https://github.com/apache/camel-k/issues/4152)
 - + [\#4151](https://github.com/apache/camel-k/issues/4151)
 - Kamel run sample integration is failing to run [\#4150](https://github.com/apache/camel-k/issues/4150)
+- Bring in startup probes to the Health trait [\#4146](https://github.com/apache/camel-k/issues/4146)
 - Bring an option to force an image build to the kamel run command [\#4126](https://github.com/apache/camel-k/issues/4126)
 - How to use JVM classpaths in Native mode? [\#4124](https://github.com/apache/camel-k/issues/4124)
 - Remove deprecated linters [\#4061](https://github.com/apache/camel-k/issues/4061)
 - Expose runtime details in `kamel version -a -v` [\#3836](https://github.com/apache/camel-k/issues/3836)
 - Remove KEP cryptic message when installing [\#3829](https://github.com/apache/camel-k/issues/3829)
 - Improve error reporting in case of knative is required but not installed [\#3803](https://github.com/apache/camel-k/issues/3803)
+- Misleading message when updating an unchanged `Integration` [\#3705](https://github.com/apache/camel-k/issues/3705)
 - Private Registry With TLS  Can Not Work [\#3672](https://github.com/apache/camel-k/issues/3672)
 - Wrong KameletBinding definition leads to operator panic [\#3586](https://github.com/apache/camel-k/issues/3586)
 - \[E2E\] Add tests for enabling traits at IntegrationPlatform [\#3476](https://github.com/apache/camel-k/issues/3476)
diff --git a/addons/strimzi/duck/client/internalclientset/fake/register.go b/addons/strimzi/duck/client/internalclientset/fake/register.go
index e6ac15499..53a4309e7 100644
--- a/addons/strimzi/duck/client/internalclientset/fake/register.go
+++ b/addons/strimzi/duck/client/internalclientset/fake/register.go
@@ -38,14 +38,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
 // AddToScheme adds all types of this clientset into the given scheme. This allows composition
 // of clientsets, like in:
 //
-//	import (
-//	  "k8s.io/client-go/kubernetes"
-//	  clientsetscheme "k8s.io/client-go/kubernetes/scheme"
-//	  aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
-//	)
+//   import (
+//     "k8s.io/client-go/kubernetes"
+//     clientsetscheme "k8s.io/client-go/kubernetes/scheme"
+//     aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
+//   )
 //
-//	kclientset, _ := kubernetes.NewForConfig(c)
-//	_ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
+//   kclientset, _ := kubernetes.NewForConfig(c)
+//   _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
 //
 // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
 // correctly.
diff --git a/addons/strimzi/duck/client/internalclientset/scheme/register.go b/addons/strimzi/duck/client/internalclientset/scheme/register.go
index 6abeca247..11f233b92 100644
--- a/addons/strimzi/duck/client/internalclientset/scheme/register.go
+++ b/addons/strimzi/duck/client/internalclientset/scheme/register.go
@@ -38,14 +38,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
 // AddToScheme adds all types of this clientset into the given scheme. This allows composition
 // of clientsets, like in:
 //
-//	import (
-//	  "k8s.io/client-go/kubernetes"
-//	  clientsetscheme "k8s.io/client-go/kubernetes/scheme"
-//	  aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
-//	)
+//   import (
+//     "k8s.io/client-go/kubernetes"
+//     clientsetscheme "k8s.io/client-go/kubernetes/scheme"
+//     aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
+//   )
 //
-//	kclientset, _ := kubernetes.NewForConfig(c)
-//	_ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
+//   kclientset, _ := kubernetes.NewForConfig(c)
+//   _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
 //
 // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
 // correctly.
diff --git a/go.mod b/go.mod
index 9a7d4d0bf..ad5848a38 100644
--- a/go.mod
+++ b/go.mod
@@ -27,7 +27,7 @@ require (
 	github.com/otiai10/copy v1.9.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.60.0
-	github.com/prometheus/client_golang v1.15.0
+	github.com/prometheus/client_golang v1.15.1
 	github.com/prometheus/client_model v0.4.0
 	github.com/prometheus/common v0.42.0
 	github.com/radovskyb/watcher v1.0.7
diff --git a/go.sum b/go.sum
index f52acf5a7..35c0c14e9 100644
--- a/go.sum
+++ b/go.sum
@@ -1030,8 +1030,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
 github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
-github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
+github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
diff --git a/pkg/client/camel/clientset/versioned/fake/register.go b/pkg/client/camel/clientset/versioned/fake/register.go
index d55e6d595..249a2b9e3 100644
--- a/pkg/client/camel/clientset/versioned/fake/register.go
+++ b/pkg/client/camel/clientset/versioned/fake/register.go
@@ -40,14 +40,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
 // AddToScheme adds all types of this clientset into the given scheme. This allows composition
 // of clientsets, like in:
 //
-//	import (
-//	  "k8s.io/client-go/kubernetes"
-//	  clientsetscheme "k8s.io/client-go/kubernetes/scheme"
-//	  aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
-//	)
+//   import (
+//     "k8s.io/client-go/kubernetes"
+//     clientsetscheme "k8s.io/client-go/kubernetes/scheme"
+//     aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
+//   )
 //
-//	kclientset, _ := kubernetes.NewForConfig(c)
-//	_ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
+//   kclientset, _ := kubernetes.NewForConfig(c)
+//   _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
 //
 // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
 // correctly.
diff --git a/pkg/client/camel/clientset/versioned/scheme/register.go b/pkg/client/camel/clientset/versioned/scheme/register.go
index 493d56e4c..9366fb20c 100644
--- a/pkg/client/camel/clientset/versioned/scheme/register.go
+++ b/pkg/client/camel/clientset/versioned/scheme/register.go
@@ -40,14 +40,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
 // AddToScheme adds all types of this clientset into the given scheme. This allows composition
 // of clientsets, like in:
 //
-//	import (
-//	  "k8s.io/client-go/kubernetes"
-//	  clientsetscheme "k8s.io/client-go/kubernetes/scheme"
-//	  aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
-//	)
+//   import (
+//     "k8s.io/client-go/kubernetes"
+//     clientsetscheme "k8s.io/client-go/kubernetes/scheme"
+//     aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
+//   )
 //
-//	kclientset, _ := kubernetes.NewForConfig(c)
-//	_ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
+//   kclientset, _ := kubernetes.NewForConfig(c)
+//   _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
 //
 // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
 // correctly.
diff --git a/pkg/platform/defaults.go b/pkg/platform/defaults.go
index 4f7da9f57..8dbf8a29d 100644
--- a/pkg/platform/defaults.go
+++ b/pkg/platform/defaults.go
@@ -53,9 +53,14 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *v1.IntegrationPl
 	// Reset the state to initial values
 	p.ResyncStatusFullConfig()
 
+	// Apply settings from global integration platform that is bound to this operator
+	if err := applyGlobalPlatformDefaults(ctx, c, p); err != nil {
+		return err
+	}
+
 	// update missing fields in the resource
 	if p.Status.Cluster == "" {
-		log.Debugf("Integration Platform [%s]: setting cluster status", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting cluster status", p.Name, p.Namespace)
 		// determine the kind of cluster the platform is installed into
 		isOpenShift, err := openshift.IsOpenShift(c)
 		switch {
@@ -74,12 +79,12 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *v1.IntegrationPl
 		} else {
 			p.Status.Build.PublishStrategy = v1.IntegrationPlatformBuildPublishStrategySpectrum
 		}
-		log.Debugf("Integration Platform [%s]: setting publishing strategy %s", p.Namespace, p.Status.Build.PublishStrategy)
+		log.Debugf("Integration Platform %s [%s]: setting publishing strategy %s", p.Name, p.Namespace, p.Status.Build.PublishStrategy)
 	}
 
 	if p.Status.Build.BuildStrategy == "" {
 		p.Status.Build.BuildStrategy = v1.BuildStrategyPod
-		log.Debugf("Integration Platform [%s]: setting build strategy %s", p.Namespace, p.Status.Build.BuildStrategy)
+		log.Debugf("Integration Platform %s [%s]: setting build strategy %s", p.Name, p.Namespace, p.Status.Build.BuildStrategy)
 	}
 
 	err := setPlatformDefaults(p, verbose)
@@ -110,7 +115,7 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *v1.IntegrationPl
 }
 
 func CreateBuilderServiceAccount(ctx context.Context, client client.Client, p *v1.IntegrationPlatform) error {
-	log.Debugf("Integration Platform [%s]: creating build service account", p.Namespace)
+	log.Debugf("Integration Platform %s [%s]: creating build service account", p.Name, p.Namespace)
 	sa := corev1.ServiceAccount{}
 	key := ctrl.ObjectKey{
 		Name:      BuilderServiceAccount,
@@ -129,7 +134,7 @@ func configureRegistry(ctx context.Context, c client.Client, p *v1.IntegrationPl
 	if p.Status.Cluster == v1.IntegrationPlatformClusterOpenShift &&
 		p.Status.Build.PublishStrategy != v1.IntegrationPlatformBuildPublishStrategyS2I &&
 		p.Status.Build.Registry.Address == "" {
-		log.Debugf("Integration Platform [%s]: setting registry address", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting registry address", p.Name, p.Namespace)
 		// Default to using OpenShift internal container images registry when using a strategy other than S2I
 		p.Status.Build.Registry.Address = "image-registry.openshift-image-registry.svc:5000"
 
@@ -138,12 +143,12 @@ func configureRegistry(ctx context.Context, c client.Client, p *v1.IntegrationPl
 		if err != nil {
 			return err
 		}
-		log.Debugf("Integration Platform [%s]: setting registry certificate authority", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting registry certificate authority", p.Name, p.Namespace)
 		p.Status.Build.Registry.CA = cm.Name
 
 		// Default to using the registry secret that's configured for the builder service account
 		if p.Status.Build.Registry.Secret == "" {
-			log.Debugf("Integration Platform [%s]: setting registry secret", p.Namespace)
+			log.Debugf("Integration Platform %s [%s]: setting registry secret", p.Name, p.Namespace)
 			// Bind the required role to push images to the registry
 			err := createBuilderRegistryRoleBinding(ctx, c, p)
 			if err != nil {
@@ -179,25 +184,142 @@ func configureRegistry(ctx context.Context, c client.Client, p *v1.IntegrationPl
 	return nil
 }
 
+func applyGlobalPlatformDefaults(ctx context.Context, c client.Client, p *v1.IntegrationPlatform) error {
+	operatorNamespace := GetOperatorNamespace()
+	if operatorNamespace != "" && operatorNamespace != p.Namespace {
+		operatorID := defaults.OperatorID()
+		if operatorID != "" {
+			if globalPlatform, err := get(ctx, c, operatorNamespace, operatorID); err != nil && !k8serrors.IsNotFound(err) {
+				return err
+			} else if globalPlatform != nil {
+				applyPlatformSpec(globalPlatform, p)
+				return nil
+			}
+		}
+
+		if globalPlatform, err := findLocal(ctx, c, operatorNamespace, true); err != nil && !k8serrors.IsNotFound(err) {
+			return err
+		} else if globalPlatform != nil {
+			applyPlatformSpec(globalPlatform, p)
+		}
+	}
+
+	return nil
+}
+
+func applyPlatformSpec(source *v1.IntegrationPlatform, target *v1.IntegrationPlatform) {
+	if target.Status.Cluster == "" {
+		target.Status.Cluster = source.Status.Cluster
+	}
+	if target.Status.Profile == "" {
+		log.Debugf("Integration Platform %s [%s]: setting profile", target.Name, target.Namespace)
+		target.Status.Profile = source.Status.Profile
+	}
+
+	if target.Status.Build.PublishStrategy == "" {
+		target.Status.Build.PublishStrategy = source.Status.Build.PublishStrategy
+	}
+	if target.Status.Build.PublishStrategyOptions == nil {
+		log.Debugf("Integration Platform %s [%s]: setting publish strategy options", target.Name, target.Namespace)
+		target.Status.Build.PublishStrategyOptions = source.Status.Build.PublishStrategyOptions
+	}
+	if target.Status.Build.BuildStrategy == "" {
+		target.Status.Build.BuildStrategy = source.Status.Build.BuildStrategy
+	}
+
+	if target.Status.Build.RuntimeVersion == "" {
+		log.Debugf("Integration Platform %s [%s]: setting runtime version", target.Name, target.Namespace)
+		target.Status.Build.RuntimeVersion = source.Status.Build.RuntimeVersion
+	}
+	if target.Status.Build.BaseImage == "" {
+		log.Debugf("Integration Platform %s [%s]: setting base image", target.Name, target.Namespace)
+		target.Status.Build.BaseImage = source.Status.Build.BaseImage
+	}
+
+	if target.Status.Build.Maven.LocalRepository == "" {
+		log.Debugf("Integration Platform %s [%s]: setting local repository", target.Name, target.Namespace)
+		target.Status.Build.Maven.LocalRepository = source.Status.Build.Maven.LocalRepository
+	}
+
+	if len(source.Status.Build.Maven.CLIOptions) > 0 && len(target.Status.Build.Maven.CLIOptions) == 0 {
+		log.Debugf("Integration Platform %s [%s]: setting CLI options", target.Name, target.Namespace)
+		target.Status.Build.Maven.CLIOptions = make([]string, len(source.Status.Build.Maven.CLIOptions))
+		copy(target.Status.Build.Maven.CLIOptions, source.Status.Build.Maven.CLIOptions)
+	}
+
+	if len(source.Status.Build.Maven.Properties) > 0 {
+		log.Debugf("Integration Platform %s [%s]: setting Maven properties", target.Name, target.Namespace)
+		if len(target.Status.Build.Maven.Properties) == 0 {
+			target.Status.Build.Maven.Properties = make(map[string]string, len(source.Status.Build.Maven.Properties))
+		}
+
+		for key, val := range source.Status.Build.Maven.Properties {
+			// only set unknown properties on target
+			if _, ok := target.Status.Build.Maven.Properties[key]; !ok {
+				target.Status.Build.Maven.Properties[key] = val
+			}
+		}
+	}
+
+	if len(source.Status.Build.Maven.Extension) > 0 && len(target.Status.Build.Maven.Extension) == 0 {
+		log.Debugf("Integration Platform %s [%s]: setting Maven extensions", target.Name, target.Namespace)
+		target.Status.Build.Maven.Extension = make([]v1.MavenArtifact, len(source.Status.Build.Maven.Extension))
+		copy(target.Status.Build.Maven.Extension, source.Status.Build.Maven.Extension)
+	}
+
+	if target.Status.Build.Registry.Address == "" && source.Status.Build.Registry.Address != "" {
+		log.Debugf("Integration Platform %s [%s]: setting registry", target.Name, target.Namespace)
+		source.Status.Build.Registry.DeepCopyInto(&target.Status.Build.Registry)
+	}
+
+	if err := target.Status.Traits.Merge(source.Status.Traits); err != nil {
+		log.Errorf(err, "Integration Platform %s [%s]: failed to merge traits", target.Name, target.Namespace)
+	} else if err := target.Status.Traits.Merge(target.Spec.Traits); err != nil {
+		log.Errorf(err, "Integration Platform %s [%s]: failed to merge traits", target.Name, target.Namespace)
+	}
+
+	// Build timeout
+	if target.Status.Build.Timeout == nil {
+		log.Debugf("Integration Platform %s [%s]: setting build timeout", target.Name, target.Namespace)
+		target.Status.Build.Timeout = source.Status.Build.Timeout
+	}
+
+	// Catalog tools build timeout
+	if target.Status.Build.BuildCatalogToolTimeout == nil {
+		log.Debugf("Integration Platform %s [%s]: setting build camel catalog tool timeout", target.Name, target.Namespace)
+		target.Status.Build.BuildCatalogToolTimeout = source.Status.Build.BuildCatalogToolTimeout
+	}
+
+	if target.Status.Build.MaxRunningBuilds <= 0 {
+		log.Debugf("Integration Platform %s [%s]: setting max running builds", target.Name, target.Namespace)
+		target.Status.Build.MaxRunningBuilds = source.Status.Build.MaxRunningBuilds
+	}
+
+	if len(target.Status.Kamelet.Repositories) == 0 {
+		log.Debugf("Integration Platform %s [%s]: setting kamelet repositories", target.Name, target.Namespace)
+		target.Status.Kamelet.Repositories = source.Status.Kamelet.Repositories
+	}
+}
+
 func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 	if p.Status.Build.PublishStrategyOptions == nil {
-		log.Debugf("Integration Platform [%s]: setting publish strategy options", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting publish strategy options", p.Name, p.Namespace)
 		p.Status.Build.PublishStrategyOptions = map[string]string{}
 	}
 	if p.Status.Build.RuntimeVersion == "" {
-		log.Debugf("Integration Platform [%s]: setting runtime version", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting runtime version", p.Name, p.Namespace)
 		p.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
 	}
 	if p.Status.Build.BaseImage == "" {
-		log.Debugf("Integration Platform [%s]: setting base image", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting base image", p.Name, p.Namespace)
 		p.Status.Build.BaseImage = defaults.BaseImage()
 	}
 	if p.Status.Build.Maven.LocalRepository == "" {
-		log.Debugf("Integration Platform [%s]: setting local repository", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting local repository", p.Name, p.Namespace)
 		p.Status.Build.Maven.LocalRepository = defaults.LocalRepository
 	}
 	if len(p.Status.Build.Maven.CLIOptions) == 0 {
-		log.Debugf("Integration Platform [%s]: setting CLI options", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting CLI options", p.Name, p.Namespace)
 		p.Status.Build.Maven.CLIOptions = []string{
 			"-V",
 			"--no-transfer-progress",
@@ -205,7 +327,7 @@ func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 		}
 	}
 	if _, ok := p.Status.Build.PublishStrategyOptions[builder.KanikoPVCName]; !ok {
-		log.Debugf("Integration Platform [%s]: setting publish strategy options", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting publish strategy options", p.Name, p.Namespace)
 		p.Status.Build.PublishStrategyOptions[builder.KanikoPVCName] = p.Name
 	}
 
@@ -221,7 +343,7 @@ func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 			log.Log.Infof("Build timeout minimum unit is sec (configured: %s, truncated: %s)", p.Status.Build.GetTimeout().Duration, d)
 		}
 
-		log.Debugf("Integration Platform [%s]: setting build timeout", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting build timeout", p.Name, p.Namespace)
 		p.Status.Build.Timeout = &metav1.Duration{
 			Duration: d,
 		}
@@ -229,7 +351,7 @@ func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 
 	// Catalog tools build timeout
 	if p.Status.Build.GetBuildCatalogToolTimeout().Duration == 0 {
-		log.Debugf("Integration Platform [%s]: setting default build camel catalog tool timeout (1 minute)", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting default build camel catalog tool timeout (1 minute)", p.Name, p.Namespace)
 		p.Status.Build.BuildCatalogToolTimeout = &metav1.Duration{
 			Duration: 1 * time.Minute,
 		}
@@ -240,13 +362,14 @@ func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 			log.Log.Infof("Build catalog tools timeout minimum unit is sec (configured: %s, truncated: %s)", p.Status.Build.GetBuildCatalogToolTimeout().Duration, d)
 		}
 
-		log.Debugf("Integration Platform [%s]: setting build catalog tools timeout", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting build catalog tools timeout", p.Name, p.Namespace)
 		p.Status.Build.BuildCatalogToolTimeout = &metav1.Duration{
 			Duration: d,
 		}
 	}
 
 	if p.Status.Build.MaxRunningBuilds <= 0 {
+		log.Debugf("Integration Platform %s [%s]: setting max running builds", p.Name, p.Namespace)
 		if p.Status.Build.BuildStrategy == v1.BuildStrategyRoutine {
 			p.Status.Build.MaxRunningBuilds = 3
 		} else if p.Status.Build.BuildStrategy == v1.BuildStrategyPod {
@@ -267,7 +390,7 @@ func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 	}
 
 	if len(p.Status.Kamelet.Repositories) == 0 {
-		log.Debugf("Integration Platform [%s]: setting kamelet repositories", p.Namespace)
+		log.Debugf("Integration Platform %s [%s]: setting kamelet repositories", p.Name, p.Namespace)
 		p.Status.Kamelet.Repositories = append(p.Status.Kamelet.Repositories, v1.IntegrationPlatformKameletRepositorySpec{
 			URI: repository.DefaultRemoteRepository,
 		})
@@ -287,13 +410,13 @@ func setPlatformDefaults(p *v1.IntegrationPlatform, verbose bool) error {
 func setStatusAdditionalInfo(platform *v1.IntegrationPlatform) {
 	platform.Status.Info = make(map[string]string)
 
-	log.Debugf("Integration Platform [%s]: setting build publish strategy", platform.Namespace)
+	log.Debugf("Integration Platform %s [%s]: setting build publish strategy", platform.Name, platform.Namespace)
 	if platform.Spec.Build.PublishStrategy == v1.IntegrationPlatformBuildPublishStrategyBuildah {
 		platform.Status.Info["buildahVersion"] = defaults.BuildahVersion
 	} else if platform.Spec.Build.PublishStrategy == v1.IntegrationPlatformBuildPublishStrategyKaniko {
 		platform.Status.Info["kanikoVersion"] = defaults.KanikoVersion
 	}
-	log.Debugf("Integration Platform [%s]: setting status info", platform.Namespace)
+	log.Debugf("Integration Platform %s [%s]: setting status info", platform.Name, platform.Namespace)
 	platform.Status.Info["goVersion"] = runtime.Version()
 	platform.Status.Info["goOS"] = runtime.GOOS
 	platform.Status.Info["gitCommit"] = defaults.GitCommit
diff --git a/pkg/util/defaults/defaults.go b/pkg/util/defaults/defaults.go
index c20ed0e4f..08f99b1fa 100644
--- a/pkg/util/defaults/defaults.go
+++ b/pkg/util/defaults/defaults.go
@@ -26,7 +26,7 @@ const (
 	Version = "2.0.0-SNAPSHOT"
 
 	// DefaultRuntimeVersion --
-	DefaultRuntimeVersion = "3.20.1-SNAPSHOT"
+	DefaultRuntimeVersion = "2.16.0-SNAPSHOT"
 
 	// BuildahVersion --
 	BuildahVersion = "1.23.3"


Test patch:
diff --git a/e2e/commonwithcustominstall/local_platform_test.go b/e2e/commonwithcustominstall/local_platform_test.go
new file mode 100644
index 000000000..98f99924c
--- /dev/null
+++ b/e2e/commonwithcustominstall/local_platform_test.go
@@ -0,0 +1,103 @@
+//go:build integration
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+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 commonwithcustominstall
+
+import (
+	"testing"
+
+	. "github.com/onsi/gomega"
+	corev1 "k8s.io/api/core/v1"
+
+	. "github.com/apache/camel-k/v2/e2e/support"
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+)
+
+func TestLocalPlatform(t *testing.T) {
+	WithNewTestNamespace(t, func(ns string) {
+		operatorID := "camel-k-platform-local"
+		Expect(KamelInstallWithID(operatorID, ns, "--global", "--force").Execute()).To(Succeed())
+		Eventually(PlatformPhase(ns), TestTimeoutMedium).Should(Equal(v1.IntegrationPlatformPhaseReady))
+
+		pl := Platform(ns)()
+		pl.Spec.Build.Maven.Properties = make(map[string]string)
+		pl.Spec.Build.Maven.Properties["build-global-prop1"] = "build-global-value1"
+		// set maximum number of running builds
+		pl.Spec.Build.MaxRunningBuilds = 1
+		if err := TestClient().Update(TestContext, pl); err != nil {
+			t.Error(err)
+			t.FailNow()
+		}
+
+		Eventually(PlatformHas(ns, func(pl *v1.IntegrationPlatform) bool {
+			return pl.Status.Build.MaxRunningBuilds == 1
+		}), TestTimeoutMedium).Should(BeTrue())
+
+		WithNewTestNamespace(t, func(ns1 string) {
+			localPlatform := v1.NewIntegrationPlatform(ns1, operatorID)
+			localPlatform.Spec.Build.Maven.Properties = make(map[string]string)
+			localPlatform.Spec.Build.Maven.Properties["build-local-prop1"] = "build-local-value1"
+			localPlatform.SetOperatorID(operatorID)
+
+			localPlatform.Spec.Traits.Container = &traitv1.ContainerTrait{
+				LimitCPU: "0.1",
+			}
+
+			if err := TestClient().Create(TestContext, &localPlatform); err != nil {
+				t.Error(err)
+				t.FailNow()
+			}
+			Eventually(PlatformPhase(ns1), TestTimeoutMedium).Should(Equal(v1.IntegrationPlatformPhaseReady))
+			Eventually(PlatformHas(ns1, func(pl *v1.IntegrationPlatform) bool {
+				return pl.Status.Cluster != ""
+			}), TestTimeoutShort).Should(BeTrue())
+
+			Eventually(PlatformHas(ns1, func(pl *v1.IntegrationPlatform) bool {
+				return pl.Status.Build.MaxRunningBuilds == 1
+			}), TestTimeoutShort).Should(BeTrue())
+
+			local := Platform(ns1)()
+			Expect(local.Status.Build.PublishStrategy).To(Equal(pl.Status.Build.PublishStrategy))
+			Expect(local.Status.Build.BuildStrategy).To(Equal(pl.Status.Build.BuildStrategy))
+			Expect(local.Status.Build.Maven.LocalRepository).To(Equal(pl.Status.Build.Maven.LocalRepository))
+			Expect(local.Status.Build.Maven.CLIOptions).To(ContainElements(pl.Status.Build.Maven.CLIOptions))
+			Expect(local.Status.Build.Maven.Extension).To(BeEmpty())
+			Expect(local.Status.Build.Maven.Properties).To(HaveLen(2))
+			Expect(local.Status.Build.Maven.Properties["build-global-prop1"]).To(Equal("build-global-value1"))
+			Expect(local.Status.Build.Maven.Properties["build-local-prop1"]).To(Equal("build-local-value1"))
+
+			Expect(KamelRunWithID(operatorID, ns1, "--name", "local-integration", "files/yaml.yaml").Execute()).To(Succeed())
+			Eventually(IntegrationPod(ns1, "local-integration"), TestTimeoutMedium).Should(Not(BeNil()))
+			Eventually(IntegrationPodHas(ns1, "local-integration", func(pod *corev1.Pod) bool {
+				if len(pod.Spec.Containers) != 1 {
+					return false
+				}
+				cpuLimits := pod.Spec.Containers[0].Resources.Limits.Cpu()
+				return cpuLimits != nil && cpuLimits.AsApproximateFloat64() > 0
+			}), TestTimeoutShort).Should(BeTrue())
+
+			// Clean up
+			Expect(Kamel("delete", "--all", "-n", ns1).Execute()).To(Succeed())
+		})
+	})
+}
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index 5cd425710..c70725ff0 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -1799,6 +1799,16 @@ func SelectedPlatformPhase(ns string, name string) func() v1.IntegrationPlatform
 	}
 }
 
+func PlatformHas(ns string, predicate func(pl *v1.IntegrationPlatform) bool) func() bool {
+	return func() bool {
+		pl := Platform(ns)()
+		if pl == nil {
+			return false
+		}
+		return predicate(pl)
+	}
+}
+
 func PlatformCondition(
 	ns string,
 	conditionType v1.IntegrationPlatformConditionType,
diff --git a/pkg/platform/defaults_test.go b/pkg/platform/defaults_test.go
new file mode 100644
index 000000000..d5754ba1c
--- /dev/null
+++ b/pkg/platform/defaults_test.go
@@ -0,0 +1,187 @@
+/*
+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 platform
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+	"github.com/apache/camel-k/v2/pkg/util/test"
+)
+
+func TestApplyGlobalPlatformSpec(t *testing.T) {
+	global := v1.IntegrationPlatform{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      DefaultPlatformName,
+			Namespace: "ns",
+		},
+		Spec: v1.IntegrationPlatformSpec{
+			Build: v1.IntegrationPlatformBuildSpec{
+				BuildStrategy: v1.BuildStrategyRoutine,
+				Maven: v1.MavenSpec{
+					Properties: map[string]string{
+						"global_prop1": "global_value1",
+						"global_prop2": "global_value2",
+					},
+				},
+			},
+			Traits: v1.Traits{
+				Logging: &trait.LoggingTrait{
+					Level: "DEBUG",
+				},
+				Container: &trait.ContainerTrait{
+					ImagePullPolicy: corev1.PullAlways,
+					LimitCPU:        "0.1",
+				},
+			},
+			Cluster: v1.IntegrationPlatformClusterOpenShift,
+			Profile: v1.TraitProfileOpenShift,
+		},
+	}
+
+	c, err := test.NewFakeClient(&global)
+	assert.Nil(t, err)
+
+	err = ConfigureDefaults(context.TODO(), c, &global, false)
+	assert.Nil(t, err)
+
+	ip := v1.IntegrationPlatform{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "local-camel-k",
+			Namespace: "ns",
+		},
+	}
+
+	ip.ResyncStatusFullConfig()
+
+	applyPlatformSpec(&global, &ip)
+
+	assert.Equal(t, v1.IntegrationPlatformClusterOpenShift, ip.Status.Cluster)
+	assert.Equal(t, v1.TraitProfileOpenShift, ip.Status.Profile)
+	assert.Equal(t, v1.BuildStrategyRoutine, ip.Status.Build.BuildStrategy)
+
+	assert.True(t, ip.Status.Build.MaxRunningBuilds == 3) // default for build strategy routine
+
+	assert.Equal(t, len(global.Status.Build.Maven.CLIOptions), len(ip.Status.Build.Maven.CLIOptions))
+	assert.Equal(t, global.Status.Build.Maven.CLIOptions, ip.Status.Build.Maven.CLIOptions)
+
+	assert.NotNil(t, ip.Status.Traits)
+	assert.NotNil(t, ip.Status.Traits.Logging)
+	assert.Equal(t, "DEBUG", ip.Status.Traits.Logging.Level)
+	assert.NotNil(t, ip.Status.Traits.Container)
+	assert.Equal(t, corev1.PullAlways, ip.Status.Traits.Container.ImagePullPolicy)
+	assert.Equal(t, "0.1", ip.Status.Traits.Container.LimitCPU)
+
+	assert.Equal(t, 2, len(ip.Status.Build.Maven.Properties))
+	assert.Equal(t, "global_value1", ip.Status.Build.Maven.Properties["global_prop1"])
+	assert.Equal(t, "global_value2", ip.Status.Build.Maven.Properties["global_prop2"])
+}
+
+func TestRetainLocalPlatformSpec(t *testing.T) {
+	global := v1.IntegrationPlatform{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      DefaultPlatformName,
+			Namespace: "ns",
+		},
+		Spec: v1.IntegrationPlatformSpec{
+			Build: v1.IntegrationPlatformBuildSpec{
+				BuildStrategy: v1.BuildStrategyRoutine,
+				Maven: v1.MavenSpec{
+					Properties: map[string]string{
+						"global_prop1": "global_value1",
+						"global_prop2": "global_value2",
+					},
+				},
+			},
+			Traits: v1.Traits{
+				Logging: &trait.LoggingTrait{
+					Level: "DEBUG",
+				},
+				Container: &trait.ContainerTrait{
+					ImagePullPolicy: corev1.PullIfNotPresent,
+					LimitCPU:        "0.1",
+				},
+			},
+			Cluster: v1.IntegrationPlatformClusterOpenShift,
+			Profile: v1.TraitProfileOpenShift,
+		},
+	}
+
+	c, err := test.NewFakeClient(&global)
+	assert.Nil(t, err)
+
+	err = ConfigureDefaults(context.TODO(), c, &global, false)
+	assert.Nil(t, err)
+
+	ip := v1.IntegrationPlatform{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "local-camel-k",
+			Namespace: "ns",
+		},
+		Spec: v1.IntegrationPlatformSpec{
+			Build: v1.IntegrationPlatformBuildSpec{
+				BuildStrategy:    v1.BuildStrategyPod,
+				MaxRunningBuilds: 1,
+				Maven: v1.MavenSpec{
+					Properties: map[string]string{
+						"local_prop1":  "local_value1",
+						"global_prop2": "local_value2",
+					},
+				},
+			},
+			Traits: v1.Traits{
+				Container: &trait.ContainerTrait{
+					ImagePullPolicy: corev1.PullAlways,
+				},
+			},
+			Cluster: v1.IntegrationPlatformClusterKubernetes,
+			Profile: v1.TraitProfileKnative,
+		},
+	}
+
+	ip.ResyncStatusFullConfig()
+
+	applyPlatformSpec(&global, &ip)
+
+	assert.Equal(t, v1.IntegrationPlatformClusterKubernetes, ip.Status.Cluster)
+	assert.Equal(t, v1.TraitProfileKnative, ip.Status.Profile)
+	assert.Equal(t, v1.BuildStrategyPod, ip.Status.Build.BuildStrategy)
+
+	assert.True(t, ip.Status.Build.MaxRunningBuilds == 1)
+
+	assert.Equal(t, len(global.Status.Build.Maven.CLIOptions), len(ip.Status.Build.Maven.CLIOptions))
+	assert.Equal(t, global.Status.Build.Maven.CLIOptions, ip.Status.Build.Maven.CLIOptions)
+
+	assert.NotNil(t, ip.Status.Traits)
+	assert.NotNil(t, ip.Status.Traits.Logging)
+	assert.Equal(t, "DEBUG", ip.Status.Traits.Logging.Level)
+	assert.NotNil(t, ip.Status.Traits.Container)
+	assert.Equal(t, corev1.PullAlways, ip.Status.Traits.Container.ImagePullPolicy)
+	assert.Equal(t, "0.1", ip.Status.Traits.Container.LimitCPU)
+
+	assert.Equal(t, 3, len(ip.Status.Build.Maven.Properties))
+	assert.Equal(t, "global_value1", ip.Status.Build.Maven.Properties["global_prop1"])
+	assert.Equal(t, "local_value2", ip.Status.Build.Maven.Properties["global_prop2"])
+	assert.Equal(t, "local_value1", ip.Status.Build.Maven.Properties["local_prop1"])
+}