From d44546bc8608524960ea26b2d3bbba10fad62e69 Mon Sep 17 00:00:00 2001 From: Anatolii Bazko Date: Sat, 9 Oct 2021 09:27:27 +0300 Subject: [PATCH] fix: import ca-bunle even if there are several checluster CR (non all-namespace mode) (#1135) Signed-off-by: Anatolii Bazko --- controllers/che/checluster_controller.go | 67 +---- controllers/che/cheobj_verifier.go | 96 +++++++ controllers/che/cheobj_verifier_test.go | 236 ++++++++++++++++++ .../checlusterbackup/backup_context.go | 2 +- .../checlusterrestore/backup_data_restorer.go | 2 +- .../checlusterrestore/restore_context.go | 2 +- pkg/deploy/tls.go | 4 +- pkg/util/checluster_util.go | 43 ++++ pkg/util/checluster_util_test.go | 136 ++++++++++ pkg/util/util.go | 27 -- 10 files changed, 517 insertions(+), 98 deletions(-) create mode 100644 controllers/che/cheobj_verifier.go create mode 100644 controllers/che/cheobj_verifier_test.go create mode 100644 pkg/util/checluster_util.go create mode 100644 pkg/util/checluster_util_test.go diff --git a/controllers/che/checluster_controller.go b/controllers/che/checluster_controller.go index 3c9e275cd..9cc8c396d 100644 --- a/controllers/che/checluster_controller.go +++ b/controllers/che/checluster_controller.go @@ -37,7 +37,6 @@ import ( corev1 "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/discovery" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -137,7 +136,7 @@ func (r *CheClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { } var toTrustedBundleConfigMapRequestMapper handler.MapFunc = func(obj client.Object) []ctrl.Request { - isTrusted, reconcileRequest := isTrustedBundleConfigMap(mgr, obj) + isTrusted, reconcileRequest := IsTrustedBundleConfigMap(r.nonCachedClient, r.namespace, obj) if isTrusted { return []ctrl.Request{reconcileRequest} } @@ -145,7 +144,7 @@ func (r *CheClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { } var toEclipseCheRelatedObjRequestMapper handler.MapFunc = func(obj client.Object) []ctrl.Request { - isEclipseCheRelatedObj, reconcileRequest := isEclipseCheRelatedObj(mgr, obj) + isEclipseCheRelatedObj, reconcileRequest := IsEclipseCheRelatedObj(r.nonCachedClient, r.namespace, obj) if isEclipseCheRelatedObj { return []ctrl.Request{reconcileRequest} } @@ -654,43 +653,6 @@ func (r *CheClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, nil } -// isTrustedBundleConfigMap detects whether given config map is the config map with additional CA certificates to be trusted by Che -func isTrustedBundleConfigMap(mgr ctrl.Manager, obj client.Object) (bool, ctrl.Request) { - checlusters := &orgv1.CheClusterList{} - if err := mgr.GetClient().List(context.TODO(), checlusters, &client.ListOptions{}); err != nil { - return false, ctrl.Request{} - } - - if len(checlusters.Items) != 1 { - return false, ctrl.Request{} - } - - // Check if config map is the config map from CR - if checlusters.Items[0].Spec.Server.ServerTrustStoreConfigMapName != obj.GetName() { - // No, it is not form CR - // Check for labels - - // Check for part of Che label - if value, exists := obj.GetLabels()[deploy.KubernetesPartOfLabelKey]; !exists || value != deploy.CheEclipseOrg { - // Labels do not match - return false, ctrl.Request{} - } - - // Check for CA bundle label - if value, exists := obj.GetLabels()[deploy.CheCACertsConfigMapLabelKey]; !exists || value != deploy.CheCACertsConfigMapLabelValue { - // Labels do not match - return false, ctrl.Request{} - } - } - - return true, ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: checlusters.Items[0].Namespace, - Name: checlusters.Items[0].Name, - }, - } -} - func (r *CheClusterReconciler) autoEnableOAuth(deployContext *deploy.DeployContext, request ctrl.Request, isOpenShift4 bool) (reconcile.Result, error) { var message, reason string oauth := false @@ -769,31 +731,6 @@ func (r *CheClusterReconciler) autoEnableOAuth(deployContext *deploy.DeployConte return reconcile.Result{}, nil } -// isEclipseCheRelatedObj indicates if there is a object with -// the label 'app.kubernetes.io/part-of=che.eclipse.org' in a che namespace -func isEclipseCheRelatedObj(mgr ctrl.Manager, obj client.Object) (bool, ctrl.Request) { - checlusters := &orgv1.CheClusterList{} - if err := mgr.GetClient().List(context.TODO(), checlusters, &client.ListOptions{}); err != nil { - return false, ctrl.Request{} - } - - if len(checlusters.Items) != 1 { - return false, ctrl.Request{} - } - - if value, exists := obj.GetLabels()[deploy.KubernetesPartOfLabelKey]; !exists || value != deploy.CheEclipseOrg { - // Labels do not match - return false, ctrl.Request{} - } - - return true, ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: checlusters.Items[0].Namespace, - Name: checlusters.Items[0].Name, - }, - } -} - func (r *CheClusterReconciler) reconcileFinalizers(deployContext *deploy.DeployContext) { if util.IsOpenShift && util.IsOAuthEnabled(deployContext.CheCluster) { if err := deploy.ReconcileOAuthClientFinalizer(deployContext); err != nil { diff --git a/controllers/che/cheobj_verifier.go b/controllers/che/cheobj_verifier.go new file mode 100644 index 000000000..75bd66ba6 --- /dev/null +++ b/controllers/che/cheobj_verifier.go @@ -0,0 +1,96 @@ +// +// Copyright (c) 2012-2019 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// +package che + +import ( + "github.com/eclipse-che/che-operator/pkg/deploy" + "github.com/eclipse-che/che-operator/pkg/util" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// IsTrustedBundleConfigMap detects whether given config map is the config map with additional CA certificates to be trusted by Che +func IsTrustedBundleConfigMap(cl client.Client, watchNamespace string, obj client.Object) (bool, ctrl.Request) { + if obj.GetNamespace() == "" { + // ignore cluster scope objects + return false, ctrl.Request{} + } + + checluster, num, _ := util.FindCheClusterCRInNamespace(cl, watchNamespace) + if num != 1 { + logrus.Warn("More than one checluster Custom Resource found.") + return false, ctrl.Request{} + } + + if checluster.Namespace != obj.GetNamespace() { + // ignore object in another namespace + return false, ctrl.Request{} + } + + // Check if config map is the config map from CR + if checluster.Spec.Server.ServerTrustStoreConfigMapName != obj.GetName() { + // No, it is not form CR + + // Check for component + if value, exists := obj.GetLabels()[deploy.KubernetesComponentLabelKey]; !exists || value != deploy.CheCACertsConfigMapLabelValue { + // Labels do not match + return false, ctrl.Request{} + } + + // Check for part-of + if value, exists := obj.GetLabels()[deploy.KubernetesPartOfLabelKey]; !exists || value != deploy.CheEclipseOrg { + // ignore not matched labels + return false, ctrl.Request{} + } + } + + return true, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: checluster.Namespace, + Name: checluster.Name, + }, + } +} + +// isEclipseCheRelatedObj indicates if there is a object with +// the label 'app.kubernetes.io/part-of=che.eclipse.org' in a che namespace +func IsEclipseCheRelatedObj(cl client.Client, watchNamespace string, obj client.Object) (bool, ctrl.Request) { + if value, exists := obj.GetLabels()[deploy.KubernetesPartOfLabelKey]; !exists || value != deploy.CheEclipseOrg { + // ignore not matched labels + return false, ctrl.Request{} + } + + if obj.GetNamespace() == "" { + // ignore cluster scope objects + return false, ctrl.Request{} + } + + checluster, num, _ := util.FindCheClusterCRInNamespace(cl, watchNamespace) + if num != 1 { + logrus.Warn("More than one checluster Custom Resource found.") + return false, ctrl.Request{} + } + + if checluster.Namespace != obj.GetNamespace() { + // ignore object in another namespace + return false, ctrl.Request{} + } + + return true, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: checluster.Namespace, + Name: checluster.Name, + }, + } +} diff --git a/controllers/che/cheobj_verifier_test.go b/controllers/che/cheobj_verifier_test.go new file mode 100644 index 000000000..5e9a833b7 --- /dev/null +++ b/controllers/che/cheobj_verifier_test.go @@ -0,0 +1,236 @@ +// +// Copyright (c) 2012-2019 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// +package che + +import ( + "testing" + + orgv1 "github.com/eclipse-che/che-operator/api/v1" + "github.com/eclipse-che/che-operator/pkg/deploy" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func TestIsTrustedBundleConfigMap(t *testing.T) { + type testCase struct { + name string + initObjects []runtime.Object + checluster *orgv1.CheCluster + objNamespace string + objLabels map[string]string + watchNamespace string + expectedIsEclipseCheObj bool + } + + testObject := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"app.kubernetes.io/part-of": "che.eclipse.org", "app.kubernetes.io/component": "ca-bundle"}, + }, + } + + testCases := []testCase{ + { + name: "Cluster scope object", + initObjects: []runtime.Object{}, + objNamespace: "", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: false, + }, + { + name: "Object in 'eclipse-che' namespace", + initObjects: []runtime.Object{}, + objNamespace: "eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: true, + }, + { + name: "Object in 'eclipse-che' namespace, not ca-bundle component", + initObjects: []runtime.Object{}, + objLabels: map[string]string{"app.kubernetes.io/part-of": "che.eclipse.org"}, + objNamespace: "eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: false, + }, + { + name: "Object in 'eclipse-che' namespace, not ca-bundle component, but trusted configmap", + initObjects: []runtime.Object{}, + checluster: &orgv1.CheCluster{ + ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "eclipse-che"}, + Spec: orgv1.CheClusterSpec{ + Server: orgv1.CheClusterSpecServer{ + ServerTrustStoreConfigMapName: "test", + }, + }, + }, + objLabels: map[string]string{}, + objNamespace: "eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: true, + }, + { + name: "Object in another namespace than 'eclipse-che'", + initObjects: []runtime.Object{}, + objNamespace: "test-eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: false, + }, + { + name: "Object in 'eclipse-che' namespace, several checluster CR", + initObjects: []runtime.Object{ + // checluster CR in `default` namespace + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "default"}}, + }, + objNamespace: "eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: true, + }, + { + name: "Cluster scope object, all-namespaces mode", + initObjects: []runtime.Object{}, + objNamespace: "", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: false, + }, + { + name: "Object in 'eclipse-che' namespace, all-namespaces mode", + initObjects: []runtime.Object{}, + objNamespace: "eclipse-che", + watchNamespace: "", + expectedIsEclipseCheObj: true, + }, + { + name: "Object in another namespace than 'eclipse-che', all-namespaces mode", + initObjects: []runtime.Object{}, + objNamespace: "test-eclipse-che", + watchNamespace: "", + expectedIsEclipseCheObj: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + deployContext := deploy.GetTestDeployContext(testCase.checluster, testCase.initObjects) + + newTestObject := testObject.DeepCopy() + newTestObject.ObjectMeta.Namespace = testCase.objNamespace + if testCase.objLabels != nil { + newTestObject.ObjectMeta.Labels = testCase.objLabels + } + + isEclipseCheObj, req := IsTrustedBundleConfigMap(deployContext.ClusterAPI.NonCachedClient, testCase.watchNamespace, newTestObject) + + assert.Equal(t, testCase.expectedIsEclipseCheObj, isEclipseCheObj) + if isEclipseCheObj { + assert.Equal(t, req.Namespace, deployContext.CheCluster.Namespace) + assert.Equal(t, req.Name, deployContext.CheCluster.Name) + } + }) + } +} + +func TestIsEclipseCheRelatedObj(t *testing.T) { + type testCase struct { + name string + initObjects []runtime.Object + objNamespace string + watchNamespace string + expectedIsEclipseCheObj bool + } + + testObject := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"app.kubernetes.io/part-of": "che.eclipse.org"}, + }, + } + + testCases := []testCase{ + { + name: "Cluster scope object", + initObjects: []runtime.Object{}, + objNamespace: "", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: false, + }, + { + name: "Object in 'eclipse-che' namespace", + initObjects: []runtime.Object{}, + objNamespace: "eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: true, + }, + { + name: "Object in another namespace than 'eclipse-che'", + initObjects: []runtime.Object{}, + objNamespace: "test-eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: false, + }, + { + name: "Object in 'eclipse-che' namespace, several checluster CR", + initObjects: []runtime.Object{ + // checluster CR in `default` namespace + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "default"}}, + }, + objNamespace: "eclipse-che", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: true, + }, + { + name: "Cluster scope object, all-namespaces mode", + initObjects: []runtime.Object{}, + objNamespace: "", + watchNamespace: "eclipse-che", + expectedIsEclipseCheObj: false, + }, + { + name: "Object in 'eclipse-che' namespace, all-namespaces mode", + initObjects: []runtime.Object{}, + objNamespace: "eclipse-che", + watchNamespace: "", + expectedIsEclipseCheObj: true, + }, + { + name: "Object in another namespace than 'eclipse-che', all-namespaces mode", + initObjects: []runtime.Object{}, + objNamespace: "test-eclipse-che", + watchNamespace: "", + expectedIsEclipseCheObj: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + deployContext := deploy.GetTestDeployContext(nil, testCase.initObjects) + + testObject.ObjectMeta.Namespace = testCase.objNamespace + isEclipseCheObj, req := IsEclipseCheRelatedObj(deployContext.ClusterAPI.NonCachedClient, testCase.watchNamespace, testObject) + + assert.Equal(t, testCase.expectedIsEclipseCheObj, isEclipseCheObj) + if isEclipseCheObj { + assert.Equal(t, req.Namespace, deployContext.CheCluster.Namespace) + assert.Equal(t, req.Name, deployContext.CheCluster.Name) + } + }) + } +} diff --git a/controllers/checlusterbackup/backup_context.go b/controllers/checlusterbackup/backup_context.go index 9c18b540c..59de05a89 100644 --- a/controllers/checlusterbackup/backup_context.go +++ b/controllers/checlusterbackup/backup_context.go @@ -48,7 +48,7 @@ func NewBackupContext(r *ReconcileCheClusterBackup, backupCR *chev1.CheClusterBa // After the preparations, a new reconcile loop will be triggered, so backupServer will not be nil any more. } - cheCR, _, err := util.FindCheCRinNamespace(r.client, namespace) + cheCR, _, err := util.FindCheClusterCRInNamespace(r.client, namespace) if err != nil { return nil, err } diff --git a/controllers/checlusterrestore/backup_data_restorer.go b/controllers/checlusterrestore/backup_data_restorer.go index f18c4d204..a85ddd6ff 100644 --- a/controllers/checlusterrestore/backup_data_restorer.go +++ b/controllers/checlusterrestore/backup_data_restorer.go @@ -124,7 +124,7 @@ func cleanPreviousInstallation(rctx *RestoreContext, dataDir string) (bool, erro } // Delete Che CR to stop operator from dealing with current installation - actualCheCR, cheCRCount, err := util.FindCheCRinNamespace(rctx.r.client, rctx.namespace) + actualCheCR, cheCRCount, err := util.FindCheClusterCRInNamespace(rctx.r.client, rctx.namespace) if cheCRCount == -1 { // error occurred while retreiving CheCluster CR return false, err diff --git a/controllers/checlusterrestore/restore_context.go b/controllers/checlusterrestore/restore_context.go index 54e191993..c2659e98c 100644 --- a/controllers/checlusterrestore/restore_context.go +++ b/controllers/checlusterrestore/restore_context.go @@ -38,7 +38,7 @@ func NewRestoreContext(r *ReconcileCheClusterRestore, restoreCR *chev1.CheCluste return nil, err } - cheCR, CRCount, err := util.FindCheCRinNamespace(r.client, namespace) + cheCR, CRCount, err := util.FindCheClusterCRInNamespace(r.client, namespace) if err != nil { // Check if Che CR is present if CRCount > 0 { diff --git a/pkg/deploy/tls.go b/pkg/deploy/tls.go index 1a5f5f123..8e038cf94 100644 --- a/pkg/deploy/tls.go +++ b/pkg/deploy/tls.go @@ -47,8 +47,6 @@ const ( CheTLSSelfSignedCertificateSecretName = "self-signed-certificate" DefaultCheTLSSecretName = "che-tls" - // CheCACertsConfigMapLabelKey is the label key which marks config map with additional CA certificates - CheCACertsConfigMapLabelKey = "app.kubernetes.io/component" // CheCACertsConfigMapLabelKey is the label value which marks config map with additional CA certificates CheCACertsConfigMapLabelValue = "ca-bundle" // CheAllCACertsConfigMapName is the name of config map which contains all additional trusted by Che TLS CA certificates @@ -591,7 +589,7 @@ func SyncAdditionalCACertsConfigMapToCluster(deployContext *DeployContext) (bool func GetCACertsConfigMaps(deployContext *DeployContext) ([]corev1.ConfigMap, error) { CACertsConfigMapList := &corev1.ConfigMapList{} - caBundleLabelSelectorRequirement, _ := labels.NewRequirement(CheCACertsConfigMapLabelKey, selection.Equals, []string{CheCACertsConfigMapLabelValue}) + caBundleLabelSelectorRequirement, _ := labels.NewRequirement(KubernetesComponentLabelKey, selection.Equals, []string{CheCACertsConfigMapLabelValue}) cheComponetLabelSelectorRequirement, _ := labels.NewRequirement(KubernetesPartOfLabelKey, selection.Equals, []string{CheEclipseOrg}) listOptions := &client.ListOptions{ LabelSelector: labels.NewSelector().Add(*cheComponetLabelSelectorRequirement).Add(*caBundleLabelSelectorRequirement), diff --git a/pkg/util/checluster_util.go b/pkg/util/checluster_util.go new file mode 100644 index 000000000..4ca006016 --- /dev/null +++ b/pkg/util/checluster_util.go @@ -0,0 +1,43 @@ +// +// Copyright (c) 2012-2019 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// +package util + +import ( + "context" + "fmt" + + orgv1 "github.com/eclipse-che/che-operator/api/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Finds checluster custom resource in a given namespace. +// If namespace is empty then checluster will be found in any namespace. +func FindCheClusterCRInNamespace(cl client.Client, namespace string) (*orgv1.CheCluster, int, error) { + cheClusters := &orgv1.CheClusterList{} + listOptions := &client.ListOptions{Namespace: namespace} + if err := cl.List(context.TODO(), cheClusters, listOptions); err != nil { + return nil, -1, err + } + + if len(cheClusters.Items) != 1 { + return nil, len(cheClusters.Items), fmt.Errorf("Expected one instance of CheCluster custom resources, but '%d' found.", len(cheClusters.Items)) + } + + checluster := &orgv1.CheCluster{} + namespacedName := types.NamespacedName{Namespace: cheClusters.Items[0].GetNamespace(), Name: cheClusters.Items[0].GetName()} + err := cl.Get(context.TODO(), namespacedName, checluster) + if err != nil { + return nil, -1, err + } + return checluster, 1, nil +} diff --git a/pkg/util/checluster_util_test.go b/pkg/util/checluster_util_test.go new file mode 100644 index 000000000..21415f256 --- /dev/null +++ b/pkg/util/checluster_util_test.go @@ -0,0 +1,136 @@ +// +// Copyright (c) 2012-2021 Red Hat, Inc. +// This program and the accompanying materials are made +// available under the terms of the Eclipse Public License 2.0 +// which is available at https://www.eclipse.org/legal/epl-2.0/ +// +// SPDX-License-Identifier: EPL-2.0 +// +// Contributors: +// Red Hat, Inc. - initial API and implementation +// +package util + +import ( + "testing" + + orgv1 "github.com/eclipse-che/che-operator/api/v1" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func TestFindCheCRinNamespace(t *testing.T) { + type testCase struct { + name string + initObjects []runtime.Object + watchNamespace string + expectedNumber int + expectedNamespace string + expectedErr bool + } + + testCases := []testCase{ + { + name: "CR in 'eclipse-che' namespace", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "eclipse-che"}}, + }, + watchNamespace: "eclipse-che", + expectedNumber: 1, + expectedErr: false, + expectedNamespace: "eclipse-che", + }, + { + name: "CR in 'default' namespace", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "default"}}, + }, + watchNamespace: "eclipse-che", + expectedNumber: 0, + expectedErr: true, + }, + { + name: "several CR in 'eclipse-che' namespace", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "eclipse-che"}}, + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "test-eclipse-che", Namespace: "eclipse-che"}}, + }, + watchNamespace: "eclipse-che", + expectedNumber: 2, + expectedErr: true, + }, + { + name: "several CR in different namespaces", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "eclipse-che"}}, + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "default"}}, + }, + watchNamespace: "eclipse-che", + expectedNumber: 1, + expectedErr: false, + expectedNamespace: "eclipse-che", + }, + { + name: "CR in 'eclipse-che' namespace, all-namespace mode", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "eclipse-che"}}, + }, + watchNamespace: "", + expectedNumber: 1, + expectedErr: false, + expectedNamespace: "eclipse-che", + }, + { + name: "CR in 'default' namespace, all-namespace mode", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "default"}}, + }, + watchNamespace: "", + expectedNumber: 1, + expectedErr: false, + expectedNamespace: "default", + }, + { + name: "several CR in 'eclipse-che' namespace, all-namespace mode", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "eclipse-che"}}, + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "test-eclipse-che", Namespace: "eclipse-che"}}, + }, + watchNamespace: "", + expectedNumber: 2, + expectedErr: true, + }, + { + name: "several CR in different namespaces, all-namespace mode", + initObjects: []runtime.Object{ + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "eclipse-che"}}, + &orgv1.CheCluster{ObjectMeta: metav1.ObjectMeta{Name: "eclipse-che", Namespace: "default"}}, + }, + watchNamespace: "", + expectedNumber: 2, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + scheme := scheme.Scheme + orgv1.SchemeBuilder.AddToScheme(scheme) + cli := fake.NewFakeClientWithScheme(scheme, testCase.initObjects...) + + checluster, num, err := FindCheClusterCRInNamespace(cli, testCase.watchNamespace) + assert.Equal(t, testCase.expectedNumber, num) + if testCase.expectedErr { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + } + if num == 1 { + assert.Equal(t, testCase.expectedNamespace, checluster.Namespace) + } + }) + } +} diff --git a/pkg/util/util.go b/pkg/util/util.go index 01524ce05..6843b8c61 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -561,33 +561,6 @@ func ComputeHash256(data []byte) string { return base64.URLEncoding.EncodeToString(hasher.Sum(nil)) } -func ReloadCheCluster(client client.Client, cheCluster *orgv1.CheCluster) error { - return client.Get( - context.TODO(), - types.NamespacedName{Name: cheCluster.Name, Namespace: cheCluster.Namespace}, - cheCluster) -} - -func FindCheCRinNamespace(cl client.Client, namespace string) (*orgv1.CheCluster, int, error) { - cheClusters := &orgv1.CheClusterList{} - listOptions := &client.ListOptions{Namespace: namespace} - if err := cl.List(context.TODO(), cheClusters, listOptions); err != nil { - return nil, -1, err - } - - if len(cheClusters.Items) != 1 { - return nil, len(cheClusters.Items), fmt.Errorf("expected an instance of CheCluster, but got %d instances", len(cheClusters.Items)) - } - - cheCR := &orgv1.CheCluster{} - namespacedName := types.NamespacedName{Namespace: namespace, Name: cheClusters.Items[0].GetName()} - err := cl.Get(context.TODO(), namespacedName, cheCR) - if err != nil { - return nil, -1, err - } - return cheCR, 1, nil -} - func UpdateBackupServerConfiguration(client client.Client, backupServerConfig *orgv1.CheBackupServerConfiguration) error { err := client.Update(context.TODO(), backupServerConfig) if err != nil {