Skip to content

Commit e30ff8e

Browse files
committed
Start using our own argocd instance
- We added consolelink creation perms
1 parent d262906 commit e30ff8e

9 files changed

Lines changed: 264 additions & 44 deletions

File tree

config/rbac/role.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ rules:
7575
verbs:
7676
- get
7777
- list
78+
- apiGroups:
79+
- console.openshift.io
80+
resources:
81+
- consolelinks
82+
verbs:
83+
- create
84+
- delete
85+
- get
86+
- list
87+
- patch
88+
- update
7889
- apiGroups:
7990
- gitops.hybrid-cloud-patterns.io
8091
resources:

internal/controller/argo.go

Lines changed: 87 additions & 2 deletions
Large diffs are not rendered by default.

internal/controller/argo_test.go

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ var _ = Describe("Argo Pattern", func() {
105105
argoApp = &argoapi.Application{
106106
ObjectMeta: metav1.ObjectMeta{
107107
Name: applicationName(pattern),
108-
Namespace: "openshift-gitops",
108+
Namespace: getClusterWideArgoNamespace(),
109109
Labels: map[string]string{
110110
"validatedpatterns.io/pattern": pattern.Name,
111111
},
@@ -118,8 +118,13 @@ var _ = Describe("Argo Pattern", func() {
118118
},
119119
Project: "default",
120120
SyncPolicy: &argoapi.SyncPolicy{
121-
Automated: &argoapi.SyncPolicyAutomated{},
121+
Automated: &argoapi.SyncPolicyAutomated{
122+
SelfHeal: true,
123+
},
122124
SyncOptions: []string{},
125+
Retry: &argoapi.RetryStrategy{
126+
Limit: 20,
127+
},
123128
},
124129
},
125130
}
@@ -450,6 +455,10 @@ var _ = Describe("Argo Pattern", func() {
450455
Name: "global.gitOpsSubNamespace",
451456
Value: GitOpsDefaultSubscriptionNamespace,
452457
},
458+
argoapi.HelmParameter{
459+
Name: "global.vpArgoNamespace",
460+
Value: getClusterWideArgoNamespace(),
461+
},
453462
argoapi.HelmParameter{
454463
Name: "global.multiSourceTargetRevision",
455464
Value: "0.0.*",
@@ -488,6 +497,10 @@ var _ = Describe("Argo Pattern", func() {
488497
Name: "global.gitOpsSubNamespace",
489498
Value: GitOpsDefaultSubscriptionNamespace,
490499
},
500+
argoapi.HelmParameter{
501+
Name: "global.vpArgoNamespace",
502+
Value: getClusterWideArgoNamespace(),
503+
},
491504
argoapi.HelmParameter{
492505
Name: "global.multiSourceTargetRevision",
493506
Value: "0.0.*",
@@ -525,6 +538,10 @@ var _ = Describe("Argo Pattern", func() {
525538
Name: "global.gitOpsSubNamespace",
526539
Value: GitOpsDefaultSubscriptionNamespace,
527540
},
541+
argoapi.HelmParameter{
542+
Name: "global.vpArgoNamespace",
543+
Value: getClusterWideArgoNamespace(),
544+
},
528545
argoapi.HelmParameter{
529546
Name: "global.multiSourceTargetRevision",
530547
Value: "0.0.*",
@@ -625,14 +642,14 @@ var _ = Describe("Argo Pattern", func() {
625642
})
626643
It("should return false and log the appropriate message", func() {
627644
automatedSyncPolicyChanged := automatedSyncPolicy.DeepCopy()
628-
automatedSyncPolicyChanged.SelfHeal = true
645+
automatedSyncPolicyChanged.SelfHeal = false
629646
logBuffer := new(bytes.Buffer)
630647
log.SetOutput(logBuffer)
631648
defer log.SetOutput(os.Stderr)
632649

633650
result := compareAutomatedSyncPolicy(automatedSyncPolicy, automatedSyncPolicyChanged)
634651
Expect(result).To(BeFalse())
635-
Expect(logBuffer.String()).To(ContainSubstring("SyncPolicy SelfHeal changed true -> false"))
652+
Expect(logBuffer.String()).To(ContainSubstring("SyncPolicy SelfHeal changed false -> true"))
636653
})
637654
It("compareAutomatedSyncPolicy() function with nil arg1", func() {
638655
Expect(compareAutomatedSyncPolicy(automatedSyncPolicy, nil)).To(BeFalse())
@@ -1479,6 +1496,9 @@ var _ = Describe("CommonSyncPolicy", func() {
14791496
Expect(policy).ToNot(BeNil())
14801497
Expect(policy.Automated).ToNot(BeNil())
14811498
Expect(policy.Automated.Prune).To(BeFalse())
1499+
Expect(policy.Automated.SelfHeal).To(BeTrue())
1500+
Expect(policy.Retry).ToNot(BeNil())
1501+
Expect(policy.Retry.Limit).To(Equal(int64(20)))
14821502
})
14831503
})
14841504

@@ -1954,16 +1974,16 @@ var _ = Describe("removeApplication", func() {
19541974
app := &argoapi.Application{
19551975
ObjectMeta: metav1.ObjectMeta{
19561976
Name: "test-app",
1957-
Namespace: "openshift-gitops",
1977+
Namespace: getClusterWideArgoNamespace(),
19581978
},
19591979
}
19601980
argoClient := argoclient.NewSimpleClientset(app)
19611981

1962-
err := removeApplication(argoClient, "test-app", "openshift-gitops")
1982+
err := removeApplication(argoClient, "test-app", getClusterWideArgoNamespace())
19631983
Expect(err).ToNot(HaveOccurred())
19641984

19651985
// Verify the application is gone
1966-
_, err = argoClient.ArgoprojV1alpha1().Applications("openshift-gitops").Get(
1986+
_, err = argoClient.ArgoprojV1alpha1().Applications(getClusterWideArgoNamespace()).Get(
19671987
context.Background(), "test-app", metav1.GetOptions{})
19681988
Expect(err).To(HaveOccurred())
19691989
Expect(kerrors.IsNotFound(err)).To(BeTrue())
@@ -1973,7 +1993,7 @@ var _ = Describe("removeApplication", func() {
19731993
Context("when the application does not exist", func() {
19741994
It("should return an error", func() {
19751995
argoClient := argoclient.NewSimpleClientset()
1976-
err := removeApplication(argoClient, "nonexistent", "openshift-gitops")
1996+
err := removeApplication(argoClient, "nonexistent", getClusterWideArgoNamespace())
19771997
Expect(err).To(HaveOccurred())
19781998
})
19791999
})
@@ -2151,6 +2171,9 @@ var _ = Describe("commonSyncPolicy", func() {
21512171
Expect(policy).ToNot(BeNil())
21522172
Expect(policy.Automated).ToNot(BeNil())
21532173
Expect(policy.Automated.Prune).To(BeFalse())
2174+
Expect(policy.Automated.SelfHeal).To(BeTrue())
2175+
Expect(policy.Retry).ToNot(BeNil())
2176+
Expect(policy.Retry.Limit).To(Equal(int64(20)))
21542177
})
21552178

21562179
It("should return nil sync policy when manual sync is enabled", func() {
@@ -2188,7 +2211,7 @@ var _ = Describe("syncApplication", func() {
21882211
app := &argoapi.Application{
21892212
ObjectMeta: metav1.ObjectMeta{
21902213
Name: "test-app",
2191-
Namespace: "openshift-gitops",
2214+
Namespace: getClusterWideArgoNamespace(),
21922215
},
21932216
}
21942217
argoFakeClient := argoclient.NewSimpleClientset(app)
@@ -2205,7 +2228,7 @@ var _ = Describe("syncApplication", func() {
22052228
app := &argoapi.Application{
22062229
ObjectMeta: metav1.ObjectMeta{
22072230
Name: "test-app",
2208-
Namespace: "openshift-gitops",
2231+
Namespace: getClusterWideArgoNamespace(),
22092232
},
22102233
}
22112234
argoFakeClient := argoclient.NewSimpleClientset(app)
@@ -2222,7 +2245,7 @@ var _ = Describe("syncApplication", func() {
22222245
app := &argoapi.Application{
22232246
ObjectMeta: metav1.ObjectMeta{
22242247
Name: "test-app",
2225-
Namespace: "openshift-gitops",
2248+
Namespace: getClusterWideArgoNamespace(),
22262249
},
22272250
Operation: &argoapi.Operation{
22282251
Sync: &argoapi.SyncOperation{
@@ -2245,15 +2268,15 @@ var _ = Describe("getChildApplications", func() {
22452268
parentApp := &argoapi.Application{
22462269
ObjectMeta: metav1.ObjectMeta{
22472270
Name: "parent-app",
2248-
Namespace: "openshift-gitops",
2271+
Namespace: getClusterWideArgoNamespace(),
22492272
},
22502273
}
22512274
childApp := &argoapi.Application{
22522275
ObjectMeta: metav1.ObjectMeta{
22532276
Name: "child-app",
2254-
Namespace: "openshift-gitops",
2277+
Namespace: getClusterWideArgoNamespace(),
22552278
Annotations: map[string]string{
2256-
"argocd.argoproj.io/tracking-id": "parent-app:argoproj.io/Application:openshift-gitops/child-app",
2279+
"argocd.argoproj.io/tracking-id": fmt.Sprintf("parent-app:argoproj.io/Application:%s/child-app", getClusterWideArgoNamespace()),
22572280
},
22582281
},
22592282
}
@@ -2271,7 +2294,7 @@ var _ = Describe("getChildApplications", func() {
22712294
parentApp := &argoapi.Application{
22722295
ObjectMeta: metav1.ObjectMeta{
22732296
Name: "parent-app",
2274-
Namespace: "openshift-gitops",
2297+
Namespace: getClusterWideArgoNamespace(),
22752298
},
22762299
}
22772300
argoFakeClient := argoclient.NewSimpleClientset(parentApp)

internal/controller/defaults.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ const (
3333
// Default Operator Config Map Name
3434
OperatorConfigMap = "patterns-operator-config"
3535
// Default Application Namespace
36-
ApplicationNamespace = "openshift-gitops"
36+
ApplicationNamespace = "vp-gitops"
3737
// ClusterWide Argo Name
38-
ClusterWideArgoName = "openshift-gitops"
38+
ClusterWideArgoName = "vp-gitops"
39+
// Legacy Application Namespace (used by the default gitops-operator instance)
40+
LegacyApplicationNamespace = "openshift-gitops"
41+
// Legacy ClusterWide Argo Name
42+
LegacyClusterWideArgoName = "openshift-gitops"
3943
)
4044

4145
// GitOps Subscription

internal/controller/pattern_controller.go

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ type PatternReconciler struct {
9999
//+kubebuilder:rbac:groups=config.openshift.io,resources=ingresses,verbs=list;get
100100
//+kubebuilder:rbac:groups=config.openshift.io,resources=infrastructures,verbs=list;get
101101
//+kubebuilder:rbac:groups="",resources=namespaces,verbs=list;watch;delete;update;get;create;patch
102+
//+kubebuilder:rbac:groups=console.openshift.io,resources=consolelinks,verbs=get;list;create;update;patch;delete
102103
//+kubebuilder:rbac:groups=argoproj.io,resources=argocds,verbs=list;watch;get;create;update;patch;delete
103104
//+kubebuilder:rbac:groups=argoproj.io,resources=applications,verbs=list;get;create;update;patch;delete
104105
//+kubebuilder:rbac:groups=operators.coreos.com,resources=subscriptions,verbs=list;get;create;update;patch;delete
@@ -174,6 +175,10 @@ func (r *PatternReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
174175
return r.actionPerformed(qualifiedInstance, "applying defaults", err)
175176
}
176177

178+
// -- Detect ArgoCD namespace (legacy upgrade vs greenfield)
179+
// Must happen before subscription creation since it controls DISABLE_DEFAULT_ARGOCD_INSTANCE.
180+
detectArgoNamespace(r.dynamicClient)
181+
177182
if r.AnalyticsClient.SendPatternInstallationInfo(qualifiedInstance) {
178183
return r.actionPerformed(qualifiedInstance, "Updated status with identity sent", nil)
179184
}
@@ -183,7 +188,10 @@ func (r *PatternReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
183188
}
184189

185190
// -- GitOps Subscription
186-
targetSub, err := newSubscriptionFromConfigMap(r.fullClient)
191+
// Only disable the default ArgoCD instance for non-legacy deployments.
192+
// For legacy deployments, the gitops-operator's default instance is still in use.
193+
disableDefault := !isLegacyArgoNamespace()
194+
targetSub, err := newSubscriptionFromConfigMap(r.fullClient, disableDefault)
187195

188196
if err != nil {
189197
return r.actionPerformed(qualifiedInstance, "error creating new subscription from configmap", err)
@@ -254,13 +262,16 @@ func (r *PatternReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
254262

255263
clusterWideNS := getClusterWideArgoNamespace()
256264
if !haveNamespace(r.Client, clusterWideNS) {
257-
return r.actionPerformed(qualifiedInstance, "check application namespace", fmt.Errorf("waiting for creation"))
265+
if isLegacyArgoNamespace() {
266+
// Legacy mode: wait for the gitops-operator to create the openshift-gitops namespace
267+
return r.actionPerformed(qualifiedInstance, "check application namespace", fmt.Errorf("waiting for creation"))
268+
}
269+
// Greenfield: create the namespace ourselves
270+
if err = createNamespace(r.fullClient, clusterWideNS); err != nil {
271+
return r.actionPerformed(qualifiedInstance, "error creating ArgoCD namespace", err)
272+
}
273+
return r.actionPerformed(qualifiedInstance, "created ArgoCD namespace", nil)
258274
}
259-
// Once we add support for creating the clusterwide argo in a separate NS we will uncomment this
260-
// else if !haveNamespace(r.Client, clusterWideNS) && *qualifiedInstance.Spec.Experimental { // create the namespace if it does not exist
261-
// err = createNamespace(r.fullClient, clusterWideNS)
262-
// return r.actionPerformed(qualifiedInstance, "created vp clusterwide namespace", err)
263-
// }
264275
logOnce("namespace found")
265276

266277
// Create the trusted-bundle configmap inside the clusterwide namespace
@@ -282,10 +293,18 @@ func (r *PatternReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
282293
}
283294

284295
// We only update the clusterwide argo instance so we can define our own 'initcontainers' section
285-
err = createOrUpdateArgoCD(r.dynamicClient, r.fullClient, ClusterWideArgoName, clusterWideNS)
296+
err = createOrUpdateArgoCD(r.dynamicClient, r.fullClient, getClusterWideArgoName(), clusterWideNS)
286297
if err != nil {
287298
return r.actionPerformed(qualifiedInstance, "created or updated clusterwide argo instance", err)
288299
}
300+
301+
// Create/update the ConsoleLink so the ArgoCD instance appears in the OpenShift console nine-box menu
302+
if !isLegacyArgoNamespace() && qualifiedInstance.Status.AppClusterDomain != "" {
303+
if err = createOrUpdateConsoleLink(r.dynamicClient, getClusterWideArgoName(), clusterWideNS, qualifiedInstance.Status.AppClusterDomain); err != nil {
304+
return r.actionPerformed(qualifiedInstance, "error creating ConsoleLink for ArgoCD", err)
305+
}
306+
}
307+
289308
// Copy the bootstrap secret to the namespaced argo namespace
290309
if qualifiedInstance.Spec.GitConfig.TokenSecret != "" {
291310
if err = r.copyAuthGitSecret(qualifiedInstance.Spec.GitConfig.TokenSecretNamespace,
@@ -691,6 +710,8 @@ func (r *PatternReconciler) finalizeObject(instance *api.Pattern) error {
691710
log.Printf("\n\x1b[31;1m\tCannot cleanup the ArgoCD application of an invalid pattern: %s\x1b[0m\n", err.Error())
692711
return nil
693712
}
713+
// Ensure detection has run for the finalize path
714+
detectArgoNamespace(r.dynamicClient)
694715
ns := getClusterWideArgoNamespace()
695716

696717
targetApp := newArgoApplication(qualifiedInstance)
@@ -793,6 +814,13 @@ func (r *PatternReconciler) finalizeObject(instance *api.Pattern) error {
793814
if err := removeApplication(r.argoClient, app.Name, ns); err != nil {
794815
return err
795816
}
817+
// Clean up the ConsoleLink if we created one
818+
if !isLegacyArgoNamespace() {
819+
err := removeConsoleLink(r.dynamicClient, getClusterWideArgoName())
820+
if err != nil {
821+
log.Printf("failed to remove the consoleLink: %v", err)
822+
}
823+
}
796824
}
797825
}
798826

@@ -865,7 +893,7 @@ func (r *PatternReconciler) startArgoCDWatch() {
865893

866894
err := r.ctrl.Watch(source.Kind(r.mgr.GetCache(), argoCD,
867895
handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, obj *unstructured.Unstructured) []reconcile.Request {
868-
if obj.GetName() != ClusterWideArgoName || obj.GetNamespace() != getClusterWideArgoNamespace() {
896+
if obj.GetName() != getClusterWideArgoName() || obj.GetNamespace() != getClusterWideArgoNamespace() {
869897
return nil
870898
}
871899
var patterns api.PatternList
@@ -917,6 +945,21 @@ func (r *PatternReconciler) onReconcileErrorWithRequeue(p *api.Pattern, reason s
917945
return reconcile.Result{}, err
918946
}
919947

948+
// detectArgoNamespace determines whether this is a legacy upgrade or greenfield deploy
949+
// by checking if the legacy ArgoCD CR exists. Sets the package-level active ArgoCD
950+
// namespace/name accordingly.
951+
func detectArgoNamespace(dynamicClient dynamic.Interface) {
952+
if haveArgo(dynamicClient, LegacyClusterWideArgoName, LegacyApplicationNamespace) {
953+
activeArgoNamespace = LegacyApplicationNamespace
954+
activeArgoName = LegacyClusterWideArgoName
955+
logOnce(fmt.Sprintf("Detected legacy ArgoCD instance, using namespace: %s", LegacyApplicationNamespace))
956+
} else {
957+
activeArgoNamespace = ApplicationNamespace
958+
activeArgoName = ClusterWideArgoName
959+
logOnce(fmt.Sprintf("No legacy ArgoCD instance found, using namespace: %s", ApplicationNamespace))
960+
}
961+
}
962+
920963
func (r *PatternReconciler) actionPerformed(p *api.Pattern, reason string, err error) (reconcile.Result, error) {
921964
if err != nil {
922965
delay := time.Minute * 1

internal/controller/subscription.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
"k8s.io/client-go/kubernetes"
3131
)
3232

33-
func newSubscriptionFromConfigMap(r kubernetes.Interface) (*operatorv1alpha1.Subscription, error) {
33+
func newSubscriptionFromConfigMap(r kubernetes.Interface, disableDefaultInstance bool) (*operatorv1alpha1.Subscription, error) {
3434
var newSubscription *operatorv1alpha1.Subscription
3535

3636
// Check if the config map exists and read the config map values
@@ -60,12 +60,7 @@ func newSubscriptionFromConfigMap(r kubernetes.Interface) (*operatorv1alpha1.Sub
6060
StartingCSV: PatternsOperatorConfig.getValueWithDefault("gitops.csv"),
6161
InstallPlanApproval: installPlanApproval,
6262
Config: &operatorv1alpha1.SubscriptionConfig{
63-
Env: []corev1.EnvVar{
64-
{
65-
Name: "ARGOCD_CLUSTER_CONFIG_NAMESPACES",
66-
Value: "*",
67-
},
68-
},
63+
Env: newSubscriptionEnvVars(disableDefaultInstance),
6964
},
7065
}
7166
subscriptionName, subscriptionNamespace := DetectGitOpsSubscription()
@@ -81,6 +76,27 @@ func newSubscriptionFromConfigMap(r kubernetes.Interface) (*operatorv1alpha1.Sub
8176
return newSubscription, nil
8277
}
8378

79+
// newSubscriptionEnvVars returns the environment variables for the GitOps operator subscription.
80+
// When disableDefaultInstance is true, the DISABLE_DEFAULT_ARGOCD_INSTANCE env var is added
81+
// to prevent the gitops-operator from creating (and actively deleting) the default ArgoCD
82+
// instance in the openshift-gitops namespace. This is safe when using a non-default ArgoCD
83+
// name/namespace (e.g. vp-gitops) since the gitops-operator only targets "openshift-gitops".
84+
func newSubscriptionEnvVars(disableDefaultInstance bool) []corev1.EnvVar {
85+
envVars := []corev1.EnvVar{
86+
{
87+
Name: "ARGOCD_CLUSTER_CONFIG_NAMESPACES",
88+
Value: "*",
89+
},
90+
}
91+
if disableDefaultInstance {
92+
envVars = append(envVars, corev1.EnvVar{
93+
Name: "DISABLE_DEFAULT_ARGOCD_INSTANCE",
94+
Value: "true",
95+
})
96+
}
97+
return envVars
98+
}
99+
84100
func getSubscription(client olmclient.Interface, name, namespace string) (*operatorv1alpha1.Subscription, error) {
85101
var subscription *operatorv1alpha1.Subscription
86102
var err error

0 commit comments

Comments
 (0)