Skip to content

Commit 6b7a2f6

Browse files
committed
feat: prevent openshift-gitops namespace creation when DISABLE_DEFAULT_ARGOCD_INSTANCE=true
Signed-off-by: Rizwana777 <rizwananaaz177@gmail.com> Assisted-by: Claude
1 parent 7b86850 commit 6b7a2f6

7 files changed

Lines changed: 146 additions & 89 deletions

File tree

controllers/gitopsservice_controller.go

Lines changed: 96 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -248,86 +248,114 @@ func (r *ReconcileGitopsService) Reconcile(ctx context.Context, request reconcil
248248
return reconcile.Result{}, err
249249
}
250250

251-
// Create namespace if it doesn't already exist
252-
namespaceRef := newRestrictedNamespace(namespace)
253-
err = r.Client.Get(ctx, types.NamespacedName{Name: namespace}, namespaceRef)
254-
if err != nil {
255-
if errors.IsNotFound(err) {
256-
reqLogger.Info("Creating a new Namespace", "Name", namespace)
257-
ensureInfraNodeSelectorAnnotation(namespaceRef, instance.Spec.RunOnInfra)
258-
err = r.Client.Create(ctx, namespaceRef)
259-
if err != nil {
251+
gitopsserviceNamespacedName := types.NamespacedName{
252+
Name: serviceName,
253+
Namespace: namespace,
254+
}
255+
256+
if !r.DisableDefaultInstall {
257+
// Create namespace if it doesn't already exist (only when default install is enabled)
258+
namespaceRef := newRestrictedNamespace(namespace)
259+
err = r.Client.Get(ctx, types.NamespacedName{Name: namespace}, namespaceRef)
260+
if err != nil {
261+
if errors.IsNotFound(err) {
262+
reqLogger.Info("Creating a new Namespace", "Name", namespace)
263+
ensureInfraNodeSelectorAnnotation(namespaceRef, instance.Spec.RunOnInfra)
264+
err = r.Client.Create(ctx, namespaceRef)
265+
if err != nil {
266+
return reconcile.Result{}, err
267+
}
268+
} else {
260269
return reconcile.Result{}, err
261270
}
262271
} else {
263-
return reconcile.Result{}, err
264-
}
265-
} else {
266-
if ensureNamespaceMetadata(namespaceRef, instance.Spec.RunOnInfra) {
267-
err = r.Client.Update(context.TODO(), namespaceRef)
268-
if err != nil {
269-
return reconcile.Result{}, err
272+
if ensureNamespaceMetadata(namespaceRef, instance.Spec.RunOnInfra) {
273+
err = r.Client.Update(context.TODO(), namespaceRef)
274+
if err != nil {
275+
return reconcile.Result{}, err
276+
}
270277
}
271278
}
272-
}
273-
274-
gitopsserviceNamespacedName := types.NamespacedName{
275-
Name: serviceName,
276-
Namespace: namespace,
277-
}
278279

279-
r.cleanKAMResources(ctx, reqLogger)
280+
r.cleanKAMResources(ctx, reqLogger)
280281

281-
if !r.DisableDefaultInstall {
282-
// Create/reconcile the default Argo CD instance, unless default install is disabled
282+
// Create/reconcile the default Argo CD instance
283283
if result, err := r.reconcileDefaultArgoCDInstance(instance, reqLogger); err != nil {
284284
return result, fmt.Errorf("unable to reconcile default Argo CD instance: %v", err)
285285
}
286-
} else {
287-
// If installation of default Argo CD instance is disabled, make sure it doesn't exist,
288-
// deleting it if necessary
289-
if err := r.ensureDefaultArgoCDInstanceDoesntExist(); err != nil {
290-
return reconcile.Result{}, fmt.Errorf("unable to ensure non-existence of default Argo CD instance: %v", err)
286+
287+
// Reconcile backend service
288+
if result, err := r.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger); err != nil {
289+
return result, err
291290
}
292-
}
293291

294-
if result, err := r.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger); err != nil {
295-
return result, err
296-
}
292+
// Reconcile console plugin (only when default install is enabled)
293+
dynamicPluginStartOCPVersion := os.Getenv(dynamicPluginStartOCPVersionEnv)
294+
if dynamicPluginStartOCPVersion == "" {
295+
dynamicPluginStartOCPVersion = common.DefaultDynamicPluginStartOCPVersion
296+
}
297297

298-
dynamicPluginStartOCPVersion := os.Getenv(dynamicPluginStartOCPVersionEnv)
299-
if dynamicPluginStartOCPVersion == "" {
300-
dynamicPluginStartOCPVersion = common.DefaultDynamicPluginStartOCPVersion
301-
}
298+
OCPVersion, err := util.GetClusterVersion(r.Client)
299+
if err != nil {
300+
log.Printf("Unable to get cluster version: %v", err)
301+
return reconcile.Result{}, nil
302+
}
302303

303-
OCPVersion, err := util.GetClusterVersion(r.Client)
304-
if err != nil {
305-
log.Printf("Unable to get cluster version: %v", err)
306-
return reconcile.Result{}, nil
307-
}
304+
v1, err := version.NewVersion(OCPVersion)
305+
if err != nil {
306+
log.Printf("Unable to retrieve current OCP version: %v", err)
307+
return reconcile.Result{}, nil
308+
}
309+
realVersion := v1.Segments()
310+
if len(realVersion) < 2 {
311+
log.Printf("OCP version %q has fewer than 2 segments, skipping plugin reconciliation", OCPVersion)
312+
return reconcile.Result{}, nil
313+
}
314+
realMajorVersion := realVersion[0]
315+
realMinorVersion := realVersion[1]
308316

309-
v1, err := version.NewVersion(OCPVersion)
310-
if err != nil {
311-
log.Printf("Unable to retrieve current OCP version: %v", err)
312-
return reconcile.Result{}, nil
313-
}
314-
realVersion := v1.Segments()
315-
realMajorVersion := realVersion[0]
316-
realMinorVersion := realVersion[1]
317+
v2, err := version.NewVersion(dynamicPluginStartOCPVersion)
318+
if err != nil {
319+
return reconcile.Result{}, nil
320+
}
321+
startVersion := v2.Segments()
322+
if len(startVersion) < 2 {
323+
log.Printf("DYNAMIC_PLUGIN_START_OCP_VERSION %q has fewer than 2 segments, skipping plugin reconciliation", dynamicPluginStartOCPVersion)
324+
return reconcile.Result{}, nil
325+
}
326+
startMajorVersion := startVersion[0]
327+
startMinorVersion := startVersion[1]
317328

318-
v2, err := version.NewVersion(dynamicPluginStartOCPVersion)
319-
if err != nil {
329+
if realMajorVersion >= startMajorVersion && (realMajorVersion > startMajorVersion || realMinorVersion >= startMinorVersion) {
330+
// Reconcile plugin only if OCP version supports it
331+
return r.reconcilePlugin(instance, request)
332+
}
320333
return reconcile.Result{}, nil
321-
}
322-
startVersion := v2.Segments()
323-
startMajorVersion := startVersion[0]
324-
startMinorVersion := startVersion[1]
334+
} else {
335+
// If installation of default Argo CD instance is disabled, make sure it doesn't exist,
336+
// deleting it if necessary
337+
if err := r.ensureDefaultArgoCDInstanceDoesntExist(); err != nil {
338+
return reconcile.Result{}, fmt.Errorf("unable to ensure non-existence of default Argo CD instance: %v", err)
339+
}
325340

326-
if realMajorVersion < startMajorVersion || (realMajorVersion == startMajorVersion && realMinorVersion < startMinorVersion) {
327-
// Skip plugin reconciliation if real OCP version is less than dynamic plugin start OCP version
341+
// When default install is disabled, only reconcile backend if namespace exists and is not being deleted
342+
namespaceRef := newRestrictedNamespace(namespace)
343+
err := r.Client.Get(ctx, types.NamespacedName{Name: namespace}, namespaceRef)
344+
if err == nil {
345+
// Check if namespace is being deleted
346+
if namespaceRef.DeletionTimestamp != nil {
347+
// Namespace is being deleted, skip backend reconciliation
348+
return reconcile.Result{}, nil
349+
}
350+
// Namespace exists and is not terminating, reconcile backend
351+
if result, err := r.reconcileBackend(gitopsserviceNamespacedName, instance, reqLogger); err != nil {
352+
return result, err
353+
}
354+
} else if !errors.IsNotFound(err) {
355+
return reconcile.Result{}, err
356+
}
357+
// If namespace doesn't exist, skip backend reconciliation and plugin reconciliation
328358
return reconcile.Result{}, nil
329-
} else {
330-
return r.reconcilePlugin(instance, request)
331359
}
332360
}
333361

@@ -404,6 +432,13 @@ func (r *ReconcileGitopsService) ensureDefaultArgoCDInstanceDoesntExist() error
404432
return err
405433
}
406434

435+
// Also delete the namespace when DISABLE_DEFAULT_ARGOCD_INSTANCE is true
436+
if err := r.Client.Delete(context.TODO(), argocdNS); err != nil {
437+
if !errors.IsNotFound(err) {
438+
return fmt.Errorf("failed to delete openshift-gitops namespace: %w", err)
439+
}
440+
}
441+
407442
return nil
408443
}
409444

controllers/gitopsservice_controller_test.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,21 +154,25 @@ func TestReconcileDisableDefault(t *testing.T) {
154154

155155
argoCD := &argoapp.ArgoCD{}
156156

157-
// ArgoCD instance SHOULD NOT created (in openshift-gitops namespace)
157+
// ArgoCD instance SHOULD NOT be created (in openshift-gitops namespace)
158158
if err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: common.ArgoCDInstanceName, Namespace: serviceNamespace},
159159
argoCD); err == nil || !errors.IsNotFound(err) {
160160

161161
t.Fatalf("ArgoCD instance should not exist in namespace, error: %v", err)
162162
}
163163

164-
// openshift-gitops namespace SHOULD be created
164+
// openshift-gitops namespace SHOULD NOT be created when DISABLE_DEFAULT_ARGOCD_INSTANCE is true
165165
err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceNamespace}, &corev1.Namespace{})
166-
assertNoError(t, err)
166+
if err == nil || !errors.IsNotFound(err) {
167+
t.Fatalf("Namespace should not exist when DISABLE_DEFAULT_ARGOCD_INSTANCE is true, error: %v", err)
168+
}
167169

168-
// backend Deployment SHOULD be created
170+
// backend Deployment SHOULD NOT be created (no namespace to deploy into)
169171
deploy := &appsv1.Deployment{}
170172
err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deploy)
171-
assertNoError(t, err)
173+
if err == nil || !errors.IsNotFound(err) {
174+
t.Fatalf("Backend deployment should not exist when namespace doesn't exist, error: %v", err)
175+
}
172176

173177
}
174178

@@ -208,14 +212,11 @@ func TestReconcileDisableDefault_DeleteIfAlreadyExists(t *testing.T) {
208212
t.Fatalf("ArgoCD instance should not exist in namespace, error: %v", err)
209213
}
210214

211-
// openshift-gitops namespace SHOULD still exist
215+
// openshift-gitops namespace SHOULD be deleted when DISABLE_DEFAULT_ARGOCD_INSTANCE is enabled
212216
err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceNamespace}, &corev1.Namespace{})
213-
assertNoError(t, err)
214-
215-
// backend Deployment SHOULD still exist
216-
deploy := &appsv1.Deployment{}
217-
err = fakeClient.Get(context.TODO(), types.NamespacedName{Name: serviceName, Namespace: serviceNamespace}, deploy)
218-
assertNoError(t, err)
217+
if err == nil || !errors.IsNotFound(err) {
218+
t.Fatalf("Namespace should be deleted when DISABLE_DEFAULT_ARGOCD_INSTANCE is enabled, error: %v", err)
219+
}
219220

220221
}
221222

docs/Migration_Guide.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ For understanding the differences between [Argo CD Community Operator](https://g
66

77
**Note**: Installing GitOps operator will create a namespace with the name `openshift-gitops` and an Argo CD instance in the same namespace. This instance can be used for managing your OpenShift cluster configuration. It is enabled with Dex OpenShift connector by default which allows users to log in with their OpenShift credentials.
88

9-
The default Argo CD instance in the `openshift-gitops` namespace can be deleted by adding an environmental variable `DISABLE_DEFAULT_ARGOCD_INSTANCE` with the value `true` in the Subscription resource.
9+
The default Argo CD instance and the `openshift-gitops` namespace can be deleted by adding an environmental variable `DISABLE_DEFAULT_ARGOCD_INSTANCE` with the value `true` in the Subscription resource. This will completely remove the default installation.
1010

1111
To disable the default instance, edit the Subscription and add the following:
1212

@@ -65,7 +65,7 @@ Post migration the above environment variables has to be copied to GitOps operat
6565

6666
**Note**:
6767
GitOps operator supports the below additional environment variables
68-
`DISABLE_DEFAULT_ARGOCD_INSTANCE`: Disables the installation of default instance in openshift-gitops namespace.
68+
`DISABLE_DEFAULT_ARGOCD_INSTANCE`: Disables the installation of default instance in openshift-gitops namespace. This prevents the creation of the `openshift-gitops` namespace and ArgoCD instance. If they already exist, they will be deleted.
6969

7070
`ARGOCD_CLUSTER_CONFIG_NAMESPACES`: Argo CD is granted permissions to manage specific cluster-scoped resources which include
7171
platform operators, optional OLM operators, user management, etc. Argo CD is not granted cluster-admin. You can find the complete

docs/OpenShift GitOps Usage Guide.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ When installing the OpenShift GitOps operator to ROSA/OSD, cluster administrator
121121

122122
To disable the default ‘ready-to-use’ installation of Argo CD: as an admin, update the existing Subscription Object for Gitops Operator and add `DISABLE_DEFAULT_ARGOCD_INSTANCE = true` to the spec.
123123

124-
**Warning**: setting this option to true will cause the existing Argo CD install in the *openshift-gitops* namespace to be deleted. Argo CD instances in other namespaces should not be affected.
124+
**Warning**: setting this option to true will cause the existing Argo CD instance **and the `openshift-gitops` namespace** to be deleted. This completely removes the default installation. Argo CD instances in other namespaces should not be affected.
125125

126126
On OpenShift Console, go to
127127

@@ -222,7 +222,7 @@ Updating the following environment variables in the existing Subscription Object
222222
<tr>
223223
<td>DISABLE_DEFAULT_ARGOCD_INSTANCE</td>
224224
<td>false</td>
225-
<td>When set to `true`, will disable the default 'ready-to-use' installation of Argo CD in `openshift-gitops` namespace.</td>
225+
<td>When set to `true`, will disable the default 'ready-to-use' installation of Argo CD in `openshift-gitops` namespace. This prevents the creation of the `openshift-gitops` namespace and ArgoCD instance. If the namespace already exists, it will be deleted along with the ArgoCD instance.</td>
226226
</tr>
227227
<tr>
228228
<td>SERVER_CLUSTER_ROLE</td>

hack/non-olm-install/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ The following environment variables can be set to configure various options for
8181
| ----------- | ----------- |------------- |
8282
| **ARGOCD_CLUSTER_CONFIG_NAMESPACES** |OpenShift GitOps instances in the identified namespaces are granted limited additional permissions to manage specific cluster-scoped resources, which include platform operators, optional OLM operators, user management, etc.Multiple namespaces can be specified via a comma delimited list. | openshift-gitops |
8383
| **CONTROLLER_CLUSTER_ROLE** | This environment variable enables administrators to configure a common cluster role to use across all managed namespaces in the role bindings the operator creates for the Argo CD application controller. | None |
84-
| **DISABLE_DEFAULT_ARGOCD_INSTANCE** | When set to `true`, this will disable the default 'ready-to-use' installation of Argo CD in the `openshift-gitops` namespace. |false |
84+
| **DISABLE_DEFAULT_ARGOCD_INSTANCE** | When set to `true`, this will disable the default 'ready-to-use' installation of Argo CD in the `openshift-gitops` namespace. This prevents the creation of the `openshift-gitops` namespace and ArgoCD instance. If they already exist, they will be deleted. |false |
8585
| **SERVER_CLUSTER_ROLE** |This environment variable enables administrators to configure a common cluster role to use across all of the managed namespaces in the role bindings the operator creates for the Argo CD server. | None |
8686
| **WATCH_NAMESPACE** | namespaces in which Argo applications can be created | None |
8787
| **ENABLE_CONVERSION_WEBHOOK** | This environment variable enables conversion webhook to convert v1alpha1 ArgoCD resources to v1beta1 | true |

test/nondefaulte2e/gitops_service_nondefault_test.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,25 @@ var _ = Describe("GitOpsServiceNoDefaultInstall", func() {
4545
},
4646
}
4747

48-
It("Backend resources are created in 'openshift-gitops' namespace", func() {
49-
resourceList := []helper.ResourceList{
50-
{
51-
Resource: &appsv1.Deployment{},
52-
ExpectedResources: []string{
53-
"cluster",
54-
},
55-
},
56-
}
57-
err := helper.WaitForResourcesByName(k8sClient, resourceList, existingArgoInstance.Namespace, time.Second*180)
58-
Expect(err).NotTo(HaveOccurred())
48+
It("openshift-gitops namespace should not be created when DISABLE_DEFAULT_ARGOCD_INSTANCE is true", func() {
49+
// When DISABLE_DEFAULT_ARGOCD_INSTANCE is true, the namespace should not exist
50+
Consistently(func() bool {
51+
ns := &corev1.Namespace{}
52+
err := k8sClient.Get(context.Background(),
53+
types.NamespacedName{Name: existingArgoInstance.Namespace},
54+
ns)
55+
// Namespace should not exist
56+
return kubeerrors.IsNotFound(err)
57+
}, time.Second*30, interval).Should(BeTrue(), "openshift-gitops namespace should not exist when DISABLE_DEFAULT_ARGOCD_INSTANCE is true")
58+
})
59+
60+
It("Backend deployment should not be created when DISABLE_DEFAULT_ARGOCD_INSTANCE is true", func() {
61+
// Backend deployment should not exist (namespace doesn't exist)
62+
deployment := &appsv1.Deployment{}
63+
err := k8sClient.Get(context.Background(),
64+
types.NamespacedName{Name: "cluster", Namespace: existingArgoInstance.Namespace},
65+
deployment)
66+
Expect(kubeerrors.IsNotFound(err)).To(BeTrue(), "Backend deployment 'cluster' should not exist when DISABLE_DEFAULT_ARGOCD_INSTANCE is true")
5967
})
6068

6169
It("Default Argo CD instance should not be found", func() {

test/openshift/e2e/ginkgo/sequential/1-018_validate_disable_default_instance_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset"
3030
"github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils"
3131
appsv1 "k8s.io/api/apps/v1"
32+
corev1 "k8s.io/api/core/v1"
3233
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3334
)
3435

@@ -145,9 +146,21 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() {
145146
}
146147
Eventually(gitopsServerDepl).Should(k8sFixture.NotExistByName())
147148

149+
By("verifying openshift-gitops namespace no longer exists")
150+
openshiftGitopsNS := &corev1.Namespace{
151+
ObjectMeta: metav1.ObjectMeta{
152+
Name: "openshift-gitops",
153+
},
154+
}
155+
Eventually(openshiftGitopsNS).Should(k8sFixture.NotExistByName())
156+
148157
By("remove the DISABLE_DEFAULT_ARGOCD_INSTANCE env var we set above")
149158
fixture.RestoreSubcriptionToDefault()
150159

160+
By("verifying openshift-gitops namespace is recreated")
161+
Eventually(openshiftGitopsNS, "3m", "5s").Should(k8sFixture.ExistByName())
162+
163+
By("verifying ArgoCD CR is recreated")
151164
Eventually(openshiftGitopsArgoCD, "3m", "5s").Should(k8sFixture.ExistByName())
152165
Eventually(openshiftGitopsArgoCD, "5m", "5s").Should(argocdFixture.BeAvailable())
153166

0 commit comments

Comments
 (0)