Skip to content

Commit

Permalink
support multiple ArgoCD instances with ApplicationTrackingAnnotations
Browse files Browse the repository at this point in the history
Signed-off-by: Atif Ali <[email protected]>
  • Loading branch information
aali309 committed Jan 8, 2025
1 parent 66f463b commit bd8f847
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 0 deletions.
10 changes: 10 additions & 0 deletions api/v1alpha1/argocd_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,16 @@ type ArgoCDSpec struct {
//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Application Instance Label Key'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
ApplicationInstanceLabelKey string `json:"applicationInstanceLabelKey,omitempty"`

// ApplicationTrackingAnnotations defines a map of annotations that will be used to support multiple
// ArgoCD instances managing the same cluster resources. For example:
// applicationTrackingAnnotations:
// installationID: "my-unique-id"
// otherAnnotation: "value"
// These annotations will be added to the argocd-cm ConfigMap.
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Application Tracking Annotations",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
ApplicationTrackingAnnotations map[string]string `json:"applicationTrackingAnnotations,omitempty"`

// ConfigManagementPlugins is used to specify additional config management plugins.
//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Config Management Plugins'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
ConfigManagementPlugins string `json:"configManagementPlugins,omitempty"`
Expand Down
7 changes: 7 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions api/v1beta1/argocd_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,16 @@ type ArgoCDSpec struct {
//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Application Instance Label Key'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
ApplicationInstanceLabelKey string `json:"applicationInstanceLabelKey,omitempty"`

// ApplicationTrackingAnnotations defines a map of annotations that will be used to support multiple
// ArgoCD instances managing the same cluster resources. For example:
// applicationTrackingAnnotations:
// installationID: "my-unique-id"
// otherAnnotation: "value"
// These annotations will be added to the argocd-cm ConfigMap.
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Application Tracking Annotations",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
ApplicationTrackingAnnotations map[string]string `json:"applicationTrackingAnnotations,omitempty"`

// ConfigManagementPlugins is used to specify additional config management plugins.
//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Config Management Plugins'",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text","urn:alm:descriptor:com.tectonic.ui:advanced"}
ConfigManagementPlugins string `json:"configManagementPlugins,omitempty"`
Expand Down
7 changes: 7 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions config/crd/bases/argoproj.io_argocds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,17 @@ spec:
type: object
type: object
type: object
applicationTrackingAnnotations:
additionalProperties:
type: string
description: |-
ApplicationTrackingAnnotations defines a map of annotations that will be used to support multiple
ArgoCD instances managing the same cluster resources. For example:
applicationTrackingAnnotations:
installationID: "my-unique-id"
otherAnnotation: "value"
These annotations will be added to the argocd-cm ConfigMap.
type: object
banner:
description: Banner defines an additional banner to be displayed in
Argo CD UI
Expand Down
7 changes: 7 additions & 0 deletions controllers/argocd/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,13 @@ func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoproj.ArgoCD) error {
cm.Data = make(map[string]string)
cm.Data = setRespectRBAC(cr, cm.Data)
cm.Data[common.ArgoCDKeyApplicationInstanceLabelKey] = getApplicationInstanceLabelKey(cr)

if cr.Spec.ApplicationTrackingAnnotations != nil {
for k, v := range cr.Spec.ApplicationTrackingAnnotations {
cm.Data[k] = v
}
}

cm.Data[common.ArgoCDKeyConfigManagementPlugins] = getConfigManagementPlugins(cr)
cm.Data[common.ArgoCDKeyAdminEnabled] = fmt.Sprintf("%t", !cr.Spec.DisableAdmin)
cm.Data[common.ArgoCDKeyGATrackingID] = getGATrackingID(cr)
Expand Down
112 changes: 112 additions & 0 deletions controllers/argocd/configmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1154,3 +1154,115 @@ func Test_validateOwnerReferences(t *testing.T) {
assert.Equal(t, cm.OwnerReferences[0].Name, "argocd")
assert.Equal(t, cm.OwnerReferences[0].UID, uid)
}

func TestReconcileArgoCD_reconcileArgoConfigMap_withApplicationTrackingAnnotations(t *testing.T) {
logf.SetLogger(ZapLogger(true))

initialAnnotations := map[string]string{
"installationID": "test-id",
}
updatedAnnotations := map[string]string{
"installationID": "updated-test-id",
}

a := makeTestArgoCD(func(a *argoproj.ArgoCD) {
a.Spec.ApplicationTrackingAnnotations = initialAnnotations
})

resObjs := []client.Object{a}
subresObjs := []client.Object{a}
runtimeObjs := []runtime.Object{}
sch := makeTestReconcilerScheme(argoproj.AddToScheme)
cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
r := makeTestReconciler(cl, sch)

err := r.reconcileArgoConfigMap(a)
assert.NoError(t, err)

cm := &corev1.ConfigMap{}
err = r.Client.Get(context.TODO(), types.NamespacedName{
Name: common.ArgoCDConfigMapName,
Namespace: testNamespace,
}, cm)
assert.NoError(t, err)

// Check initial annotations
for k, v := range initialAnnotations {
if c := cm.Data[k]; c != v {
t.Fatalf("reconcileArgoConfigMap failed got %q, want %q", c, v)
}
}

// Test updating annotations
a.Spec.ApplicationTrackingAnnotations = updatedAnnotations
err = r.reconcileArgoConfigMap(a)
assert.NoError(t, err)

err = r.Client.Get(context.TODO(), types.NamespacedName{
Name: common.ArgoCDConfigMapName,
Namespace: testNamespace,
}, cm)
assert.NoError(t, err)

// Check updated annotations
for k, v := range updatedAnnotations {
if c := cm.Data[k]; c != v {
t.Fatalf("reconcileArgoConfigMap failed got %q, want %q", c, v)
}
}
}

func TestReconcileArgoCD_reconcileArgoConfigMap_withMultipleInstances(t *testing.T) {
logf.SetLogger(ZapLogger(true))

// Create first ArgoCD instance
argocd1 := makeTestArgoCD(func(a *argoproj.ArgoCD) {
a.Name = "argocd-1"
a.Namespace = testNamespace
a.Spec.ApplicationTrackingAnnotations = map[string]string{
"installationID": "instance-1",
}
})

// Create second ArgoCD instance
argocd2 := makeTestArgoCD(func(a *argoproj.ArgoCD) {
a.Name = "argocd-2"
a.Namespace = testNamespace
a.Spec.ApplicationTrackingAnnotations = map[string]string{
"installationID": "instance-2",
}
})

resObjs := []client.Object{argocd1, argocd2}
subresObjs := []client.Object{argocd1, argocd2}
runtimeObjs := []runtime.Object{}
sch := makeTestReconcilerScheme(argoproj.AddToScheme)
cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
r := makeTestReconciler(cl, sch)

// Test first instance
err := r.reconcileArgoConfigMap(argocd1)
assert.NoError(t, err)

cm1 := &corev1.ConfigMap{}
err = r.Client.Get(context.TODO(), types.NamespacedName{
Name: common.ArgoCDConfigMapName,
Namespace: testNamespace,
}, cm1)
assert.NoError(t, err)
assert.Equal(t, "instance-1", cm1.Data["installationID"])

// Test second instance
err = r.reconcileArgoConfigMap(argocd2)
assert.NoError(t, err)

cm2 := &corev1.ConfigMap{}
err = r.Client.Get(context.TODO(), types.NamespacedName{
Name: common.ArgoCDConfigMapName,
Namespace: testNamespace,
}, cm2)
assert.NoError(t, err)
assert.Equal(t, "instance-2", cm2.Data["installationID"])

assert.NotEqual(t, cm1.Data["installationID"], cm2.Data["installationID"])
}

0 comments on commit bd8f847

Please sign in to comment.