From 954e5a64f624db68d97dd1d3d72107c0fcfc25d2 Mon Sep 17 00:00:00 2001 From: Anatolii Bazko Date: Fri, 5 Aug 2022 17:06:18 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20Improve=20a=20way=20to=20check=20if=20De?= =?UTF-8?q?vWorkspace=20resources=20must=20be=20managed=E2=80=A6=20(#1467)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Improve a way to check if DevWorkspace resources must be managed by Che Operator Signed-off-by: Anatolii Bazko --- Makefile | 3 + .../che-operator.clusterserviceversion.yaml | 6 +- pkg/common/constants/constants.go | 3 +- pkg/common/utils/utils.go | 11 + pkg/deploy/dev-workspace/dev_workspace.go | 48 +--- .../dev_workspace_syncer_test.go | 43 --- .../dev-workspace/dev_workspace_test.go | 258 ++++-------------- .../dev-workspace/dev_workspace_utils.go | 89 +++--- 8 files changed, 116 insertions(+), 345 deletions(-) diff --git a/Makefile b/Makefile index bd595dc75..16516c8c6 100644 --- a/Makefile +++ b/Makefile @@ -583,6 +583,9 @@ bundle: generate manifests download-kustomize download-operator-sdk ## Generate yq -riY '.metadata.annotations.containerImage = "'$(IMG)'"' $${CSV_PATH} yq -riY '.spec.install.spec.deployments[0].spec.template.spec.containers[0].image = "'$(IMG)'"' $${CSV_PATH} + # Add No Opt DWO environment variable + yq -riY '.spec.install.spec.deployments[0].spec.template.spec.containers[0].env += [{"name": "NO_OPT_DWO", "value": "true"}]' "$${CSV_PATH}" + # Format file yq -riY "." "$${BUNDLE_PATH}/manifests/org.eclipse.che_checlusters.yaml" diff --git a/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml b/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml index 3bc66a579..d420b07b2 100644 --- a/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml +++ b/bundle/next/eclipse-che-preview-openshift/manifests/che-operator.clusterserviceversion.yaml @@ -76,7 +76,7 @@ metadata: operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/eclipse-che/che-operator support: Eclipse Foundation - name: eclipse-che-preview-openshift.v7.52.0-642.next + name: eclipse-che-preview-openshift.v7.52.0-643.next namespace: placeholder spec: apiservicedefinitions: {} @@ -1138,6 +1138,8 @@ spec: value: "1" - name: ADD_COMPONENT_READINESS_INIT_CONTAINERS value: "false" + - name: NO_OPT_DWO + value: 'true' image: quay.io/eclipse/che-operator:next imagePullPolicy: Always livenessProbe: @@ -1390,7 +1392,7 @@ spec: maturity: stable provider: name: Eclipse Foundation - version: 7.52.0-642.next + version: 7.52.0-643.next webhookdefinitions: - admissionReviewVersions: - v1 diff --git a/pkg/common/constants/constants.go b/pkg/common/constants/constants.go index 00d9e0721..fc7595feb 100644 --- a/pkg/common/constants/constants.go +++ b/pkg/common/constants/constants.go @@ -120,8 +120,9 @@ const ( GatewayAuthenticationContainerName = "oauth-proxy" GatewayAuthorizationContainerName = "kube-rbac-proxy" - // + // common CheEclipseOrg = "che.eclipse.org" + DevWorkspaceOperator = "devworkspace-operator" InstallOrUpdateFailed = "InstallOrUpdateFailed" ) diff --git a/pkg/common/utils/utils.go b/pkg/common/utils/utils.go index a677a3379..c71b1b5fb 100644 --- a/pkg/common/utils/utils.go +++ b/pkg/common/utils/utils.go @@ -22,6 +22,9 @@ import ( "strings" "time" + "github.com/devfile/devworkspace-operator/pkg/infrastructure" + "github.com/eclipse-che/che-operator/pkg/common/test" + "k8s.io/apimachinery/pkg/labels" corev1 "k8s.io/api/core/v1" @@ -269,3 +272,11 @@ func Whitelist(hostname string) (value string) { } return hostname } + +func GetOperatorNamespace() (string, error) { + if test.IsTestMode() { + return "eclipse-che", nil + } + + return infrastructure.GetOperatorNamespace() +} diff --git a/pkg/deploy/dev-workspace/dev_workspace.go b/pkg/deploy/dev-workspace/dev_workspace.go index d0bcd3ba3..eaffbf721 100644 --- a/pkg/deploy/dev-workspace/dev_workspace.go +++ b/pkg/deploy/dev-workspace/dev_workspace.go @@ -34,14 +34,6 @@ const ( DevWorkspaceNamespace = "devworkspace-controller" DevWorkspaceDeploymentName = "devworkspace-controller-manager" DevWorkspaceWebhookName = "controller.devfile.io" - - SubscriptionResourceName = "subscriptions" - ClusterServiceVersionResourceName = "clusterserviceversions" - DevWorkspaceCSVNamePrefix = "devworkspace-operator" - - WebTerminalOperatorSubscriptionName = "web-terminal" - - OperatorNamespace = "openshift-operators" ) var ( @@ -62,19 +54,22 @@ func NewDevWorkspaceReconciler() *DevWorkspaceReconciler { } func (d *DevWorkspaceReconciler) Reconcile(ctx *chetypes.DeployContext) (reconcile.Result, bool, error) { - if isDevWorkspaceOperatorCSVExists(ctx) { - // Do nothing if DevWorkspace has been already deployed via OLM - return reconcile.Result{}, true, nil - } - if infrastructure.IsOpenShift() { - wtoInstalled, err := isWebTerminalSubscriptionExist(ctx) - if err != nil { + // Do nothing if explicitly declared not to manage Dev Workspace resources + isNoOptDWO, err := isNoOptDWO() + if isNoOptDWO { + return reconcile.Result{}, true, nil + } else if err != nil { return reconcile.Result{Requeue: true}, false, err } - if wtoInstalled { - // Do nothing if WTO exists since it should bring or embeds DWO + + // Do nothing if Dev Workspace operator has owner (installed via OLM). + // In this case Dev Workspace operator resources mustn't be managed by Che operator. + isDevWorkspaceOperatorHasOwner, err := isDevWorkspaceOperatorHasOwner(ctx) + if isDevWorkspaceOperatorHasOwner { return reconcile.Result{}, true, nil + } else if err != nil { + return reconcile.Result{Requeue: true}, false, err } } @@ -91,26 +86,9 @@ func (d *DevWorkspaceReconciler) Reconcile(ctx *chetypes.DeployContext) (reconci namespaceOwnershipAnnotation := namespace.GetAnnotations()[constants.CheEclipseOrgNamespace] if namespaceOwnershipAnnotation == "" { - // don't manage DWO if namespace is create by someone else not but not Che Operator + // don't manage DWO if namespace is created by someone else not but not Che Operator return reconcile.Result{}, true, nil } - - // if DWO is managed by another Che, check if we should take control under it after possible removal - if namespaceOwnershipAnnotation != ctx.CheCluster.Namespace { - isOnlyOneOperatorManagesDWResources, err := isOnlyOneOperatorManagesDWResources(ctx) - if err != nil { - return reconcile.Result{Requeue: true}, false, err - } - if !isOnlyOneOperatorManagesDWResources { - // Don't take a control over DWO if CheCluster in another CR is handling it - return reconcile.Result{}, true, nil - } - namespace.GetAnnotations()[constants.CheEclipseOrgNamespace] = ctx.CheCluster.Namespace - _, err = deploy.Sync(ctx, namespace) - if err != nil { - return reconcile.Result{Requeue: true}, false, err - } - } } // check if DW exists on the cluster diff --git a/pkg/deploy/dev-workspace/dev_workspace_syncer_test.go b/pkg/deploy/dev-workspace/dev_workspace_syncer_test.go index 2e1b0d1dc..9b326e15f 100644 --- a/pkg/deploy/dev-workspace/dev_workspace_syncer_test.go +++ b/pkg/deploy/dev-workspace/dev_workspace_syncer_test.go @@ -77,49 +77,6 @@ func TestShouldSyncObjectIfItWasCreatedBySameOriginHashDifferent(t *testing.T) { assert.Equal(t, "c", actual.Data["a"], "data mismatch") } -func TestShouldNotSyncObjectIfThereIsAnotherCheCluster(t *testing.T) { - cheCluster := &chev2.CheCluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: "eclipse-che", - Namespace: "eclipse-che-1", - }, - } - anotherCheCluster := &chev2.CheCluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: "eclipse-che", - Namespace: "eclipse-che-2", - }, - } - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{anotherCheCluster}) - - // creates initial object - initialObject := deploy.GetConfigMapSpec(deployContext, "test", map[string]string{"a": "b"}, "test") - initialObject.SetAnnotations(map[string]string{ - constants.CheEclipseOrgHash256: "hash-2", - constants.CheEclipseOrgNamespace: "eclipse-che-2", - }) - isCreated, err := deploy.Create(deployContext, initialObject) - assert.NoError(t, err) - assert.True(t, isCreated) - - // tries to sync object with a new hash but different origin - newObject := deploy.GetConfigMapSpec(deployContext, "test", map[string]string{"a": "c"}, "test") - newObject.GetAnnotations()[constants.CheEclipseOrgHash256] = "newHash" - isDone, err := syncObject(deployContext, newObject, "eclipse-che") - assert.NoError(t, err, "Failed to sync object") - assert.True(t, isDone, "Failed to sync object") - - // reads object and check content, object isn't supposed to be updated - actual := &corev1.ConfigMap{} - exists, err := deploy.GetNamespacedObject(deployContext, "test", actual) - assert.NoError(t, err, "failed to get configmap") - assert.True(t, exists, "configmap is not found") - - assert.Equal(t, "eclipse-che-2", actual.GetAnnotations()[constants.CheEclipseOrgNamespace], "hash annotation mismatch") - assert.Equal(t, "hash-2", actual.GetAnnotations()[constants.CheEclipseOrgHash256], "namespace annotation mismatch") - assert.Equal(t, "b", actual.Data["a"], "data mismatch") -} - func TestShouldNotSyncObjectIfHashIsEqual(t *testing.T) { deployContext := test.GetDeployContext(nil, []runtime.Object{}) diff --git a/pkg/deploy/dev-workspace/dev_workspace_test.go b/pkg/deploy/dev-workspace/dev_workspace_test.go index c49596778..145007b97 100644 --- a/pkg/deploy/dev-workspace/dev_workspace_test.go +++ b/pkg/deploy/dev-workspace/dev_workspace_test.go @@ -15,7 +15,7 @@ import ( "context" "os" - crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + defaults "github.com/eclipse-che/che-operator/pkg/common/operator-defaults" "k8s.io/apimachinery/pkg/types" k8sErrors "k8s.io/apimachinery/pkg/api/errors" @@ -27,22 +27,22 @@ import ( "github.com/eclipse-che/che-operator/pkg/common/constants" "github.com/eclipse-che/che-operator/pkg/common/test" "github.com/eclipse-che/che-operator/pkg/deploy" - operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/stretchr/testify/assert" - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - fakeDiscovery "k8s.io/client-go/discovery/fake" "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - DevWorkspaceCSVName = "devworkspace-operator.v0.11.0" -) - func TestReconcileDevWorkspace(t *testing.T) { + cheOperatorDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: defaults.GetCheFlavor() + "-operator", + Namespace: "eclipse-che", + }, + } + type testCase struct { name string infrastructure infrastructure.Type @@ -82,13 +82,9 @@ func TestReconcileDevWorkspace(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - deployContext := test.GetDeployContext(testCase.cheCluster, []runtime.Object{}) - + deployContext := test.GetDeployContext(testCase.cheCluster, []runtime.Object{cheOperatorDeployment}) infrastructure.InitializeForTesting(testCase.infrastructure) - err := os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "true") - assert.NoError(t, err) - devWorkspaceReconciler := NewDevWorkspaceReconciler() _, done, err := devWorkspaceReconciler.Reconcile(deployContext) assert.NoError(t, err, "Reconcile failed") @@ -98,13 +94,12 @@ func TestReconcileDevWorkspace(t *testing.T) { } func TestShouldReconcileDevWorkspaceIfDevWorkspaceDeploymentExists(t *testing.T) { - cheCluster := &chev2.CheCluster{ + cheOperatorDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ + Name: defaults.GetCheFlavor() + "-operator", Namespace: "eclipse-che", - Name: "eclipse-che", }, } - devworkspaceDeployment := &appsv1.Deployment{ TypeMeta: metav1.TypeMeta{ Kind: "Deployment", @@ -113,14 +108,15 @@ func TestShouldReconcileDevWorkspaceIfDevWorkspaceDeploymentExists(t *testing.T) ObjectMeta: metav1.ObjectMeta{ Name: DevWorkspaceDeploymentName, Namespace: DevWorkspaceNamespace, + Labels: map[string]string{ + constants.KubernetesPartOfLabelKey: constants.DevWorkspaceOperator, + constants.KubernetesNameLabelKey: constants.DevWorkspaceController, + }, }, } - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{devworkspaceDeployment}) - + deployContext := test.GetDeployContext(nil, []runtime.Object{devworkspaceDeployment, cheOperatorDeployment}) infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) - err := os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "false") - assert.NoError(t, err) devWorkspaceReconciler := NewDevWorkspaceReconciler() _, done, err := devWorkspaceReconciler.Reconcile(deployContext) @@ -129,112 +125,83 @@ func TestShouldReconcileDevWorkspaceIfDevWorkspaceDeploymentExists(t *testing.T) assert.True(t, done, "DevWorkspace should be reconciled.") } -func TestReconcileWhenWebTerminalSubscriptionExists(t *testing.T) { - cheCluster := &chev2.CheCluster{ +func TestShouldNotReconcileDevWorkspaceIfDevWorkspaceDeploymentManagedByOLM(t *testing.T) { + cheOperatorDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ + Name: defaults.GetCheFlavor() + "-operator", Namespace: "eclipse-che", }, } - subscription := &operatorsv1alpha1.Subscription{ + devworkspaceDeployment := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + Kind: "Deployment", + APIVersion: "apps/v1", + }, ObjectMeta: metav1.ObjectMeta{ - Name: WebTerminalOperatorSubscriptionName, - Namespace: OperatorNamespace, - }, - Spec: &operatorsv1alpha1.SubscriptionSpec{}, - } - - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{subscription}) - deployContext.ClusterAPI.Scheme.AddKnownTypes(operatorsv1alpha1.SchemeGroupVersion, &operatorsv1alpha1.Subscription{}) - deployContext.ClusterAPI.Scheme.AddKnownTypes(admissionregistrationv1.SchemeGroupVersion, &admissionregistrationv1.MutatingWebhookConfiguration{}) - deployContext.ClusterAPI.DiscoveryClient.(*fakeDiscovery.FakeDiscovery).Fake.Resources = []*metav1.APIResourceList{ - { - APIResources: []metav1.APIResource{ - {Name: SubscriptionResourceName}, + Name: DevWorkspaceDeploymentName, + Namespace: DevWorkspaceNamespace, + Labels: map[string]string{ + constants.KubernetesPartOfLabelKey: constants.DevWorkspaceOperator, + constants.KubernetesNameLabelKey: constants.DevWorkspaceController, }, + OwnerReferences: []metav1.OwnerReference{{}}, }, } + deployContext := test.GetDeployContext(nil, []runtime.Object{cheOperatorDeployment, devworkspaceDeployment}) infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) - err := os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "true") - assert.NoError(t, err) devWorkspaceReconciler := NewDevWorkspaceReconciler() _, done, err := devWorkspaceReconciler.Reconcile(deployContext) - assert.NoError(t, err) assert.True(t, done) // verify that DWO is not provisioned - namespace := &corev1.Namespace{} - err = deployContext.ClusterAPI.NonCachingClient.Get(context.TODO(), types.NamespacedName{Name: DevWorkspaceNamespace}, namespace) + err = deployContext.ClusterAPI.NonCachingClient.Get(context.TODO(), types.NamespacedName{Name: DevWorkspaceNamespace}, &corev1.Namespace{}) assert.True(t, k8sErrors.IsNotFound(err)) } -func TestReconcileDevWorkspaceCheckIfCSVExists(t *testing.T) { - cheCluster := &chev2.CheCluster{ +func TestShouldNotReconcileDevWorkspaceIfNoOptExists(t *testing.T) { + os.Setenv("NO_OPT_DWO", "true") + + cheOperatorDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ + Name: defaults.GetCheFlavor() + "-operator", Namespace: "eclipse-che", }, } - devWorkspaceCSV := &operatorsv1alpha1.ClusterServiceVersion{ - ObjectMeta: metav1.ObjectMeta{ - Name: DevWorkspaceCSVName, - Namespace: "openshift-operators", - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{}, - } - - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{}) - deployContext.ClusterAPI.Scheme.AddKnownTypes(operatorsv1alpha1.SchemeGroupVersion, &operatorsv1alpha1.ClusterServiceVersion{}) - deployContext.ClusterAPI.Scheme.AddKnownTypes(operatorsv1alpha1.SchemeGroupVersion, &operatorsv1alpha1.ClusterServiceVersionList{}) - err := deployContext.ClusterAPI.Client.Create(context.TODO(), devWorkspaceCSV) - assert.NoError(t, err) - deployContext.ClusterAPI.DiscoveryClient.(*fakeDiscovery.FakeDiscovery).Fake.Resources = []*metav1.APIResourceList{ - { - APIResources: []metav1.APIResource{ - { - Name: ClusterServiceVersionResourceName, - }, - }, - }, - } + deployContext := test.GetDeployContext(nil, []runtime.Object{cheOperatorDeployment}) infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) - err = os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "true") - assert.NoError(t, err) devWorkspaceReconciler := NewDevWorkspaceReconciler() _, done, err := devWorkspaceReconciler.Reconcile(deployContext) - assert.True(t, done, "Reconcile is not triggered") + assert.True(t, done) - // Get Devworkspace namespace. If error is thrown means devworkspace is not anymore installed if CSV is detected - err = deployContext.ClusterAPI.Client.Get(context.TODO(), client.ObjectKey{Name: DevWorkspaceNamespace}, &corev1.Namespace{}) - assert.True(t, k8sErrors.IsNotFound(err), "DevWorkspace namespace is created when instead DWO CSV is expected to be created") + // verify that DWO is not provisioned + err = deployContext.ClusterAPI.NonCachingClient.Get(context.TODO(), types.NamespacedName{Name: DevWorkspaceNamespace}, &corev1.Namespace{}) + assert.True(t, k8sErrors.IsNotFound(err)) + + os.Unsetenv("NO_OPT_DWO") } -func TestReconcileDevWorkspaceIfUnmanagedDWONamespaceExists(t *testing.T) { - cheCluster := &chev2.CheCluster{ +func TestShouldNotReconcileDevWorkspaceIfUnmanagedDWONamespaceExists(t *testing.T) { + cheOperatorDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ + Name: defaults.GetCheFlavor() + "-operator", Namespace: "eclipse-che", }, } - dwoNamespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: DevWorkspaceNamespace, // no che annotations are there }, } - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{}) - err := deployContext.ClusterAPI.Client.Create(context.TODO(), dwoNamespace) - assert.NoError(t, err) - + deployContext := test.GetDeployContext(nil, []runtime.Object{cheOperatorDeployment, dwoNamespace}) infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) - err = os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "true") - assert.NoError(t, err) - devWorkspaceReconciler := NewDevWorkspaceReconciler() _, done, err := devWorkspaceReconciler.Reconcile(deployContext) @@ -246,12 +213,12 @@ func TestReconcileDevWorkspaceIfUnmanagedDWONamespaceExists(t *testing.T) { } func TestReconcileDevWorkspaceIfManagedDWONamespaceExists(t *testing.T) { - cheCluster := &chev2.CheCluster{ + cheOperatorDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ + Name: defaults.GetCheFlavor() + "-operator", Namespace: "eclipse-che", }, } - dwoNamespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: DevWorkspaceNamespace, @@ -261,19 +228,9 @@ func TestReconcileDevWorkspaceIfManagedDWONamespaceExists(t *testing.T) { // no che annotations are there }, } - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{}) - err := deployContext.ClusterAPI.NonCachingClient.Create(context.TODO(), dwoNamespace) - assert.NoError(t, err) - - exists, err := deploy.Get(deployContext, - types.NamespacedName{Name: DevWorkspaceNamespace, Namespace: DevWorkspaceNamespace}, - &corev1.Namespace{}) - + deployContext := test.GetDeployContext(nil, []runtime.Object{cheOperatorDeployment, dwoNamespace}) infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) - err = os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "true") - assert.NoError(t, err) - devWorkspaceReconciler := NewDevWorkspaceReconciler() _, done, err := devWorkspaceReconciler.Reconcile(deployContext) @@ -281,120 +238,9 @@ func TestReconcileDevWorkspaceIfManagedDWONamespaceExists(t *testing.T) { assert.NoError(t, err, "Reconcile failed") // check is reconcile created deployment if existing namespace is not annotated in che specific way - exists, err = deploy.Get(deployContext, + exists, err := deploy.Get(deployContext, types.NamespacedName{Name: DevWorkspaceDeploymentName, Namespace: DevWorkspaceNamespace}, &appsv1.Deployment{}) assert.True(t, exists, "DevWorkspace deployment is not created in Che managed DWO namespace") assert.NoError(t, err, "Failed to get devworkspace deployment") } - -func TestReconcileDevWorkspaceIfManagedDWOShouldBeTakenUnderControl(t *testing.T) { - cheCluster := &chev2.CheCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "eclipse-che", - }, - } - - dwoNamespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: DevWorkspaceNamespace, - Annotations: map[string]string{ - constants.CheEclipseOrgNamespace: "eclipse-che-removed", - }, - // no che annotations are there - }, - } - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{}) - deployContext.ClusterAPI.Scheme.AddKnownTypes(crdv1.SchemeGroupVersion, &crdv1.CustomResourceDefinition{}) - err := deployContext.ClusterAPI.NonCachingClient.Create(context.TODO(), dwoNamespace) - assert.NoError(t, err) - - exists, err := deploy.Get(deployContext, - types.NamespacedName{Name: DevWorkspaceNamespace, Namespace: DevWorkspaceNamespace}, - &corev1.Namespace{}) - - infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) - - err = os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "true") - assert.NoError(t, err) - - devWorkspaceReconciler := NewDevWorkspaceReconciler() - _, done, err := devWorkspaceReconciler.Reconcile(deployContext) - - assert.True(t, done, "Reconcile is not triggered") - assert.NoError(t, err, "Reconcile failed") - - // check is reconcile updated namespace with according way - exists, err = deploy.Get(deployContext, - types.NamespacedName{Name: DevWorkspaceNamespace}, - dwoNamespace) - assert.True(t, exists, "DevWorkspace Namespace does not exist") - assert.Equal(t, "eclipse-che", dwoNamespace.GetAnnotations()[constants.CheEclipseOrgNamespace]) - - // check that objects are sync - exists, err = deploy.Get(deployContext, - types.NamespacedName{Name: DevWorkspaceDeploymentName, Namespace: DevWorkspaceNamespace}, - &appsv1.Deployment{}) - assert.True(t, exists, "DevWorkspace deployment is not created in Che managed DWO namespace") - assert.NoError(t, err, "Failed to get devworkspace deployment") -} - -func TestReconcileDevWorkspaceIfManagedDWOShouldNotBeTakenUnderControl(t *testing.T) { - cheCluster := &chev2.CheCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "eclipse-che", - Name: "che-cluster", - }, - } - cheCluster2 := &chev2.CheCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "eclipse-che2", - Name: "che-cluster2", - }, - } - - dwoNamespace := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: DevWorkspaceNamespace, - Annotations: map[string]string{ - constants.CheEclipseOrgNamespace: "eclipse-che2", - }, - // no che annotations are there - }, - } - deployContext := test.GetDeployContext(cheCluster, []runtime.Object{}) - deployContext.ClusterAPI.Scheme.AddKnownTypes(crdv1.SchemeGroupVersion, &crdv1.CustomResourceDefinition{}) - err := deployContext.ClusterAPI.NonCachingClient.Create(context.TODO(), dwoNamespace) - assert.NoError(t, err) - err = deployContext.ClusterAPI.NonCachingClient.Create(context.TODO(), cheCluster2) - assert.NoError(t, err) - - exists, err := deploy.Get(deployContext, - types.NamespacedName{Name: DevWorkspaceNamespace, Namespace: DevWorkspaceNamespace}, - &corev1.Namespace{}) - - infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) - - err = os.Setenv("ALLOW_DEVWORKSPACE_ENGINE", "true") - assert.NoError(t, err) - - devWorkspaceReconciler := NewDevWorkspaceReconciler() - _, done, err := devWorkspaceReconciler.Reconcile(deployContext) - - assert.True(t, done, "Reconcile is not triggered") - assert.NoError(t, err, "Reconcile failed") - - // check is reconcile updated namespace with according way - exists, err = deploy.Get(deployContext, - types.NamespacedName{Name: DevWorkspaceNamespace}, - dwoNamespace) - assert.True(t, exists, "DevWorkspace Namespace does not exist") - assert.Equal(t, "eclipse-che2", dwoNamespace.GetAnnotations()[constants.CheEclipseOrgNamespace]) - - // check that objects are sync - exists, err = deploy.Get(deployContext, - types.NamespacedName{Name: DevWorkspaceDeploymentName, Namespace: DevWorkspaceNamespace}, - &appsv1.Deployment{}) - assert.False(t, exists, "DevWorkspace deployment is not created in Che managed DWO namespace") - assert.NoError(t, err, "Failed to get devworkspace deployment") -} diff --git a/pkg/deploy/dev-workspace/dev_workspace_utils.go b/pkg/deploy/dev-workspace/dev_workspace_utils.go index e89b28428..6e283946c 100644 --- a/pkg/deploy/dev-workspace/dev_workspace_utils.go +++ b/pkg/deploy/dev-workspace/dev_workspace_utils.go @@ -14,68 +14,19 @@ package devworkspace import ( "context" - "strings" + "os" + "strconv" - chev2 "github.com/eclipse-che/che-operator/api/v2" "github.com/eclipse-che/che-operator/pkg/common/chetypes" "github.com/eclipse-che/che-operator/pkg/common/constants" - "github.com/eclipse-che/che-operator/pkg/common/utils" "github.com/eclipse-che/che-operator/pkg/deploy" - operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/sirupsen/logrus" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/controller-runtime/pkg/client" ) -func isDevWorkspaceOperatorCSVExists(deployContext *chetypes.DeployContext) bool { - // If clusterserviceversions resource doesn't exist in cluster DWO as well will not be present - if !utils.IsK8SResourceServed(deployContext.ClusterAPI.DiscoveryClient, ClusterServiceVersionResourceName) { - return false - } - - csvList := &operatorsv1alpha1.ClusterServiceVersionList{} - err := deployContext.ClusterAPI.NonCachingClient.List(context.TODO(), csvList, &client.ListOptions{Namespace: OperatorNamespace}) - if err != nil { - logrus.Errorf("Failed to list csv: %v", err) - return false - } - - for _, csv := range csvList.Items { - if strings.HasPrefix(csv.Name, DevWorkspaceCSVNamePrefix) { - return true - } - } - - return false -} - -func isWebTerminalSubscriptionExist(deployContext *chetypes.DeployContext) (bool, error) { - // If subscriptions resource doesn't exist in cluster WTO as well will not be present - if !utils.IsK8SResourceServed(deployContext.ClusterAPI.DiscoveryClient, SubscriptionResourceName) { - return false, nil - } - - subscription := &operatorsv1alpha1.Subscription{} - if err := deployContext.ClusterAPI.NonCachingClient.Get( - context.TODO(), - types.NamespacedName{ - Name: WebTerminalOperatorSubscriptionName, - Namespace: OperatorNamespace, - }, - subscription); err != nil { - - if apierrors.IsNotFound(err) { - return false, nil - } - return false, err - } - - return true, nil -} - func createDwNamespace(deployContext *chetypes.DeployContext) (bool, error) { namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -90,12 +41,34 @@ func createDwNamespace(deployContext *chetypes.DeployContext) (bool, error) { return deploy.CreateIfNotExists(deployContext, namespace) } -func isOnlyOneOperatorManagesDWResources(deployContext *chetypes.DeployContext) (bool, error) { - cheClusters := &chev2.CheClusterList{} - err := deployContext.ClusterAPI.NonCachingClient.List(context.TODO(), cheClusters) - if err != nil { +func isNoOptDWO() (bool, error) { + value, exists := os.LookupEnv("NO_OPT_DWO") + if !exists { + return false, nil + } + + return strconv.ParseBool(value) +} + +func isDevWorkspaceOperatorHasOwner(ctx *chetypes.DeployContext) (bool, error) { + deployments := &appsv1.DeploymentList{} + if err := ctx.ClusterAPI.NonCachingClient.List( + context.TODO(), + deployments, + &client.ListOptions{ + LabelSelector: labels.SelectorFromSet(map[string]string{ + constants.KubernetesPartOfLabelKey: constants.DevWorkspaceOperator, + constants.KubernetesNameLabelKey: constants.DevWorkspaceController, + }), + }); err != nil { return false, err } - return len(cheClusters.Items) == 1, nil + for _, deployment := range deployments.Items { + if len(deployment.OwnerReferences) != 0 { + return true, nil + } + } + + return false, nil }