You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pc...@apache.org on 2026/06/20 10:26:19 UTC
(camel-k) 01/02: feat(install): multi namespace watching
This is an automated email from the ASF dual-hosted git repository.
squakez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 38aa87044f68b16c07d44664dd52e3b4075fc316
Author: Pasquale Congiusti <pa...@gmail.com>
AuthorDate: Sat Jun 13 09:15:06 2026 +0200
feat(install): multi namespace watching
* Enable the possibility to watch another namespace, beside the own namespace
* Enable the possibility to watch multiple namespaces
* Deprecate operator.id annotation
* Change install names to clarify each overlay intent
Ref #6616
---
docs/modules/ROOT/pages/pipes/bind-cli.adoc | 2 -
docs/modules/ROOT/pages/running/running-cli.adoc | 2 -
e2e/advanced/operator_id_filtering_test.go | 2 +-
e2e/common/misc/pipe_test.go | 47 -------
.../{setup_test.go => all_namespaces_test.go} | 64 ---------
e2e/install/kustomize/own_namespace_test.go | 83 ++++++++++++
e2e/install/kustomize/single_namespace_test.go | 87 ++++++++++++
e2e/support/test_support.go | 13 +-
.../kustomization.yaml | 0
.../patch-log-level.yaml | 0
.../patch-node-selector.yaml | 0
.../patch-operator-id.yaml | 0
.../{namespaced => own-namespace}/patch-ports.yaml | 0
.../patch-resource-requirements.yaml | 0
.../patch-toleration.yaml | 0
.../kustomization.yaml} | 8 +-
.../single-namespace/operator}/kustomization.yaml | 14 +-
.../operator/patch-envvars.yaml} | 19 +--
.../operator/remove-watch-ns.yaml} | 5 +-
.../tenant-a-ns-rbac}/kustomization.yaml | 15 +--
.../patch-rolebinding-subjects.yaml} | 9 +-
pkg/apis/camel/v1/common_types.go | 2 +
pkg/cmd/bind.go | 24 ++--
pkg/cmd/bind_test.go | 18 +--
pkg/cmd/operator/operator.go | 54 ++++----
pkg/cmd/operator/operator_test.go | 150 +++++++++++++++++++++
pkg/cmd/promote_test.go | 12 +-
pkg/cmd/run.go | 10 +-
pkg/cmd/run_test.go | 14 --
pkg/controller/integration/build.go | 1 +
.../integration/integration_controller.go | 9 +-
pkg/controller/integrationkit/build.go | 1 +
.../integrationkit/integrationkit_controller.go | 1 +
pkg/install/common.go | 50 -------
pkg/install/optional.go | 2 +-
pkg/platform/defaults.go | 13 +-
pkg/platform/operator.go | 15 +--
pkg/resources/config/manager/kustomization.yaml | 10 ++
.../config/manager/operator-deployment.yaml | 6 +
pkg/util/gitops/gitops.go | 4 +
script/Makefile | 2 +-
41 files changed, 460 insertions(+), 308 deletions(-)
diff --git a/docs/modules/ROOT/pages/pipes/bind-cli.adoc b/docs/modules/ROOT/pages/pipes/bind-cli.adoc
index 5133b22a6..fd48effbe 100644
--- a/docs/modules/ROOT/pages/pipes/bind-cli.adoc
+++ b/docs/modules/ROOT/pages/pipes/bind-cli.adoc
@@ -65,8 +65,6 @@ As an example, take the option available on the `kamel bind timer-source log-sin
apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: timer-source-to-log-sink
namespace: camel-k
spec:
diff --git a/docs/modules/ROOT/pages/running/running-cli.adoc b/docs/modules/ROOT/pages/running/running-cli.adoc
index 67c8d14d9..d4d871ebe 100644
--- a/docs/modules/ROOT/pages/running/running-cli.adoc
+++ b/docs/modules/ROOT/pages/running/running-cli.adoc
@@ -67,8 +67,6 @@ As an example, take the option available on the `kamel run test.yaml -t promethe
apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: test
spec:
flows:
diff --git a/e2e/advanced/operator_id_filtering_test.go b/e2e/advanced/operator_id_filtering_test.go
index 4e2d71412..184603d91 100644
--- a/e2e/advanced/operator_id_filtering_test.go
+++ b/e2e/advanced/operator_id_filtering_test.go
@@ -91,7 +91,7 @@ func TestOperatorIDFiltering(t *testing.T) {
v1.IntegrationKitTypeLabel: v1.IntegrationKitTypeExternal,
},
Annotations: map[string]string{
- "camel.apache.org/operator.id": operator2,
+ v1.OperatorIDAnnotation: operator2,
},
},
Spec: v1.IntegrationKitSpec{
diff --git a/e2e/common/misc/pipe_test.go b/e2e/common/misc/pipe_test.go
index 4aa7797bd..2402919b6 100644
--- a/e2e/common/misc/pipe_test.go
+++ b/e2e/common/misc/pipe_test.go
@@ -127,53 +127,6 @@ func TestPipe(t *testing.T) {
})
}
-func TestPipeWithImage(t *testing.T) {
- WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
- bindingID := "with-image-binding"
-
- t.Run("run with initial image", func(t *testing.T) {
- expectedImage := "quay.io/fuse_qe/echo-server:0.3.2"
-
- g.Expect(KamelBind(t, ctx, ns, "my-own-timer-source", "my-own-log-sink",
- "--trait", "container.image="+expectedImage, "--trait", "jvm.enabled=false",
- "--trait", "kamelets.enabled=false", "--trait", "dependencies.enabled=false",
- "--annotation", "test=1", "--name", bindingID).Execute()).To(Succeed())
-
- g.Eventually(IntegrationGeneration(t, ctx, ns, bindingID)).
- Should(gstruct.PointTo(BeNumerically("==", 1)))
- g.Eventually(Integration(t, ctx, ns, bindingID)).Should(WithTransform(Annotations,
- HaveKeyWithValue("test", "1"),
- ))
- g.Eventually(IntegrationStatusImage(t, ctx, ns, bindingID)).
- Should(Equal(expectedImage))
- g.Eventually(IntegrationPodPhase(t, ctx, ns, bindingID), TestTimeoutShort).
- Should(Equal(corev1.PodRunning))
- g.Eventually(IntegrationPodImage(t, ctx, ns, bindingID)).
- Should(Equal(expectedImage))
- })
-
- t.Run("run with new image", func(t *testing.T) {
- expectedImage := "quay.io/fuse_qe/echo-server:0.3.3"
-
- g.Expect(KamelBind(t, ctx, ns, "my-own-timer-source", "my-own-log-sink",
- "--trait", "container.image="+expectedImage, "--trait", "jvm.enabled=false",
- "--trait", "kamelets.enabled=false", "--trait", "dependencies.enabled=false",
- "--annotation", "test=2", "--name", bindingID).Execute()).To(Succeed())
- g.Eventually(IntegrationGeneration(t, ctx, ns, bindingID)).
- Should(gstruct.PointTo(BeNumerically("==", 1)))
- g.Eventually(Integration(t, ctx, ns, bindingID)).Should(WithTransform(Annotations,
- HaveKeyWithValue("test", "2"),
- ))
- g.Eventually(IntegrationStatusImage(t, ctx, ns, bindingID)).
- Should(Equal(expectedImage))
- g.Eventually(IntegrationPodPhase(t, ctx, ns, bindingID), TestTimeoutShort).
- Should(Equal(corev1.PodRunning))
- g.Eventually(IntegrationPodImage(t, ctx, ns, bindingID)).
- Should(Equal(expectedImage))
- })
- })
-}
-
func TestPipeScale(t *testing.T) {
WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
name := RandomizedSuffixName("timer2log")
diff --git a/e2e/install/kustomize/setup_test.go b/e2e/install/kustomize/all_namespaces_test.go
similarity index 61%
rename from e2e/install/kustomize/setup_test.go
rename to e2e/install/kustomize/all_namespaces_test.go
index e5740b9d3..9df5e5e8f 100644
--- a/e2e/install/kustomize/setup_test.go
+++ b/e2e/install/kustomize/all_namespaces_test.go
@@ -37,67 +37,6 @@ import (
. "github.com/onsi/gomega"
)
-func TestKustomizeNamespaced(t *testing.T) {
- kustomizeDir := testutil.MakeTempCopyDir(t, "../../../install")
- WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
- // Let's make sure no CRD is yet available in the cluster
- // as we must make the procedure to install them accordingly
- g.Eventually(CRDs(t)).Should(BeNil(), "No Camel K CRDs should be previously installed for this test")
- // We must change a few values in the Kustomize config
- ExpectExecSucceed(t, g,
- exec.Command(
- "sed",
- "-i",
- fmt.Sprintf("s/namespace: .*/namespace: %s/", ns),
- fmt.Sprintf("%s/overlays/kubernetes/namespaced/kustomization.yaml", kustomizeDir),
- ))
- ExpectExecSucceed(t, g, Kubectl(
- "apply",
- "-k",
- fmt.Sprintf("%s/overlays/kubernetes/namespaced", kustomizeDir),
- "--server-side",
- ))
-
- // Refresh the test client to account for the newly installed CRDs
- RefreshClient(t)
- g.Eventually(OperatorPod(t, ctx, ns)).ShouldNot(BeNil())
- g.Eventually(OperatorPodPhase(t, ctx, ns)).Should(Equal(corev1.PodRunning))
- // Check if restricted security context has been applied
- operatorPod := OperatorPod(t, ctx, ns)()
- g.Expect(operatorPod.Spec.Containers[0].SecurityContext.RunAsNonRoot).To(
- Equal(DefaultOperatorSecurityContext().RunAsNonRoot),
- )
- g.Expect(operatorPod.Spec.Containers[0].SecurityContext.Capabilities).To(
- Equal(DefaultOperatorSecurityContext().Capabilities),
- )
- g.Expect(operatorPod.Spec.Containers[0].SecurityContext.SeccompProfile).To(
- Equal(DefaultOperatorSecurityContext().SeccompProfile),
- )
- g.Expect(operatorPod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation).To(
- Equal(DefaultOperatorSecurityContext().AllowPrivilegeEscalation),
- )
-
- // Test a simple integration is running
- g.Expect(KamelRun(t, ctx, ns, "files/yaml.yaml").Execute()).To(Succeed())
- g.Eventually(IntegrationPodPhase(t, ctx, ns, "yaml"), TestTimeoutMedium).Should(Equal(corev1.PodRunning))
- g.Eventually(IntegrationConditionStatus(t, ctx, ns, "yaml", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
- g.Eventually(IntegrationLogs(t, ctx, ns, "yaml"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
-
- // Test operator only uninstall
- UninstallOperator(t, ctx, g, ns, "../../../")
-
- g.Eventually(OperatorPod(t, ctx, ns)).Should(BeNil())
- g.Eventually(Integration(t, ctx, ns, "yaml"), TestTimeoutShort).ShouldNot(BeNil())
- g.Eventually(IntegrationConditionStatus(t, ctx, ns, "yaml", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
-
- // Test CRD uninstall (will remove Integrations as well)
- UninstallCRDs(t, ctx, g, "../../../")
-
- g.Eventually(OperatorPod(t, ctx, ns)).Should(BeNil())
- g.Eventually(CRDs(t)).Should(BeNil())
- })
-}
-
func TestKustomizeDescoped(t *testing.T) {
kustomizeDir := testutil.MakeTempCopyDir(t, "../../../install")
WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
@@ -119,9 +58,6 @@ func TestKustomizeDescoped(t *testing.T) {
"--server-side",
))
- // Refresh the test client to account for the newly installed CRDs
- RefreshClient(t)
-
podFunc := OperatorPod(t, ctx, ns)
g.Eventually(podFunc).ShouldNot(BeNil())
g.Eventually(OperatorPodPhase(t, ctx, ns)).Should(Equal(corev1.PodRunning))
diff --git a/e2e/install/kustomize/own_namespace_test.go b/e2e/install/kustomize/own_namespace_test.go
new file mode 100644
index 000000000..82f0a7161
--- /dev/null
+++ b/e2e/install/kustomize/own_namespace_test.go
@@ -0,0 +1,83 @@
+//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 kustomize
+
+import (
+ "context"
+ "fmt"
+ "os/exec"
+ "testing"
+
+ corev1 "k8s.io/api/core/v1"
+
+ . "github.com/apache/camel-k/v2/e2e/support"
+ testutil "github.com/apache/camel-k/v2/e2e/support/util"
+ v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+
+ . "github.com/onsi/gomega"
+)
+
+func TestKustomizeOwnNamespace(t *testing.T) {
+ kustomizeDir := testutil.MakeTempCopyDir(t, "../../../install")
+ WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
+ // Let's make sure no CRD is yet available in the cluster
+ // as we must make the procedure to install them accordingly
+ g.Eventually(CRDs(t)).Should(BeNil(), "No Camel K CRDs should be previously installed for this test")
+ // We must change a few values in the Kustomize config
+ ExpectExecSucceed(t, g,
+ exec.Command(
+ "sed",
+ "-i",
+ fmt.Sprintf("s/namespace: .*/namespace: %s/", ns),
+ fmt.Sprintf("%s/overlays/kubernetes/own-namespace/kustomization.yaml", kustomizeDir),
+ ))
+ ExpectExecSucceed(t, g, Kubectl(
+ "apply",
+ "-k",
+ fmt.Sprintf("%s/overlays/kubernetes/own-namespace", kustomizeDir),
+ "--server-side",
+ ))
+
+ g.Eventually(OperatorPod(t, ctx, ns)).ShouldNot(BeNil())
+ g.Eventually(OperatorPodPhase(t, ctx, ns)).Should(Equal(corev1.PodRunning))
+
+ // Test a simple integration is running
+ g.Expect(KamelRun(t, ctx, ns, "files/yaml.yaml").Execute()).To(Succeed())
+ g.Eventually(IntegrationPodPhase(t, ctx, ns, "yaml"), TestTimeoutMedium).Should(Equal(corev1.PodRunning))
+ g.Eventually(IntegrationConditionStatus(t, ctx, ns, "yaml", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+ g.Eventually(IntegrationLogs(t, ctx, ns, "yaml"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+
+ // Test operator only uninstall
+ UninstallOperator(t, ctx, g, ns, "../../../")
+
+ g.Eventually(OperatorPod(t, ctx, ns)).Should(BeNil())
+ g.Eventually(Integration(t, ctx, ns, "yaml"), TestTimeoutShort).ShouldNot(BeNil())
+ g.Eventually(IntegrationConditionStatus(t, ctx, ns, "yaml", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+
+ // Test CRD uninstall (will remove Integrations as well)
+ UninstallCRDs(t, ctx, g, "../../../")
+
+ g.Eventually(OperatorPod(t, ctx, ns)).Should(BeNil())
+ g.Eventually(CRDs(t)).Should(BeNil())
+ })
+}
diff --git a/e2e/install/kustomize/single_namespace_test.go b/e2e/install/kustomize/single_namespace_test.go
new file mode 100644
index 000000000..e0229e49a
--- /dev/null
+++ b/e2e/install/kustomize/single_namespace_test.go
@@ -0,0 +1,87 @@
+//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 kustomize
+
+import (
+ "context"
+ "fmt"
+ "testing"
+ "time"
+
+ corev1 "k8s.io/api/core/v1"
+
+ . "github.com/apache/camel-k/v2/e2e/support"
+ testutil "github.com/apache/camel-k/v2/e2e/support/util"
+ v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+
+ . "github.com/onsi/gomega"
+)
+
+func TestKustomizeSingleNamespace(t *testing.T) {
+ kustomizeDir := testutil.MakeTempCopyDir(t, "../../../install")
+
+ // The operator is expected to be installed in "operators" namespace
+ // it also expects to reconcile correctly an Integration in namespace "tenant-a"
+ // but it won't reconcile in any other namespaces, for example, "tenan-b"
+ WithNamedTestNamespace(t, func(ctx context.Context, g *WithT, operatorNs string) {
+ WithNamedTestNamespace(t, func(ctx context.Context, g *WithT, tenantNs string) {
+ // Let's make sure no CRD is yet available in the cluster
+ // as we must make the procedure to install them accordingly
+ g.Eventually(CRDs(t)).Should(BeNil(), "No Camel K CRDs should be previously installed for this test")
+ ExpectExecSucceed(t, g, Kubectl(
+ "apply",
+ "-k",
+ fmt.Sprintf("%s/overlays/kubernetes/single-namespace", kustomizeDir),
+ "--server-side",
+ ))
+ g.Eventually(OperatorPod(t, ctx, operatorNs)).ShouldNot(BeNil())
+ g.Eventually(OperatorPodPhase(t, ctx, operatorNs)).Should(Equal(corev1.PodRunning))
+
+ WithNamedTestNamespace(t, func(ctx context.Context, g *WithT, tenantNs string) {
+ // Test a simple integration in "tenant-b" is not reconciled
+ g.Expect(KamelRun(t, ctx, tenantNs, "files/yaml.yaml").Execute()).To(Succeed())
+ g.Consistently(IntegrationPhase(t, ctx, tenantNs, "yaml"), 10*time.Second).Should(BeEmpty())
+ }, "tenant-b")
+
+ // Test a simple integration in "tenant-a" is reconciled and runs correctly
+ g.Expect(KamelRun(t, ctx, tenantNs, "files/yaml.yaml").Execute()).To(Succeed())
+ g.Eventually(IntegrationConditionStatus(t, ctx, tenantNs, "yaml", v1.IntegrationConditionReady), TestTimeoutMedium).
+ Should(Equal(corev1.ConditionTrue))
+ g.Eventually(IntegrationLogs(t, ctx, tenantNs, "yaml"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+
+ // Test operator only uninstall
+ UninstallOperator(t, ctx, g, operatorNs, "../../../")
+
+ g.Eventually(OperatorPod(t, ctx, operatorNs)).Should(BeNil())
+ g.Eventually(Integration(t, ctx, "tenant-a", "yaml"), TestTimeoutShort).ShouldNot(BeNil())
+ g.Eventually(IntegrationConditionStatus(t, ctx, "tenant-a", "yaml", v1.IntegrationConditionReady), TestTimeoutShort).
+ Should(Equal(corev1.ConditionTrue))
+
+ // Test CRD uninstall (will remove Integrations as well)
+ UninstallCRDs(t, ctx, g, "../../../")
+
+ g.Eventually(OperatorPod(t, ctx, operatorNs)).Should(BeNil())
+ g.Eventually(CRDs(t)).Should(BeNil())
+ }, "tenant-a")
+ }, "operators")
+}
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index 156f7cde9..e61bbca34 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -292,7 +292,10 @@ func kamelCommandWithContext(t *testing.T, ctx context.Context, command string,
cmdMutex.Lock()
defer cmdMutex.Unlock()
- cmdArgs := []string{command, "-n", namespace, "--operator-id", operatorID}
+ cmdArgs := []string{command, "-n", namespace}
+ if operatorID != platform.DefaultPlatformName {
+ cmdArgs = append(cmdArgs, "--operator-id", operatorID)
+ }
cmdArgs = append(cmdArgs, args...)
return KamelWithContext(t, ctx, cmdArgs...)
}
@@ -2539,6 +2542,14 @@ func WithNewTestNamespace(t *testing.T, doRun func(context.Context, *gomega.With
invokeUserTestCode(t, testContext, ns.GetName(), doRun)
}
+func WithNamedTestNamespace(t *testing.T, doRun func(context.Context, *gomega.WithT, string), namespace string) {
+ ns := NewNamedTestNamespace(t, testContext, namespace, false)
+ defer deleteTestNamespace(t, testContext, ns)
+ defer userCleanup(t)
+
+ invokeUserTestCode(t, testContext, ns.GetName(), doRun)
+}
+
func WithNewTestNamespaceWithKnativeBroker(t *testing.T, doRun func(context.Context, *gomega.WithT, string)) {
ns := NewTestNamespace(t, testContext, true)
defer deleteTestNamespace(t, testContext, ns)
diff --git a/install/overlays/kubernetes/namespaced/kustomization.yaml b/install/overlays/kubernetes/own-namespace/kustomization.yaml
similarity index 100%
rename from install/overlays/kubernetes/namespaced/kustomization.yaml
rename to install/overlays/kubernetes/own-namespace/kustomization.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-log-level.yaml b/install/overlays/kubernetes/own-namespace/patch-log-level.yaml
similarity index 100%
rename from install/overlays/kubernetes/namespaced/patch-log-level.yaml
rename to install/overlays/kubernetes/own-namespace/patch-log-level.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-node-selector.yaml b/install/overlays/kubernetes/own-namespace/patch-node-selector.yaml
similarity index 100%
rename from install/overlays/kubernetes/namespaced/patch-node-selector.yaml
rename to install/overlays/kubernetes/own-namespace/patch-node-selector.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-operator-id.yaml b/install/overlays/kubernetes/own-namespace/patch-operator-id.yaml
similarity index 100%
copy from install/overlays/kubernetes/namespaced/patch-operator-id.yaml
copy to install/overlays/kubernetes/own-namespace/patch-operator-id.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-ports.yaml b/install/overlays/kubernetes/own-namespace/patch-ports.yaml
similarity index 100%
rename from install/overlays/kubernetes/namespaced/patch-ports.yaml
rename to install/overlays/kubernetes/own-namespace/patch-ports.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-resource-requirements.yaml b/install/overlays/kubernetes/own-namespace/patch-resource-requirements.yaml
similarity index 100%
rename from install/overlays/kubernetes/namespaced/patch-resource-requirements.yaml
rename to install/overlays/kubernetes/own-namespace/patch-resource-requirements.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-toleration.yaml b/install/overlays/kubernetes/own-namespace/patch-toleration.yaml
similarity index 100%
copy from install/overlays/kubernetes/namespaced/patch-toleration.yaml
copy to install/overlays/kubernetes/own-namespace/patch-toleration.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-operator-id.yaml b/install/overlays/kubernetes/single-namespace/kustomization.yaml
similarity index 89%
copy from install/overlays/kubernetes/namespaced/patch-operator-id.yaml
copy to install/overlays/kubernetes/single-namespace/kustomization.yaml
index 25c150420..bd6a00ee6 100644
--- a/install/overlays/kubernetes/namespaced/patch-operator-id.yaml
+++ b/install/overlays/kubernetes/single-namespace/kustomization.yaml
@@ -14,7 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ---------------------------------------------------------------------------
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
-- op: add
- path: /spec/template/spec/containers/0/env/2/value
- value: camel-k
+resources:
+- operator
+- tenant-a-ns-rbac
diff --git a/pkg/resources/config/manager/kustomization.yaml b/install/overlays/kubernetes/single-namespace/operator/kustomization.yaml
similarity index 86%
copy from pkg/resources/config/manager/kustomization.yaml
copy to install/overlays/kubernetes/single-namespace/operator/kustomization.yaml
index a4543333a..62fa2c867 100644
--- a/pkg/resources/config/manager/kustomization.yaml
+++ b/install/overlays/kubernetes/single-namespace/operator/kustomization.yaml
@@ -14,17 +14,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ---------------------------------------------------------------------------
-
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
+namespace: operators
+nameSuffix: -tenant-a
+
resources:
-- operator-deployment.yaml
-- operator-service-account.yaml
-- builder-service-account.yaml
+- ../../own-namespace
patches:
- - path: add-registry-envvars.yaml
- target:
+ - target:
kind: Deployment
- name: camel-k-operator
+ path: remove-watch-ns.yaml
+ - path: patch-envvars.yaml
diff --git a/install/overlays/kubernetes/namespaced/patch-toleration.yaml b/install/overlays/kubernetes/single-namespace/operator/patch-envvars.yaml
similarity index 78%
rename from install/overlays/kubernetes/namespaced/patch-toleration.yaml
rename to install/overlays/kubernetes/single-namespace/operator/patch-envvars.yaml
index 71b7f1228..b5ceec673 100644
--- a/install/overlays/kubernetes/namespaced/patch-toleration.yaml
+++ b/install/overlays/kubernetes/single-namespace/operator/patch-envvars.yaml
@@ -22,11 +22,14 @@ metadata:
spec:
template:
spec:
- tolerations:
-#
-# Add tolerations for configuring the deployment
-# eg.
-# - key: "key1"
-# operator: "Equal"
-# value: "value1"
-# effect: "NoSchedule"
+ containers:
+ - name: camel-k-operator
+ env:
+ - name: BUILDER_SA
+ value: camel-k-builder-tenant-a
+
+ - name: WATCH_NAMESPACE
+ value: tenant-a
+
+ - name: OPERATOR_ID
+ value: camel-k-tenant-a
\ No newline at end of file
diff --git a/install/overlays/kubernetes/namespaced/patch-operator-id.yaml b/install/overlays/kubernetes/single-namespace/operator/remove-watch-ns.yaml
similarity index 92%
rename from install/overlays/kubernetes/namespaced/patch-operator-id.yaml
rename to install/overlays/kubernetes/single-namespace/operator/remove-watch-ns.yaml
index 25c150420..6a9dc9b98 100644
--- a/install/overlays/kubernetes/namespaced/patch-operator-id.yaml
+++ b/install/overlays/kubernetes/single-namespace/operator/remove-watch-ns.yaml
@@ -15,6 +15,5 @@
# limitations under the License.
# ---------------------------------------------------------------------------
-- op: add
- path: /spec/template/spec/containers/0/env/2/value
- value: camel-k
+- op: remove
+ path: /spec/template/spec/containers/0/env/0
\ No newline at end of file
diff --git a/pkg/resources/config/manager/kustomization.yaml b/install/overlays/kubernetes/single-namespace/tenant-a-ns-rbac/kustomization.yaml
similarity index 84%
copy from pkg/resources/config/manager/kustomization.yaml
copy to install/overlays/kubernetes/single-namespace/tenant-a-ns-rbac/kustomization.yaml
index a4543333a..0b1aafa9b 100644
--- a/pkg/resources/config/manager/kustomization.yaml
+++ b/install/overlays/kubernetes/single-namespace/tenant-a-ns-rbac/kustomization.yaml
@@ -14,17 +14,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ---------------------------------------------------------------------------
-
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
+namespace: tenant-a
+nameSuffix: -tenant-a
+
resources:
-- operator-deployment.yaml
-- operator-service-account.yaml
-- builder-service-account.yaml
+- ../../../../base/config/rbac/namespaced
patches:
- - path: add-registry-envvars.yaml
- target:
- kind: Deployment
- name: camel-k-operator
+ - target:
+ kind: RoleBinding
+ path: patch-rolebinding-subjects.yaml
\ No newline at end of file
diff --git a/install/overlays/kubernetes/namespaced/patch-install-default-kamelets.yaml b/install/overlays/kubernetes/single-namespace/tenant-a-ns-rbac/patch-rolebinding-subjects.yaml
similarity index 88%
rename from install/overlays/kubernetes/namespaced/patch-install-default-kamelets.yaml
rename to install/overlays/kubernetes/single-namespace/tenant-a-ns-rbac/patch-rolebinding-subjects.yaml
index fa3012076..d60bd2220 100644
--- a/install/overlays/kubernetes/namespaced/patch-install-default-kamelets.yaml
+++ b/install/overlays/kubernetes/single-namespace/tenant-a-ns-rbac/patch-rolebinding-subjects.yaml
@@ -16,7 +16,8 @@
# ---------------------------------------------------------------------------
- op: add
- path: /spec/template/spec/containers/0/env/-
- value:
- name: KAMEL_INSTALL_DEFAULT_KAMELETS
- value: "false"
+ path: /subjects/0/namespace
+ value: "operators"
+- op: replace
+ path: /subjects/0/name
+ value: camel-k-operator-tenant-a
\ No newline at end of file
diff --git a/pkg/apis/camel/v1/common_types.go b/pkg/apis/camel/v1/common_types.go
index 1a7cf947a..826a6099b 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -29,6 +29,8 @@ const (
// Deprecated: use .spec.traits instead.
TraitAnnotationPrefix = "trait.camel.apache.org/"
// OperatorIDAnnotation operator id annotation label.
+ //
+ // Deprecated: will be removed in the future.
OperatorIDAnnotation = "camel.apache.org/operator.id"
// PlatformSelectorAnnotation platform id annotation label.
PlatformSelectorAnnotation = "camel.apache.org/platform.id"
diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go
index e5b991196..1e775567d 100644
--- a/pkg/cmd/bind.go
+++ b/pkg/cmd/bind.go
@@ -62,7 +62,7 @@ func newCmdBind(rootCmdOptions *RootCmdOptions) (*cobra.Command, *bindCmdOptions
cmd.Flags().Bool("skip-checks", false, "Do not verify the binding for compliance with Kamelets and other Kubernetes resources")
cmd.Flags().StringArray("step", nil, `Add binding steps as Kubernetes resources. Endpoints are expected in the format "[[apigroup/]version:]kind:[namespace/]name", plain Camel URIs or Kamelet name.`)
cmd.Flags().StringArrayP("trait", "t", nil, `Add a trait to the corresponding Integration.`)
- cmd.Flags().StringP("operator-id", "x", "camel-k", "Operator id selected to manage this Pipe.")
+ cmd.Flags().StringP("operator-id", "x", "", "Deprecated. Operator id selected to manage this Pipe.")
cmd.Flags().StringArray("annotation", nil, "Add an annotation to the Pipe. E.g. \"--annotation my.company=hello\"")
cmd.Flags().String("service-account", "", "The SA to use to run this binding")
cmd.Flags().StringArrayP("dependency", "d", nil, `A dependency that should be included, e.g., "camel:mail" for a Camel component, "mvn:org.my:app:1.0" for a Maven dependency`)
@@ -120,10 +120,6 @@ func (o *bindCmdOptions) validate(cmd *cobra.Command, args []string) error {
return errors.New("source or sink arguments are missing")
}
- if o.OperatorID == "" {
- return errors.New("cannot use empty operator id")
- }
-
for _, annotation := range o.Annotations {
parts := strings.SplitN(annotation, "=", 2)
if len(parts) != 2 {
@@ -245,12 +241,20 @@ func (o *bindCmdOptions) run(cmd *cobra.Command, args []string) error {
}
// --operator-id={id} is a syntax sugar for '--annotation camel.apache.org/operator.id={id}'
- pipe.SetOperatorID(strings.TrimSpace(o.OperatorID))
+ if o.OperatorID != "" {
+ pipe.SetOperatorID(strings.TrimSpace(o.OperatorID))
+ }
- for _, annotation := range o.Annotations {
- parts := strings.SplitN(annotation, "=", 2)
- if len(parts) == 2 {
- pipe.Annotations[parts[0]] = parts[1]
+ if o.Annotations != nil {
+ if pipe.Annotations == nil {
+ pipe.Annotations = map[string]string{}
+ }
+
+ for _, annotation := range o.Annotations {
+ parts := strings.SplitN(annotation, "=", 2)
+ if len(parts) == 2 {
+ pipe.Annotations[parts[0]] = parts[1]
+ }
}
}
diff --git a/pkg/cmd/bind_test.go b/pkg/cmd/bind_test.go
index 1e0396e9d..a6627d666 100644
--- a/pkg/cmd/bind_test.go
+++ b/pkg/cmd/bind_test.go
@@ -55,7 +55,7 @@ func TestBindOutputJSON(t *testing.T) {
assert.Equal(t, "json", buildCmdOptions.OutputFormat)
require.NoError(t, err)
- assert.Equal(t, `{"kind":"Pipe","apiVersion":"camel.apache.org/v1","metadata":{"name":"my-to-my","annotations":{"camel.apache.org/operator.id":"camel-k"}},"spec":{"source":{"uri":"my:src"},"sink":{"uri":"my:dst"}},"status":{}}`, output)
+ assert.Equal(t, `{"kind":"Pipe","apiVersion":"camel.apache.org/v1","metadata":{"name":"my-to-my"},"spec":{"source":{"uri":"my:src"},"sink":{"uri":"my:dst"}},"status":{}}`, output)
}
func TestBindOutputYAML(t *testing.T) {
@@ -67,8 +67,6 @@ func TestBindOutputYAML(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
sink:
@@ -97,8 +95,6 @@ func TestBindErrorHandlerDLCKamelet(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
errorHandler:
@@ -128,8 +124,6 @@ func TestBindErrorHandlerNone(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
errorHandler:
@@ -152,8 +146,6 @@ func TestBindErrorHandlerLog(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
errorHandler:
@@ -176,8 +168,6 @@ func TestBindTraits(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
sink:
@@ -202,8 +192,6 @@ func TestBindTraitsArray(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
sink:
@@ -231,8 +219,6 @@ func TestBindSteps(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
sink:
@@ -283,8 +269,6 @@ func TestBindOutputWithDependencies(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-to-my
spec:
dependencies:
diff --git a/pkg/cmd/operator/operator.go b/pkg/cmd/operator/operator.go
index 9255c727c..58d11ebbc 100644
--- a/pkg/cmd/operator/operator.go
+++ b/pkg/cmd/operator/operator.go
@@ -19,7 +19,6 @@ package operator
import (
"context"
- "errors"
"flag"
"fmt"
"os"
@@ -38,7 +37,6 @@ import (
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
@@ -158,8 +156,7 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
}
// Set the operator container image if it runs in-container
- platform.OperatorImage, err = getOperatorImage(ctx, bootstrapClient)
- exitOnError(err, "cannot get operator container image")
+ platform.OperatorImage = getOperatorImage()
if !leaderElection {
log.Info("Leader election is disabled!")
@@ -173,11 +170,15 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
Label: labelsSelector,
}
+ cacheConfigs := getNamespacesSelector(operatorNamespace, watchNamespace)
if !platform.IsCurrentOperatorGlobal() {
+ log.Infof("This operator is configured to watch only %s namespace(s)", watchNamespace)
selector = cache.ByObject{
Label: labelsSelector,
- Namespaces: getNamespacesSelector(operatorNamespace, watchNamespace),
+ Namespaces: cacheConfigs,
}
+ } else {
+ log.Info("This operator is global and will watch all namespaces!")
}
selectors := map[ctrl.Object]cache.ByObject{
@@ -186,11 +187,13 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
&batchv1.Job{}: selector,
}
- if ok, err := kubernetes.IsAPIResourceInstalled(bootstrapClient, servingv1.SchemeGroupVersion.String(), reflect.TypeFor[servingv1.Service]().Name()); ok && err == nil {
+ if ok, err := kubernetes.IsAPIResourceInstalled(bootstrapClient, servingv1.SchemeGroupVersion.String(),
+ reflect.TypeFor[servingv1.Service]().Name()); ok && err == nil {
selectors[&servingv1.Service{}] = selector
}
- if ok, err := kubernetes.IsAPIResourceInstalled(bootstrapClient, batchv1.SchemeGroupVersion.String(), reflect.TypeFor[batchv1.CronJob]().Name()); ok && err == nil {
+ if ok, err := kubernetes.IsAPIResourceInstalled(bootstrapClient, batchv1.SchemeGroupVersion.String(),
+ reflect.TypeFor[batchv1.CronJob]().Name()); ok && err == nil {
selectors[&batchv1.CronJob{}] = selector
}
@@ -199,7 +202,7 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
}
if !platform.IsCurrentOperatorGlobal() {
- options.DefaultNamespaces = getNamespacesSelector(operatorNamespace, watchNamespace)
+ options.DefaultNamespaces = cacheConfigs
}
mgr, err := manager.New(cfg, manager.Options{
@@ -224,7 +227,7 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
log.Info("Installing operator resources")
installCtx, installCancel := context.WithTimeout(ctx, 1*time.Minute)
defer installCancel()
- install.OperatorStartupOptionalTools(installCtx, bootstrapClient, watchNamespace, operatorNamespace, log)
+ install.OperatorStartupOptionalTools(installCtx, bootstrapClient, log)
synthEnvVal, synth := os.LookupEnv("CAMEL_K_SYNTHETIC_INTEGRATIONS")
if synth && synthEnvVal == "true" {
@@ -238,10 +241,19 @@ func Run(healthPort, monitoringPort int32, leaderElection bool, leaderElectionID
func getNamespacesSelector(operatorNamespace string, watchNamespace string) map[string]cache.Config {
namespacesSelector := map[string]cache.Config{
+ // The same operator namespace is needed while the operator stores
+ // Builds and IntegrationKits and CamelCatalogs in its namespace
+ // TODO: remove this when we either remove those CR or we move them in the tenant namespace only
operatorNamespace: {},
}
- if operatorNamespace != watchNamespace {
- namespacesSelector[watchNamespace] = cache.Config{}
+
+ for ns := range strings.SplitSeq(watchNamespace, ",") {
+ ns = strings.TrimSpace(ns)
+ if ns == "" || ns == operatorNamespace {
+ continue
+ }
+
+ namespacesSelector[ns] = cache.Config{}
}
return namespacesSelector
@@ -258,24 +270,8 @@ func getWatchNamespace() (string, error) {
}
// getOperatorImage returns the image currently used by the running operator if present (when running out of cluster, it may be absent).
-func getOperatorImage(ctx context.Context, c ctrl.Reader) (string, error) {
- ns := platform.GetOperatorNamespace()
- name := platform.GetOperatorPodName()
- if ns == "" || name == "" {
- return "", nil
- }
-
- pod := corev1.Pod{}
- if err := c.Get(ctx, ctrl.ObjectKey{Namespace: ns, Name: name}, &pod); err != nil && k8serrors.IsNotFound(err) {
- return "", nil
- } else if err != nil {
- return "", err
- }
- if len(pod.Spec.Containers) == 0 {
- return "", errors.New("no containers found in operator pod")
- }
-
- return pod.Spec.Containers[0].Image, nil
+func getOperatorImage() string {
+ return os.Getenv("CONTAINER_IMAGE")
}
func exitOnError(err error, msg string) {
diff --git a/pkg/cmd/operator/operator_test.go b/pkg/cmd/operator/operator_test.go
new file mode 100644
index 000000000..00eac0784
--- /dev/null
+++ b/pkg/cmd/operator/operator_test.go
@@ -0,0 +1,150 @@
+/*
+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 operator
+
+import (
+ "testing"
+
+ "github.com/apache/camel-k/v2/pkg/platform"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+)
+
+func TestGetNamespacesSelector(t *testing.T) {
+ tests := []struct {
+ name string
+ operatorNamespace string
+ watchNamespace string
+ expected map[string]cache.Config
+ }{
+ {
+ name: "same namespace",
+ operatorNamespace: "operator",
+ watchNamespace: "operator",
+ expected: map[string]cache.Config{
+ "operator": {},
+ },
+ },
+ {
+ name: "different namespace",
+ operatorNamespace: "operator",
+ watchNamespace: "tenant",
+ expected: map[string]cache.Config{
+ "operator": {},
+ "tenant": {},
+ },
+ },
+ {
+ name: "csv namespaces",
+ operatorNamespace: "operator",
+ watchNamespace: "tenant-a,tenant-b,tenant-c",
+ expected: map[string]cache.Config{
+ "operator": {},
+ "tenant-a": {},
+ "tenant-b": {},
+ "tenant-c": {},
+ },
+ },
+ {
+ name: "trim spaces",
+ operatorNamespace: "operator",
+ watchNamespace: "tenant-a, tenant-b , tenant-c",
+ expected: map[string]cache.Config{
+ "operator": {},
+ "tenant-a": {},
+ "tenant-b": {},
+ "tenant-c": {},
+ },
+ },
+ {
+ name: "ignore duplicates",
+ operatorNamespace: "operator",
+ watchNamespace: "tenant-a,tenant-a,tenant-b",
+ expected: map[string]cache.Config{
+ "operator": {},
+ "tenant-a": {},
+ "tenant-b": {},
+ },
+ },
+ {
+ name: "ignore empty entries",
+ operatorNamespace: "operator",
+ watchNamespace: "tenant-a,,tenant-b,",
+ expected: map[string]cache.Config{
+ "operator": {},
+ "tenant-a": {},
+ "tenant-b": {},
+ },
+ },
+ {
+ name: "ignore operator namespace in csv",
+ operatorNamespace: "operator",
+ watchNamespace: "tenant-a,operator,tenant-b",
+ expected: map[string]cache.Config{
+ "operator": {},
+ "tenant-a": {},
+ "tenant-b": {},
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ actual := getNamespacesSelector(tt.operatorNamespace, tt.watchNamespace)
+ assert.Equal(t, tt.expected, actual)
+ })
+ }
+}
+
+func TestGetWatchNamespace(t *testing.T) {
+ t.Run("env variable set", func(t *testing.T) {
+ t.Setenv(platform.OperatorWatchNamespaceEnvVariable, "tenant-a,tenant-b")
+
+ ns, err := getWatchNamespace()
+
+ require.NoError(t, err)
+ assert.Equal(t, "tenant-a,tenant-b", ns)
+ })
+
+ t.Run("env variable not set", func(t *testing.T) {
+ ns, err := getWatchNamespace()
+
+ require.Error(t, err)
+ assert.Empty(t, ns)
+ assert.Contains(t, err.Error(), platform.OperatorWatchNamespaceEnvVariable)
+ })
+}
+
+func TestGetOperatorImage(t *testing.T) {
+ t.Run("env variable set", func(t *testing.T) {
+ t.Setenv("CONTAINER_IMAGE", "quay.io/example/operator:latest")
+
+ image := getOperatorImage()
+
+ assert.Equal(t, "quay.io/example/operator:latest", image)
+ })
+
+ t.Run("env variable not set", func(t *testing.T) {
+ t.Setenv("CONTAINER_IMAGE", "")
+
+ image := getOperatorImage()
+
+ assert.Empty(t, image)
+ })
+}
diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go
index 7a128395e..522ec5ab1 100644
--- a/pkg/cmd/promote_test.go
+++ b/pkg/cmd/promote_test.go
@@ -145,8 +145,7 @@ func createTestCamelCatalog(ns string, runtimeProvider v1.RuntimeProvider, versi
func TestIntegrationWithMetadataDryRun(t *testing.T) {
defaultIntegration, defaultKit := nominalIntegration("my-it-test")
defaultIntegration.Annotations = map[string]string{
- "camel.apache.org/operator.id": "camel-k",
- "my-annotation": "my-value",
+ "my-annotation": "my-value",
}
defaultIntegration.Labels = map[string]string{
"my-label": "my-value",
@@ -182,8 +181,7 @@ status: {}
func TestPipeWithMetadataDryRun(t *testing.T) {
defaultKB := nominalPipe("my-pipe-test")
defaultKB.Annotations = map[string]string{
- "camel.apache.org/operator.id": "camel-k",
- "my-annotation": "my-value",
+ "my-annotation": "my-value",
}
defaultKB.Labels = map[string]string{
"my-label": "my-value",
@@ -334,8 +332,7 @@ status: {}
func TestPipeWithSavedTraitsDryRun(t *testing.T) {
defaultKB := nominalPipe("my-pipe-test")
defaultKB.Annotations = map[string]string{
- "camel.apache.org/operator.id": "camel-k",
- "my-annotation": "my-value",
+ "my-annotation": "my-value",
}
defaultKB.Labels = map[string]string{
"my-label": "my-value",
@@ -614,8 +611,7 @@ resources:
func TestPipeGitOps(t *testing.T) {
defaultPipe := nominalPipe("my-pipe-test")
defaultPipe.Annotations = map[string]string{
- "camel.apache.org/operator.id": "camel-k",
- "my-annotation": "my-value",
+ "my-annotation": "my-value",
}
defaultPipe.Labels = map[string]string{
"my-label": "my-value",
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 87ef58382..4a008edf4 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -97,7 +97,7 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) (*cobra.Command, *runCmdOptions)
cmd.Flags().Bool("sync", false, "[Deprecated] Synchronize the local source file with the cluster, republishing at each change")
cmd.Flags().Bool("dev", false, "[Deprecated] Enable Dev mode (equivalent to \"-w --logs --sync\")")
cmd.Flags().Bool("use-flows", true, "Write yaml sources as Flow objects in the integration custom resource")
- cmd.Flags().StringP("operator-id", "x", "camel-k", "Operator id selected to manage this integration.")
+ cmd.Flags().StringP("operator-id", "x", "", "Operator id selected to manage this integration.")
cmd.Flags().String("profile", "", "Trait profile used for deployment")
cmd.Flags().String("integration-profile", "", "Integration profile used for deployment")
cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
@@ -246,10 +246,6 @@ func (o *runCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
}
func (o *runCmdOptions) validate(cmd *cobra.Command) error {
- if o.OperatorID == "" {
- return errors.New("cannot use empty operator id")
- }
-
for _, volume := range o.Volumes {
volumeConfig := strings.Split(volume, ":")
if len(volumeConfig) != 2 || len(strings.TrimSpace(volumeConfig[0])) == 0 || len(strings.TrimSpace(volumeConfig[1])) == 0 {
@@ -719,7 +715,9 @@ func (o *runCmdOptions) applyAnnotations(it *v1.Integration) {
}
// --operator-id={id} is a syntax sugar for '--annotation camel.apache.org/operator.id={id}'
- it.SetOperatorID(strings.TrimSpace(o.OperatorID))
+ if o.OperatorID != "" {
+ it.SetOperatorID(strings.TrimSpace(o.OperatorID))
+ }
// --integration-profile={id} is a syntax sugar for '--annotation camel.apache.org/integration-profile.id={id}'
if o.IntegrationProfile != "" {
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index 39dc64c5d..73873a7de 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -578,8 +578,6 @@ func TestOutputYaml(t *testing.T) {
assert.Equal(t, fmt.Sprintf(`apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: %s
spec:
sources:
@@ -612,8 +610,6 @@ func TestTrait(t *testing.T) {
assert.Equal(t, fmt.Sprintf(`apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: %s
spec:
sources:
@@ -919,8 +915,6 @@ func TestSelfManagedBuildIntegration(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-app-v1
spec:
traits:
@@ -942,8 +936,6 @@ func TestGitRepoIntegration(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-it
spec:
git:
@@ -962,8 +954,6 @@ func TestGitTagIntegration(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-it
spec:
git:
@@ -983,8 +973,6 @@ func TestGitBranchIntegration(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-it
spec:
git:
@@ -1004,8 +992,6 @@ func TestGitCommitIntegration(t *testing.T) {
assert.Equal(t, `apiVersion: camel.apache.org/v1
kind: Integration
metadata:
- annotations:
- camel.apache.org/operator.id: camel-k
name: my-it
spec:
git:
diff --git a/pkg/controller/integration/build.go b/pkg/controller/integration/build.go
index 64cf10133..6c57004e9 100644
--- a/pkg/controller/integration/build.go
+++ b/pkg/controller/integration/build.go
@@ -100,6 +100,7 @@ func (action *buildAction) createBuild(ctx context.Context, it *v1.Integration)
operatorID := defaults.OperatorID()
if operatorID != "" {
+ //nolint:staticcheck
annotations[v1.OperatorIDAnnotation] = operatorID
}
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 612d30675..10a8c7c35 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -149,12 +149,7 @@ func integrationKitEnqueueRequestsFromMapFunc(ctx context.Context, c client.Clie
}
list := &v1.IntegrationList{}
- // Do global search in case of global operator (it may be using a global platform)
- var opts []ctrl.ListOption
- if !platform.IsCurrentOperatorGlobal() {
- opts = append(opts, ctrl.InNamespace(kit.Namespace))
- }
- if err := c.List(ctx, list, opts...); err != nil {
+ if err := c.List(ctx, list); err != nil {
log.Error(err, "Failed to retrieve integration list")
return requests
@@ -452,7 +447,7 @@ func watchKnativeResources(ctx context.Context, c client.Client, b *builder.Buil
b.Owns(&servingv1.Service{}, builder.WithPredicates(StatusChangedPredicate{}))
} else {
log.Info("KnativeService resources installed in the cluster. However Camel K operator has not the required RBAC privileges. " +
- "You can't use Knative features.Make sure to apply the required RBAC privileges and restart the Camel K Operator Pod to be able " +
+ "You can't use Knative features. Make sure to apply the required RBAC privileges and restart the Camel K Operator Pod to be able " +
"to watch for Camel K managed Knative Services.")
}
diff --git a/pkg/controller/integrationkit/build.go b/pkg/controller/integrationkit/build.go
index b7f41c83e..ab830f8a9 100644
--- a/pkg/controller/integrationkit/build.go
+++ b/pkg/controller/integrationkit/build.go
@@ -128,6 +128,7 @@ func (action *buildAction) createBuild(ctx context.Context, kit *v1.IntegrationK
operatorID := defaults.OperatorID()
if operatorID != "" {
+ //nolint:staticcheck
annotations[v1.OperatorIDAnnotation] = operatorID
}
diff --git a/pkg/controller/integrationkit/integrationkit_controller.go b/pkg/controller/integrationkit/integrationkit_controller.go
index 5fb5f2fd3..12c9c171d 100644
--- a/pkg/controller/integrationkit/integrationkit_controller.go
+++ b/pkg/controller/integrationkit/integrationkit_controller.go
@@ -153,6 +153,7 @@ func add(_ context.Context, mgr manager.Manager, r reconcile.Reconciler) error {
continue
}
+ //nolint:staticcheck
if v, ok := kit.Annotations[v1.OperatorIDAnnotation]; ok && v != itp.Name {
// kit waiting for another platform to become ready - skip here
log.Debugf("Integration kit %s is waiting for another integration platform '%s' - skip it now", kit.Name, v)
diff --git a/pkg/install/common.go b/pkg/install/common.go
deleted file mode 100644
index a2f620be4..000000000
--- a/pkg/install/common.go
+++ /dev/null
@@ -1,50 +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 (
- networking "k8s.io/api/networking/v1"
- rbacv1 "k8s.io/api/rbac/v1"
-
- ctrl "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// ResourceCustomizer can be used to inject code that changes the objects before they are created.
-type ResourceCustomizer func(object ctrl.Object) ctrl.Object
-
-// IdentityResourceCustomizer is a ResourceCustomizer that does nothing.
-var IdentityResourceCustomizer = func(object ctrl.Object) ctrl.Object {
- return object
-}
-
-var RemoveIngressRoleCustomizer = func(object ctrl.Object) ctrl.Object {
- if role, ok := object.(*rbacv1.Role); ok && role.Name == "camel-k-operator" {
- rules:
- for i, rule := range role.Rules {
- for _, group := range rule.APIGroups {
- if group == networking.GroupName {
- role.Rules = append(role.Rules[:i], role.Rules[i+1:]...)
-
- break rules
- }
- }
- }
- }
-
- return object
-}
diff --git a/pkg/install/optional.go b/pkg/install/optional.go
index 11b23d97c..764c5ece3 100644
--- a/pkg/install/optional.go
+++ b/pkg/install/optional.go
@@ -27,7 +27,7 @@ import (
)
// OperatorStartupOptionalTools tries to install optional tools at operator startup and warns if something goes wrong.
-func OperatorStartupOptionalTools(ctx context.Context, c client.Client, namespace string, operatorNamespace string, log logutil.Logger) {
+func OperatorStartupOptionalTools(ctx context.Context, c client.Client, log logutil.Logger) {
// Try to register the OpenShift CLI Download link if possible
if err := OpenShiftConsoleDownloadLink(ctx, c); err != nil {
log.Info("Cannot install OpenShift CLI download link: skipping.")
diff --git a/pkg/platform/defaults.go b/pkg/platform/defaults.go
index 28175c98a..22538128e 100644
--- a/pkg/platform/defaults.go
+++ b/pkg/platform/defaults.go
@@ -19,6 +19,7 @@ package platform
import (
"context"
+ "os"
"runtime"
"strings"
"time"
@@ -39,7 +40,6 @@ import (
const (
DefaultPlatformName = "camel-k"
- BuilderServiceAccount = "camel-k-builder"
DefaultBuildTimeout = 5 * time.Minute
DefaultBuildStrategy = v1.BuildStrategyRoutine
DefaultBuildOrderStrategy = v1.BuildOrderStrategyDependencies
@@ -49,6 +49,17 @@ const (
DefaultMaxRunningBuildsRoutineStrategy = 3
)
+var BuilderServiceAccount = getBuilderServiceAccount()
+
+func getBuilderServiceAccount() string {
+ bsa := os.Getenv("BUILDER_SA")
+ if bsa == "" {
+ bsa = "camel-k-builder"
+ }
+
+ return bsa
+}
+
// ConfigureDefaults fills with default values all missing details about the integration platform.
// Defaults are set in the status fields, not in the spec.
//
diff --git a/pkg/platform/operator.go b/pkg/platform/operator.go
index ad9275a67..16aa0c863 100644
--- a/pkg/platform/operator.go
+++ b/pkg/platform/operator.go
@@ -150,20 +150,7 @@ func IsOperatorHandler(object ctrl.Object) bool {
return true
}
- // check if we are dealing with resource that is missing a proper operator id annotation
- if resourceID == "" {
- // allow default global operator to handle legacy resources (missing proper operator id annotations)
- if operatorID == DefaultPlatformName {
- return true
- }
-
- // allow local operators to handle legacy resources (missing proper operator id annotations)
- if !IsCurrentOperatorGlobal() {
- return true
- }
- }
-
- return false
+ return resourceID == ""
}
// IsOperatorHandlerConsideringLock uses normal IsOperatorHandler checks and adds additional check for legacy resources
diff --git a/pkg/resources/config/manager/kustomization.yaml b/pkg/resources/config/manager/kustomization.yaml
index a4543333a..b067e2c33 100644
--- a/pkg/resources/config/manager/kustomization.yaml
+++ b/pkg/resources/config/manager/kustomization.yaml
@@ -28,3 +28,13 @@ patches:
target:
kind: Deployment
name: camel-k-operator
+
+replacements:
+ - source:
+ kind: Deployment
+ fieldPath: spec.template.spec.containers.[name=camel-k-operator].image
+ targets:
+ - select:
+ kind: Deployment
+ fieldPaths:
+ - spec.template.spec.containers.[name=camel-k-operator].env.[name=CONTAINER_IMAGE].value
diff --git a/pkg/resources/config/manager/operator-deployment.yaml b/pkg/resources/config/manager/operator-deployment.yaml
index d395d64ab..1331ea35d 100644
--- a/pkg/resources/config/manager/operator-deployment.yaml
+++ b/pkg/resources/config/manager/operator-deployment.yaml
@@ -77,6 +77,12 @@ spec:
# Note: remove the variable to disable the feature.
- name: CAMEL_MONITOR_OPERATOR_LABEL
value: "camel.apache.org/monitor"
+ # Used to query which is the image this operator is running
+ - name: CONTAINER_IMAGE
+ value: ""
+ # You can provide a different SA for builder Pods
+ - name: BUILDER_SA
+ value: "camel-k-builder"
# Attempt to read bootstrap configuration from configmap or secret
envFrom:
- configMapRef:
diff --git a/pkg/util/gitops/gitops.go b/pkg/util/gitops/gitops.go
index 16b4f40d1..c16214216 100644
--- a/pkg/util/gitops/gitops.go
+++ b/pkg/util/gitops/gitops.go
@@ -123,6 +123,7 @@ func cloneAnnotations(ann map[string]string, operatorID string) map[string]strin
if k == "kubectl.kubernetes.io/last-applied-configuration" {
continue
}
+ //nolint:staticcheck
if k == v1.OperatorIDAnnotation {
if operatorID != "" {
newMap[v1.OperatorIDAnnotation] = operatorID
@@ -132,6 +133,7 @@ func cloneAnnotations(ann map[string]string, operatorID string) map[string]strin
newMap[k] = v
}
}
+ //nolint:staticcheck
if !operatorIDAnnotationSet && operatorID != "" {
newMap[v1.OperatorIDAnnotation] = operatorID
}
@@ -213,6 +215,7 @@ func AppendKustomizeIntegration(dstIt *v1.Integration, destinationDir string, ov
baseIt := dstIt.DeepCopy()
baseIt.Namespace = ""
if baseIt.Annotations != nil {
+ //nolint:staticcheck
delete(baseIt.Annotations, v1.OperatorIDAnnotation)
}
appFolderName := strings.ToLower(baseIt.Name)
@@ -417,6 +420,7 @@ func AppendKustomizePipe(dstPipe *v1.Pipe, destinationDir string, overwrite bool
basePipe := dstPipe.DeepCopy()
basePipe.Namespace = ""
if basePipe.Annotations != nil {
+ //nolint:staticcheck
delete(basePipe.Annotations, v1.OperatorIDAnnotation)
}
appFolderName := strings.ToLower(basePipe.Name)
diff --git a/script/Makefile b/script/Makefile
index 8753ad6bf..f1acf5ed8 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -804,7 +804,7 @@ install-k8s-global: KUSTOMIZE_DIR="install/overlays/kubernetes/descoped"
install-k8s-global: clone-kustomize-dir set-operator-id set-operator-env install-operator
install-k8s-ns: DEFAULT_NS="default"
-install-k8s-ns: KUSTOMIZE_DIR="install/overlays/kubernetes/namespaced"
+install-k8s-ns: KUSTOMIZE_DIR="install/overlays/kubernetes/own-namespace"
install-k8s-ns: clone-kustomize-dir set-operator-id set-operator-env install-operator
install-registry: NAMESPACE="camel-k"