You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2020/11/03 23:40:54 UTC

[camel-k] branch master updated: Fix #751: add guard to global operator

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 9dac8ad  Fix #751: add guard to global operator
9dac8ad is described below

commit 9dac8adb53471364b81f72f10ace1233e38c444d
Author: nicolaferraro <ni...@gmail.com>
AuthorDate: Mon Nov 2 16:25:12 2020 +0100

    Fix #751: add guard to global operator
---
 e2e/builder/global_test.go                         | 19 ++++++++++++-
 pkg/cmd/operator/operator.go                       |  3 +-
 pkg/controller/build/build_controller.go           |  8 ++++++
 .../integration/integration_controller.go          |  9 ++++++
 .../integrationkit/integrationkit_controller.go    |  8 ++++++
 .../integrationplatform_controller.go              |  9 ++++++
 pkg/controller/kamelet/kamelet_controller.go       |  9 ++++++
 .../kameletbinding/kamelet_binding_controller.go   |  9 ++++++
 pkg/platform/operator.go                           | 33 ++++++++++++++++++++++
 9 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/e2e/builder/global_test.go b/e2e/builder/global_test.go
index 8d38d85..f257149 100644
--- a/e2e/builder/global_test.go
+++ b/e2e/builder/global_test.go
@@ -26,6 +26,7 @@ import (
 	"testing"
 
 	. "github.com/apache/camel-k/e2e/support"
+	"github.com/apache/camel-k/pkg/platform"
 	"github.com/apache/camel-k/pkg/util/openshift"
 	. "github.com/onsi/gomega"
 	"github.com/stretchr/testify/assert"
@@ -46,7 +47,7 @@ func TestRunGlobalInstall(t *testing.T) {
 	WithNewTestNamespace(t, func(ns string) {
 		Expect(Kamel("install", "-n", ns, "--global").Execute()).Should(BeNil())
 
-		// NS2
+		// NS2: namespace without operator
 		WithNewTestNamespace(t, func(ns2 string) {
 			Expect(Kamel("install", "-n", ns2, "--skip-operator-setup", "--olm=false").Execute()).Should(BeNil())
 
@@ -54,6 +55,22 @@ func TestRunGlobalInstall(t *testing.T) {
 			Eventually(IntegrationPodPhase(ns2, "java"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
 			Eventually(IntegrationLogs(ns2, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
 			Expect(Kamel("delete", "--all", "-n", ns2).Execute()).Should(BeNil())
+
+			Expect(ConfigMap(ns2, platform.OperatorLockName)()).Should(BeNil(), "No locking configmap expected")
+		})
+
+		// NS3: namespace with its own operator
+		WithNewTestNamespace(t, func(ns3 string) {
+			Expect(Kamel("install", "-n", ns3, "--olm=false").Execute()).Should(BeNil())
+
+			Expect(Kamel("run", "-n", ns3, "files/Java.java").Execute()).Should(BeNil())
+			Eventually(IntegrationPodPhase(ns3, "java"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
+			Eventually(IntegrationLogs(ns3, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+			Expect(Kamel("delete", "--all", "-n", ns3).Execute()).Should(BeNil())
+
+			Expect(ConfigMap(ns3, platform.OperatorLockName)()).ShouldNot(BeNil(),
+				"OperatorSDK is expected to use configmaps for locking: if this changes (e.g. using Leases) we should update our guard logic",
+			)
 		})
 
 		Expect(Kamel("uninstall", "-n", ns, "--skip-crd", "--skip-cluster-roles").Execute()).Should(BeNil())
diff --git a/pkg/cmd/operator/operator.go b/pkg/cmd/operator/operator.go
index 9eec07e..b11c021 100644
--- a/pkg/cmd/operator/operator.go
+++ b/pkg/cmd/operator/operator.go
@@ -26,6 +26,7 @@ import (
 	"runtime"
 	"time"
 
+	"github.com/apache/camel-k/pkg/platform"
 	corev1 "k8s.io/api/core/v1"
 	typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
 	"k8s.io/client-go/tools/record"
@@ -91,7 +92,7 @@ func Run() {
 	}
 
 	// Become the leader before proceeding
-	err = leader.Become(context.TODO(), "camel-k-lock")
+	err = leader.Become(context.TODO(), platform.OperatorLockName)
 	if err != nil {
 		if err == leader.ErrNoNamespace {
 			log.Info("Local run detected, leader election is disabled")
diff --git a/pkg/controller/build/build_controller.go b/pkg/controller/build/build_controller.go
index d9e771f..30a0e04 100644
--- a/pkg/controller/build/build_controller.go
+++ b/pkg/controller/build/build_controller.go
@@ -138,6 +138,14 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result,
 
 	ctx := context.TODO()
 
+	// Make sure the operator is allowed to act on namespace
+	if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil {
+		return reconcile.Result{}, err
+	} else if !ok {
+		rlog.Info("Ignoring request because namespace is locked")
+		return reconcile.Result{}, nil
+	}
+
 	// Fetch the Build instance
 	var instance v1.Build
 
diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go
index 8170a37..3d94b87 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -21,6 +21,7 @@ import (
 	"context"
 
 	camelevent "github.com/apache/camel-k/pkg/event"
+	"github.com/apache/camel-k/pkg/platform"
 	appsv1 "k8s.io/api/apps/v1"
 	"k8s.io/api/batch/v1beta1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -236,6 +237,14 @@ func (r *ReconcileIntegration) Reconcile(request reconcile.Request) (reconcile.R
 
 	ctx := context.TODO()
 
+	// Make sure the operator is allowed to act on namespace
+	if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil {
+		return reconcile.Result{}, err
+	} else if !ok {
+		rlog.Info("Ignoring request because namespace is locked")
+		return reconcile.Result{}, nil
+	}
+
 	// Fetch the Integration instance
 	var instance v1.Integration
 
diff --git a/pkg/controller/integrationkit/integrationkit_controller.go b/pkg/controller/integrationkit/integrationkit_controller.go
index d16def6..aaa87fe 100644
--- a/pkg/controller/integrationkit/integrationkit_controller.go
+++ b/pkg/controller/integrationkit/integrationkit_controller.go
@@ -171,6 +171,14 @@ func (r *ReconcileIntegrationKit) Reconcile(request reconcile.Request) (reconcil
 
 	ctx := context.TODO()
 
+	// Make sure the operator is allowed to act on namespace
+	if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil {
+		return reconcile.Result{}, err
+	} else if !ok {
+		rlog.Info("Ignoring request because namespace is locked")
+		return reconcile.Result{}, nil
+	}
+
 	var instance v1.IntegrationKit
 
 	// Fetch the IntegrationKit instance
diff --git a/pkg/controller/integrationplatform/integrationplatform_controller.go b/pkg/controller/integrationplatform/integrationplatform_controller.go
index 6412ba7..9a0d99d 100644
--- a/pkg/controller/integrationplatform/integrationplatform_controller.go
+++ b/pkg/controller/integrationplatform/integrationplatform_controller.go
@@ -22,6 +22,7 @@ import (
 	"time"
 
 	camelevent "github.com/apache/camel-k/pkg/event"
+	"github.com/apache/camel-k/pkg/platform"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/tools/record"
@@ -111,6 +112,14 @@ func (r *ReconcileIntegrationPlatform) Reconcile(request reconcile.Request) (rec
 
 	ctx := context.TODO()
 
+	// Make sure the operator is allowed to act on namespace
+	if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil {
+		return reconcile.Result{}, err
+	} else if !ok {
+		rlog.Info("Ignoring request because namespace is locked")
+		return reconcile.Result{}, nil
+	}
+
 	// Fetch the IntegrationPlatform instance
 	var instance v1.IntegrationPlatform
 
diff --git a/pkg/controller/kamelet/kamelet_controller.go b/pkg/controller/kamelet/kamelet_controller.go
index 0522a59..22d7548 100644
--- a/pkg/controller/kamelet/kamelet_controller.go
+++ b/pkg/controller/kamelet/kamelet_controller.go
@@ -24,6 +24,7 @@ import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/client"
 	camelevent "github.com/apache/camel-k/pkg/event"
+	"github.com/apache/camel-k/pkg/platform"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/tools/record"
@@ -109,6 +110,14 @@ func (r *ReconcileKamelet) Reconcile(request reconcile.Request) (reconcile.Resul
 
 	ctx := context.TODO()
 
+	// Make sure the operator is allowed to act on namespace
+	if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil {
+		return reconcile.Result{}, err
+	} else if !ok {
+		rlog.Info("Ignoring request because namespace is locked")
+		return reconcile.Result{}, nil
+	}
+
 	// Fetch the Kamelet instance
 	var instance v1alpha1.Kamelet
 
diff --git a/pkg/controller/kameletbinding/kamelet_binding_controller.go b/pkg/controller/kameletbinding/kamelet_binding_controller.go
index dbebfc3..bbc84cb 100644
--- a/pkg/controller/kameletbinding/kamelet_binding_controller.go
+++ b/pkg/controller/kameletbinding/kamelet_binding_controller.go
@@ -25,6 +25,7 @@ import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/client"
 	camelevent "github.com/apache/camel-k/pkg/event"
+	"github.com/apache/camel-k/pkg/platform"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/tools/record"
@@ -119,6 +120,14 @@ func (r *ReconcileKameletBinding) Reconcile(request reconcile.Request) (reconcil
 
 	ctx := context.TODO()
 
+	// Make sure the operator is allowed to act on namespace
+	if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil {
+		return reconcile.Result{}, err
+	} else if !ok {
+		rlog.Info("Ignoring request because namespace is locked")
+		return reconcile.Result{}, nil
+	}
+
 	// Fetch the KameletBinding instance
 	var instance v1alpha1.KameletBinding
 
diff --git a/pkg/platform/operator.go b/pkg/platform/operator.go
index 82ed950..d0ff38b 100644
--- a/pkg/platform/operator.go
+++ b/pkg/platform/operator.go
@@ -32,6 +32,8 @@ const operatorWatchNamespaceEnvVariable = "WATCH_NAMESPACE"
 const operatorNamespaceEnvVariable = "NAMESPACE"
 const operatorPodNameEnvVariable = "POD_NAME"
 
+const OperatorLockName = "camel-k-lock"
+
 // GetCurrentOperatorImage returns the image currently used by the running operator if present (when running out of cluster, it may be absent).
 func GetCurrentOperatorImage(ctx context.Context, c client.Client) (string, error) {
 	podNamespace := GetOperatorNamespace()
@@ -80,3 +82,34 @@ func GetOperatorPodName() string {
 	}
 	return ""
 }
+
+// IsNamespaceLocked tells if the namespace contains a lock indicating that an operator owns it
+func IsNamespaceLocked(ctx context.Context, c client.Client, namespace string) (bool, error) {
+	if namespace == "" {
+		return false, nil
+	}
+
+	cm := v1.ConfigMap{}
+	key := client.ObjectKey{
+		Namespace: namespace,
+		Name:      OperatorLockName,
+	}
+	if err := c.Get(ctx, key, &cm); err != nil && k8serrors.IsNotFound(err) {
+		return false, nil
+	} else if err != nil {
+		return true, err
+	}
+	return true, nil
+}
+
+// IsOperatorAllowedOnNamespace returns true if the current operator is allowed to react on changes in the given namespace
+func IsOperatorAllowedOnNamespace(ctx context.Context, c client.Client, namespace string) (bool, error) {
+	if !IsCurrentOperatorGlobal() {
+		return true, nil
+	}
+	alreadyOwned, err := IsNamespaceLocked(ctx, c, namespace)
+	if err != nil {
+		return false, err
+	}
+	return !alreadyOwned, nil
+}