Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add labelSelector option to filter the ArgoCD instances for reconciliation #961

Merged
merged 35 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6cbb155
Added labelselector string to map conversion
raghavi101 Jul 31, 2023
c6a07be
Changed data-type for labelSelector to parse string
raghavi101 Aug 2, 2023
4cf717d
Added code to reconcile selected ArgoCD instances based on label sele…
raghavi101 Aug 3, 2023
2082e94
remove comments
raghavi101 Aug 3, 2023
dbb25ca
Updated argoCD label fetch, renamed env var
raghavi101 Aug 7, 2023
bc68282
Updated unit test and yaml
raghavi101 Aug 7, 2023
2f45801
Updated unit test
raghavi101 Aug 8, 2023
2937885
Fix yaml env ValueFrom field
raghavi101 Aug 9, 2023
d6f7924
Added comments and labelSelector check in main.go
raghavi101 Aug 10, 2023
9fe6252
removed label-selector option from manifest
raghavi101 Aug 29, 2023
66c00e5
updated label-selector format in manifests
raghavi101 Aug 29, 2023
967003f
added label selector logs
raghavi101 Sep 4, 2023
c9013ff
go mod tidy
raghavi101 Sep 4, 2023
4f4105e
added e2e tests for label-selector
raghavi101 Sep 7, 2023
7dbfd41
restructured kuttl files and added operator patch file
raghavi101 Sep 13, 2023
d79caf6
go mod tidy
raghavi101 Sep 18, 2023
dfa77ba
corrected kuttl tests for cm failure
raghavi101 Sep 20, 2023
60440b8
Added documentation for Environment Variable ARGOCD_LABEL_SELECTOR
raghavi101 Sep 26, 2023
9a64e9a
cleanup
raghavi101 Sep 26, 2023
89dcb5c
improved unit tests and some minor changes
raghavi101 Sep 28, 2023
88cefba
kuttl rerun
raghavi101 Sep 28, 2023
8048e76
removed env var
raghavi101 Oct 5, 2023
5dea229
misc modifications
raghavi101 Oct 10, 2023
e00fb35
argocd-operator csv correction
raghavi101 Oct 10, 2023
83f1b3c
fix bundle error
raghavi101 Oct 10, 2023
eae66a8
fix bundle error
raghavi101 Oct 10, 2023
6d58c63
fix manifests build
ishitasequeira Oct 11, 2023
96c73dd
Added more unit test cases
raghavi101 Oct 12, 2023
95e1163
rebase
raghavi101 Oct 13, 2023
4927010
removed excess reconcilers
raghavi101 Oct 16, 2023
2fd9a6e
minor fix
raghavi101 Oct 16, 2023
988f7ee
removed extraneous test case and cleaned manager.yaml
raghavi101 Oct 18, 2023
63b0604
cleaned manager.yaml
raghavi101 Oct 18, 2023
979e4a9
fix make bundle issue
raghavi101 Oct 18, 2023
15cdce7
fix make bundle issue
raghavi101 Oct 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bundle/manifests/argocd-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1733,13 +1733,15 @@ spec:
containers:
- args:
- --leader-elect
- --label-selector
raghavi101 marked this conversation as resolved.
Show resolved Hide resolved
command:
- /manager
env:
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.annotations['olm.targetNamespaces']
- name: ARGOCD_LABEL_SELECTOR
- name: ENABLE_CONVERSION_WEBHOOK
value: "true"
image: quay.io/argoprojlabs/argocd-operator:v0.8.0
Expand Down
3 changes: 3 additions & 0 deletions common/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ const (
// ArgoCDKeycloakImage is the default Keycloak Image used for the non-openshift platforms when not specified.
ArgoCDKeycloakImage = "quay.io/keycloak/keycloak"

// ArgoCDDefaultLabelSelector is the default Label Selector which will reconcile all ArgoCD instances.
ArgoCDDefaultLabelSelector = ""

// ArgoCDKeycloakVersion is the default Keycloak version used for the non-openshift platform when not specified.
// Version: 15.0.2
ArgoCDKeycloakVersion = "sha256:64fb81886fde61dee55091e6033481fa5ccdac62ae30a4fd29b54eb5e97df6a9"
Expand Down
3 changes: 3 additions & 0 deletions common/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,7 @@ const (

// ArgoCDDexSecretKey is used to reference Dex secret from Argo CD secret into Argo CD configmap
ArgoCDDexSecretKey = "oidc.dex.clientSecret"

// Label Selector is an env variable for ArgoCD instance reconcilliation.
ArgoCDLabelSelectorKey = "ARGOCD_LABEL_SELECTOR"
)
3 changes: 3 additions & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ spec:
- /manager
args:
- --leader-elect
- --label-selector
image: controller:latest
name: manager
securityContext:
Expand All @@ -55,5 +56,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.annotations['olm.targetNamespaces']
- name: ARGOCD_LABEL_SELECTOR
value: ""
raghavi101 marked this conversation as resolved.
Show resolved Hide resolved
serviceAccountName: controller-manager
terminationGracePeriodSeconds: 10
15 changes: 15 additions & 0 deletions controllers/argocd/argocd_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"

ctrl "sigs.k8s.io/controller-runtime"
Expand All @@ -46,6 +47,8 @@ type ReconcileArgoCD struct {
ManagedNamespaces *corev1.NamespaceList
// Stores a list of SourceNamespaces as values
ManagedSourceNamespaces map[string]string
// Stores label selector used to reconcile a subset of ArgoCD
LabelSelector string
}

var log = logr.Log.WithName("controller_argocd")
Expand Down Expand Up @@ -105,6 +108,18 @@ func (r *ReconcileArgoCD) Reconcile(ctx context.Context, request ctrl.Request) (
return reconcile.Result{}, err
}

// Fetch labelSelector from r.LabelSelector (command-line option)
labelSelector, err := labels.Parse(r.LabelSelector)
if err != nil {
reqLogger.Info(fmt.Sprintf("error parsing the labelSelector '%s'.", labelSelector))
return reconcile.Result{}, err
}
// Match the value of labelSelector from ReconcileArgoCD to labels from the argocd instance
if !labelSelector.Matches(labels.Set(argocd.Labels)) {
reqLogger.Info(fmt.Sprintf("the ArgoCD instance '%s' does not match the label selector '%s' and skipping for reconciliation", request.NamespacedName, r.LabelSelector))
return reconcile.Result{}, fmt.Errorf("Error: failed to reconcile ArgoCD instance: '%s'", request.NamespacedName)
}

newPhase := argocd.Status.Phase
raghavi101 marked this conversation as resolved.
Show resolved Hide resolved
// If we discover a new Argo CD instance in a previously un-seen namespace
// we add it to the map and increment active instance count by phase
Expand Down
145 changes: 145 additions & 0 deletions controllers/argocd/argocd_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,151 @@ func TestReconcileArgoCD_Reconcile(t *testing.T) {
}
}

func TestReconcileArgoCD_LabelSelector(t *testing.T) {
raghavi101 marked this conversation as resolved.
Show resolved Hide resolved
logf.SetLogger(ZapLogger(true))
//ctx := context.Background()
a := makeTestArgoCD()
a.Name = "argo-test-1"
b := makeTestArgoCD()
b.Name = "argo-test-2"
c := makeTestArgoCD()
c.Name = "argo-test-3"
rt := makeTestReconciler(t, a, b, c)
assert.NoError(t, createNamespace(rt, a.Namespace, ""))

// All ArgoCD instance should be reconciled if no label-selctor is applied to the operator.
// No label selector provided and all argocd instances are reconciled

// Instance 'a'
req1 := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: a.Name,
Namespace: a.Namespace,
},
}
res1, err := rt.Reconcile(context.TODO(), req1)
assert.NoError(t, err)
if res1.Requeue {
t.Fatal("reconcile requeued request")
}

//Instance 'b'
req2 := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: b.Name,
Namespace: b.Namespace,
},
}
res2, err := rt.Reconcile(context.TODO(), req2)
assert.NoError(t, err)
if res2.Requeue {
t.Fatal("reconcile requeued request")
}

//Instance 'c'
req3 := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: c.Name,
Namespace: c.Namespace,
},
}
res3, err := rt.Reconcile(context.TODO(), req3)
assert.NoError(t, err)
if res3.Requeue {
t.Fatal("reconcile requeued request")
}

// Apply label-selector foo=bar to the operator but not to the argocd instances. No reconciliation will happen and an error is expected.
rt.LabelSelector = "foo=bar"
reqTest := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: a.Name,
Namespace: a.Namespace,
},
}
resTest, err := rt.Reconcile(context.TODO(), reqTest)
assert.Error(t, err)
if resTest.Requeue {
t.Fatal("reconcile requeued request")
}

//not reconciled should return error
reqTest2 := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: b.Name,
Namespace: b.Namespace,
},
}
resTest2, err := rt.Reconcile(context.TODO(), reqTest2)
assert.Error(t, err)
if resTest2.Requeue {
t.Fatal("reconcile requeued request")
}

//not reconciled should return error
reqTest3 := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: c.Name,
Namespace: c.Namespace,
},
}
resTest3, err := rt.Reconcile(context.TODO(), reqTest3)
assert.Error(t, err)
if resTest3.Requeue {
t.Fatal("reconcile requeued request")
}
}
func TestReconcileArgoCD_ReconcileLabel(t *testing.T) {
raghavi101 marked this conversation as resolved.
Show resolved Hide resolved

// Multiple ArgoCD instances present with matching label present on some and absent on some.
// Only instances matching the label are reconciled.

logf.SetLogger(ZapLogger(true))
ctx := context.Background()
a := makeTestArgoCD()
r1 := makeTestReconciler(t, a)
assert.NoError(t, createNamespace(r1, a.Namespace, ""))
b := makeTestArgoCD()
r2 := makeTestReconciler(t, b)
assert.NoError(t, createNamespace(r2, b.Namespace, ""))

// Apply label foo=bar to the argocd instance and to the operator for reconciliation without any error.
r1.LabelSelector = "foo=bar"
r2.LabelSelector = "foo=bar"

//Apply label to Instance 'a' but not to Instance 'b'
a.SetLabels(map[string]string{"foo": "bar"})
err := r1.Client.Update(ctx, a)
fatalIfError(t, err, "failed to update the ArgoCD: %s", err)
reqTest2 := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: a.Name,
Namespace: a.Namespace,
},
}
resTest2, err := r1.Reconcile(context.TODO(), reqTest2)

//Instance 'a' reconciled without error
assert.NoError(t, err)
if resTest2.Requeue {
t.Fatal("reconcile requeued request")
}

reqTest3 := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: b.Name,
Namespace: b.Namespace,
},
}
resTest3, err := r2.Reconcile(context.TODO(), reqTest3)
//Instance 'b' is not reconciled and an error is expeced
assert.Error(t, err)
if resTest3.Requeue {
t.Fatal("reconcile requeued request")
}

}

raghavi101 marked this conversation as resolved.
Show resolved Hide resolved
func TestReconcileArgoCD_Reconcile_RemoveManagedByLabelOnArgocdDeletion(t *testing.T) {
logf.SetLogger(ZapLogger(true))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1733,13 +1733,15 @@ spec:
containers:
- args:
- --leader-elect
- --label-selector
command:
- /manager
env:
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.annotations['olm.targetNamespaces']
- name: ARGOCD_LABEL_SELECTOR
- name: ENABLE_CONVERSION_WEBHOOK
value: "true"
image: quay.io/argoprojlabs/argocd-operator:v0.8.0
Expand Down
1 change: 1 addition & 0 deletions docs/usage/environment_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following environment variables are available in `argocd-operator`:
| `CONTROLLER_CLUSTER_ROLE` | none | Administrators can configure a common cluster role for all the managed namespaces in role bindings for the Argo CD application controller with this environment variable. Note: If this environment variable contains custom roles, the Operator doesn't create the default admin role. Instead, it uses the existing custom role for all managed namespaces. |
| `SERVER_CLUSTER_ROLE` | none | Administrators can configure a common cluster role for all the managed namespaces in role bindings for the Argo CD server with this environment variable. Note: If this environment variable contains custom roles, the Operator doesn’t create the default admin role. Instead, it uses the existing custom role for all managed namespaces. |
| `REMOVE_MANAGED_BY_LABEL_ON_ARGOCD_DELETION` | false | When an Argo CD instance is deleted, namespaces managed by that instance (via the `argocd.argoproj.io/managed-by` label ) will retain the label by default. Users can change this behavior by setting the environment variable `REMOVE_MANAGED_BY_LABEL_ON_ARGOCD_DELETION` to `true` in the Subscription. |
| `ARGOCD_LABEL_SELECTOR` | none | The label selector can be set on argocd-opertor by exporting `ARGOCD_LABEL_SELECTOR` (eg: `export ARGOCD_LABEL_SELECTOR=foo=bar`). The labels can be added to the argocd instances using the command `kubectl label argocd test1 foo=bar -n test-argocd`. This will enable the operator instance to be tailored to oversee only the corresponding ArgoCD instances having the matching label selector. |

Custom Environment Variables are supported in `applicationSet`, `controller`, `notifications`, `repo` and `server` components. For example:

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ require (
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
Expand Down Expand Up @@ -63,6 +64,7 @@ require (
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.43.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
raghavi101 marked this conversation as resolved.
Show resolved Hide resolved
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
Expand Down
Loading
Loading