Skip to content

Commit 6ba2568

Browse files
Merge branch 'master' into alkumari/rec-labels
2 parents 5b04c90 + ca764d0 commit 6ba2568

21 files changed

+1102
-464
lines changed

cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/argoproj-labs/argocd-operator/common"
3838
"github.com/argoproj-labs/argocd-operator/controllers/argocd"
3939
"github.com/argoproj-labs/argocd-operator/controllers/argocdexport"
40+
"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
4041

4142
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
4243

@@ -243,6 +244,7 @@ func main() {
243244
LocalUsers: &argocd.LocalUsersInfo{
244245
TokenRenewalTimers: map[string]*argocd.TokenRenewalTimer{},
245246
},
247+
FipsConfigChecker: argoutil.NewLinuxFipsConfigChecker(),
246248
}).SetupWithManager(mgr); err != nil {
247249
setupLog.Error(err, "unable to create controller", "controller", "ArgoCD")
248250
os.Exit(1)

controllers/argocd/argocd_controller.go

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ import (
2626

2727
argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
2828
"github.com/argoproj-labs/argocd-operator/common"
29+
"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
2930

3031
corev1 "k8s.io/api/core/v1"
3132
"k8s.io/apimachinery/pkg/api/errors"
3233
"k8s.io/apimachinery/pkg/labels"
3334
"k8s.io/apimachinery/pkg/runtime"
3435
"k8s.io/apimachinery/pkg/types"
35-
3636
"k8s.io/client-go/kubernetes"
3737

3838
ctrl "sigs.k8s.io/controller-runtime"
@@ -83,6 +83,8 @@ type ReconcileArgoCD struct {
8383

8484
K8sClient kubernetes.Interface
8585
LocalUsers *LocalUsersInfo
86+
// FipsConfigChecker checks if the deployment needs FIPS specific environment variables set.
87+
FipsConfigChecker argoutil.FipsConfigChecker
8688
}
8789

8890
var log = logr.Log.WithName("controller_argocd")
@@ -124,22 +126,32 @@ var ActiveInstanceMap = make(map[string]string)
124126
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
125127
func (r *ReconcileArgoCD) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
126128

127-
result, argocd, err := r.internalReconcile(ctx, request)
129+
result, argocd, argocdStatus, err := r.internalReconcile(ctx, request)
128130

129131
message := ""
130132
if err != nil {
131133
message = err.Error()
134+
argocdStatus.Phase = "Failed" // Any error should reset phase back to Failed
135+
}
136+
137+
log.Info("reconciling status")
138+
if reconcileStatusErr := r.reconcileStatus(argocd, argocdStatus); reconcileStatusErr != nil {
139+
log.Error(reconcileStatusErr, "Unable to reconcile status")
140+
argocdStatus.Phase = "Failed"
141+
message = "unable to reconcile ArgoCD CR .status field"
132142
}
133143

134-
if error := updateStatusConditionOfArgoCD(ctx, createCondition(message), argocd, r.Client, log); error != nil {
135-
log.Error(error, "unable to update status of ArgoCD")
136-
return reconcile.Result{}, error
144+
if updateStatusErr := updateStatusConditionOfArgoCD(ctx, createCondition(message), argocd, argocdStatus, r.Client, log); updateStatusErr != nil {
145+
log.Error(updateStatusErr, "unable to update status of ArgoCD")
146+
return reconcile.Result{}, updateStatusErr
137147
}
138148

139149
return result, err
140150
}
141151

142-
func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, *argoproj.ArgoCD, error) {
152+
func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, *argoproj.ArgoCD, *argoproj.ArgoCDStatus, error) {
153+
154+
argoCDStatus := &argoproj.ArgoCDStatus{} // Start with a blank canvas
143155

144156
reconcileStartTS := time.Now()
145157
defer func() {
@@ -156,10 +168,10 @@ func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Re
156168
// Request object not found, could have been deleted after reconcile request.
157169
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
158170
// Return and don't requeue
159-
return reconcile.Result{}, argocd, nil
171+
return reconcile.Result{}, argocd, argoCDStatus, nil
160172
}
161173
// Error reading the object - requeue the request.
162-
return reconcile.Result{}, argocd, err
174+
return reconcile.Result{}, argocd, argoCDStatus, err
163175
}
164176

165177
// If the number of notification replicas is greater than 1, display a warning.
@@ -171,14 +183,14 @@ func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Re
171183
labelSelector, err := labels.Parse(r.LabelSelector)
172184
if err != nil {
173185
message := fmt.Sprintf("error parsing the labelSelector '%s'.", labelSelector)
174-
reqLogger.Info(message)
175-
return reconcile.Result{}, argocd, fmt.Errorf("%s error: %w", message, err)
186+
reqLogger.Error(err, message)
187+
return reconcile.Result{}, argocd, argoCDStatus, fmt.Errorf("%s error: %w", message, err)
176188
}
177189

178190
// Match the value of labelSelector from ReconcileArgoCD to labels from the argocd instance
179191
if !labelSelector.Matches(labels.Set(argocd.Labels)) {
180-
reqLogger.Info(fmt.Sprintf("the ArgoCD instance '%s' does not match the label selector '%s' and skipping for reconciliation", request.NamespacedName, r.LabelSelector))
181-
return reconcile.Result{}, argocd, fmt.Errorf("the ArgoCD instance '%s' does not match the label selector '%s' and skipping for reconciliation", request.NamespacedName, r.LabelSelector)
192+
reqLogger.Error(nil, fmt.Sprintf("the ArgoCD instance '%s' does not match the label selector '%s' and skipping for reconciliation", request.NamespacedName, r.LabelSelector))
193+
return reconcile.Result{}, argocd, argoCDStatus, fmt.Errorf("the ArgoCD instance '%s' does not match the label selector '%s' and skipping for reconciliation", request.NamespacedName, r.LabelSelector)
182194
}
183195

184196
newPhase := argocd.Status.Phase
@@ -207,6 +219,8 @@ func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Re
207219

208220
if argocd.GetDeletionTimestamp() != nil {
209221

222+
argoCDStatus.Phase = "Unknown" // Set to Unknown since we are in the process of deleting ArgoCD CR
223+
210224
// Argo CD instance marked for deletion; remove entry from activeInstances map and decrement active instance count
211225
// by phase as well as total
212226
delete(ActiveInstanceMap, argocd.Namespace)
@@ -220,74 +234,69 @@ func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Re
220234

221235
if argocd.IsDeletionFinalizerPresent() {
222236
if err := r.deleteClusterResources(argocd); err != nil {
223-
return reconcile.Result{}, argocd, fmt.Errorf("failed to delete ClusterResources: %w", err)
237+
return reconcile.Result{}, argocd, argoCDStatus, fmt.Errorf("failed to delete ClusterResources: %w", err)
224238
}
225239

226240
if isRemoveManagedByLabelOnArgoCDDeletion() {
227241
if err := r.removeManagedByLabelFromNamespaces(argocd.Namespace); err != nil {
228-
return reconcile.Result{}, argocd, fmt.Errorf("failed to remove label from namespace[%v], error: %w", argocd.Namespace, err)
242+
return reconcile.Result{}, argocd, argoCDStatus, fmt.Errorf("failed to remove label from namespace[%v], error: %w", argocd.Namespace, err)
229243
}
230244
}
231245

232246
if err := r.removeUnmanagedSourceNamespaceResources(argocd); err != nil {
233-
return reconcile.Result{}, argocd, fmt.Errorf("failed to remove resources from sourceNamespaces, error: %w", err)
247+
return reconcile.Result{}, argocd, argoCDStatus, fmt.Errorf("failed to remove resources from sourceNamespaces, error: %w", err)
234248
}
235249

236250
if err := r.removeUnmanagedApplicationSetSourceNamespaceResources(argocd); err != nil {
237-
return reconcile.Result{}, argocd, fmt.Errorf("failed to remove resources from applicationSetSourceNamespaces, error: %w", err)
251+
return reconcile.Result{}, argocd, argoCDStatus, fmt.Errorf("failed to remove resources from applicationSetSourceNamespaces, error: %w", err)
238252
}
239253

240254
if err := r.removeDeletionFinalizer(argocd); err != nil {
241-
return reconcile.Result{}, argocd, err
255+
return reconcile.Result{}, argocd, argoCDStatus, err
242256
}
243257

244258
// remove namespace of deleted Argo CD instance from deprecationEventEmissionTracker (if exists) so that if another instance
245259
// is created in the same namespace in the future, that instance is appropriately tracked
246260
delete(DeprecationEventEmissionTracker, argocd.Namespace)
247261
}
248262

249-
return reconcile.Result{}, argocd, nil
263+
return reconcile.Result{}, argocd, argoCDStatus, nil
250264
}
251265

252266
if !argocd.IsDeletionFinalizerPresent() {
253267
if err := r.addDeletionFinalizer(argocd); err != nil {
254-
return reconcile.Result{}, argocd, err
268+
return reconcile.Result{}, argocd, argoCDStatus, err
255269
}
256270
}
257271

258-
// get the latest version of argocd instance before reconciling
259-
if err = r.Get(ctx, request.NamespacedName, argocd); err != nil {
260-
return reconcile.Result{}, argocd, err
261-
}
262-
263272
if err = r.setManagedNamespaces(argocd); err != nil {
264-
return reconcile.Result{}, argocd, err
273+
return reconcile.Result{}, argocd, argoCDStatus, err
265274
}
266275

267276
if err = r.setManagedSourceNamespaces(argocd); err != nil {
268-
return reconcile.Result{}, argocd, err
277+
return reconcile.Result{}, argocd, argoCDStatus, err
269278
}
270279

271280
if err = r.setManagedApplicationSetSourceNamespaces(argocd); err != nil {
272-
return reconcile.Result{}, argocd, err
281+
return reconcile.Result{}, argocd, argoCDStatus, err
273282
}
274283

275284
// Handle NamespaceManagement reconciliation and check if Namespace Management is enabled via the Subscription env variable.
276285
if isNamespaceManagementEnabled() {
277286
if err := r.reconcileNamespaceManagement(argocd); err != nil {
278-
return reconcile.Result{}, argocd, err
287+
return reconcile.Result{}, argocd, argoCDStatus, err
279288
}
280289
} else if argocd.Spec.NamespaceManagement != nil {
281290
k8sClient := r.K8sClient
282291
if err := r.disableNamespaceManagement(argocd, k8sClient); err != nil {
283292
log.Error(err, "Failed to disable NamespaceManagement feature")
284-
return reconcile.Result{}, argocd, err
293+
return reconcile.Result{}, argocd, argoCDStatus, err
285294
}
286295
} else if len(argocd.Spec.NamespaceManagement) == 0 {
287296
// Handle cleanup of NamespaceManagement RBAC when the feature is removed from the ArgoCD CR.
288297
nsMgmtList := &argoproj.NamespaceManagementList{}
289298
if err := r.List(context.TODO(), nsMgmtList); err != nil {
290-
return reconcile.Result{}, argocd, err
299+
return reconcile.Result{}, argocd, argoCDStatus, err
291300
}
292301

293302
k8sClient := r.K8sClient
@@ -301,7 +310,7 @@ func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Re
301310
namespace := &corev1.Namespace{}
302311
if err := r.Get(ctx, types.NamespacedName{Name: nsMgmt.Namespace}, namespace); err != nil {
303312
log.Error(err, fmt.Sprintf("unable to fetch namespace %s", nsMgmt.Namespace))
304-
return reconcile.Result{}, argocd, err
313+
return reconcile.Result{}, argocd, argoCDStatus, err
305314
}
306315

307316
// Skip RBAC deletion if the namespace has the "managed-by" label
@@ -313,13 +322,13 @@ func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Re
313322
// Remove roles and rolebindings
314323
if err := deleteRBACsForNamespace(nsMgmt.Namespace, k8sClient); err != nil {
315324
log.Error(err, fmt.Sprintf("Failed to delete RBACs for namespace: %s", nsMgmt.Namespace))
316-
return reconcile.Result{}, argocd, err
325+
return reconcile.Result{}, argocd, argoCDStatus, err
317326
}
318327
log.Info(fmt.Sprintf("Successfully removed RBACs for namespace: %s", nsMgmt.Namespace))
319328

320329
if err := deleteManagedNamespaceFromClusterSecret(argocd.Namespace, nsMgmt.Namespace, k8sClient); err != nil {
321330
log.Error(err, fmt.Sprintf("Unable to delete namespace %s from cluster secret", nsMgmt.Namespace))
322-
return reconcile.Result{}, argocd, err
331+
return reconcile.Result{}, argocd, argoCDStatus, err
323332
}
324333

325334
}
@@ -328,13 +337,13 @@ func (r *ReconcileArgoCD) internalReconcile(ctx context.Context, request ctrl.Re
328337
// Process DropMetadata for namespace-based label cleanup
329338
r.processDropMetadataForCleanup(argocd)
330339

331-
if err := r.reconcileResources(argocd); err != nil {
340+
if err := r.reconcileResources(argocd, argoCDStatus); err != nil {
332341
// Error reconciling ArgoCD sub-resources - requeue the request.
333-
return reconcile.Result{}, argocd, err
342+
return reconcile.Result{}, argocd, argoCDStatus, err
334343
}
335344

336345
// Return and don't requeue
337-
return reconcile.Result{}, argocd, nil
346+
return reconcile.Result{}, argocd, argoCDStatus, nil
338347
}
339348

340349
// SetupWithManager sets up the controller with the Manager.

controllers/argocd/argocd_controller_test.go

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

2828
"github.com/stretchr/testify/assert"
2929
appsv1 "k8s.io/api/apps/v1"
30-
v1 "k8s.io/api/rbac/v1"
30+
rbacv1 "k8s.io/api/rbac/v1"
3131
apierrors "k8s.io/apimachinery/pkg/api/errors"
3232
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3333
"k8s.io/apimachinery/pkg/runtime"
@@ -78,6 +78,110 @@ func TestReconcileArgoCD_Reconcile_with_deleted(t *testing.T) {
7878
}
7979
}
8080

81+
// TestReconcileArgoCD_DexWorkloads verifies that when dex is enabled, that the appropriate operator resources are created. When dex is disabled, the objects are verified to be removed.
82+
func TestReconcileArgoCD_DexWorkloads(t *testing.T) {
83+
logf.SetLogger(ZapLogger(true))
84+
a := makeTestArgoCD()
85+
86+
a.Spec.SSO = &argoproj.ArgoCDSSOSpec{
87+
Provider: argoproj.SSOProviderTypeDex,
88+
Dex: &argoproj.ArgoCDDexSpec{
89+
Config: "test-config",
90+
OpenShiftOAuth: false,
91+
},
92+
}
93+
94+
resObjs := []client.Object{a}
95+
subresObjs := []client.Object{a}
96+
runtimeObjs := []runtime.Object{}
97+
sch := makeTestReconcilerScheme(argoproj.AddToScheme)
98+
cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
99+
r := makeTestReconciler(cl, sch, testclient.NewSimpleClientset())
100+
101+
assert.NoError(t, createNamespace(r, a.Namespace, ""))
102+
103+
req := reconcile.Request{
104+
NamespacedName: types.NamespacedName{
105+
Name: a.Name,
106+
Namespace: a.Namespace,
107+
},
108+
}
109+
110+
_, err := r.Reconcile(context.TODO(), req)
111+
assert.NoError(t, err)
112+
113+
objectsToVerify := []client.Object{}
114+
115+
dexRole := &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-dex-server", Namespace: a.Namespace}}
116+
objectsToVerify = append(objectsToVerify, dexRole)
117+
118+
dexRoleBinding := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-dex-server", Namespace: a.Namespace}}
119+
objectsToVerify = append(objectsToVerify, dexRoleBinding)
120+
121+
dexServiceAccount := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-dex-server", Namespace: a.Namespace}}
122+
objectsToVerify = append(objectsToVerify, dexServiceAccount)
123+
124+
dexService := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "argocd-dex-server", Namespace: a.Namespace}}
125+
objectsToVerify = append(objectsToVerify, dexService)
126+
127+
dexDeployment := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "argocd-dex-server", Namespace: a.Namespace}}
128+
objectsToVerify = append(objectsToVerify, dexDeployment)
129+
130+
for _, objectToVerify := range objectsToVerify {
131+
t.Logf("verifying object %s", objectToVerify.GetName())
132+
err = r.Get(context.TODO(), client.ObjectKeyFromObject(objectToVerify), objectToVerify)
133+
assert.NoError(t, err)
134+
assert.True(t, len(objectToVerify.GetOwnerReferences()) > 0)
135+
}
136+
137+
var secretList corev1.SecretList
138+
err = r.List(context.TODO(), &secretList, client.InNamespace(a.Namespace))
139+
assert.NoError(t, err)
140+
141+
configMap := &corev1.ConfigMap{
142+
ObjectMeta: metav1.ObjectMeta{
143+
Name: "argocd-cm",
144+
Namespace: a.Namespace,
145+
},
146+
}
147+
err = r.Get(context.TODO(), client.ObjectKeyFromObject(configMap), configMap)
148+
assert.NoError(t, err)
149+
150+
assert.Equal(t, configMap.Data["dex.config"], a.Spec.SSO.Dex.Config)
151+
152+
var dexSecret *corev1.Secret
153+
154+
for idx := range secretList.Items {
155+
secret := secretList.Items[idx]
156+
if strings.HasPrefix(secret.Name, "argocd-dex-server-token-") {
157+
dexSecret = &secret
158+
break
159+
}
160+
}
161+
assert.NotNil(t, dexSecret)
162+
163+
err = r.Get(context.TODO(), client.ObjectKeyFromObject(a), a)
164+
assert.NoError(t, err)
165+
166+
a.Spec.SSO = nil
167+
err = r.Update(context.TODO(), a)
168+
assert.NoError(t, err)
169+
170+
_, err = r.Reconcile(context.TODO(), req)
171+
assert.NoError(t, err)
172+
173+
for _, objectToVerify := range objectsToVerify {
174+
err = r.Get(context.TODO(), client.ObjectKeyFromObject(objectToVerify), objectToVerify)
175+
assert.Error(t, err)
176+
}
177+
178+
err = r.Get(context.TODO(), client.ObjectKeyFromObject(configMap), configMap)
179+
assert.NoError(t, err)
180+
181+
assert.Equal(t, configMap.Data["dex.config"], "")
182+
183+
}
184+
81185
func TestReconcileArgoCD_Reconcile(t *testing.T) {
82186
logf.SetLogger(ZapLogger(true))
83187
a := makeTestArgoCD()
@@ -313,11 +417,11 @@ func TestReconcileArgoCD_CleanUp(t *testing.T) {
313417
}{
314418
{
315419
fmt.Sprintf("ClusterRole %s", common.ArgoCDApplicationControllerComponent),
316-
newClusterRole(common.ArgoCDApplicationControllerComponent, []v1.PolicyRule{}, a),
420+
newClusterRole(common.ArgoCDApplicationControllerComponent, []rbacv1.PolicyRule{}, a),
317421
},
318422
{
319423
fmt.Sprintf("ClusterRole %s", common.ArgoCDServerComponent),
320-
newClusterRole(common.ArgoCDServerComponent, []v1.PolicyRule{}, a),
424+
newClusterRole(common.ArgoCDServerComponent, []rbacv1.PolicyRule{}, a),
321425
},
322426
{
323427
fmt.Sprintf("ClusterRoleBinding %s", common.ArgoCDApplicationControllerComponent),
@@ -355,8 +459,8 @@ func addFinalizer(finalizerParam string) argoCDOpt { //nolint:unparam
355459

356460
func clusterResources(argocd *argoproj.ArgoCD) []client.Object {
357461
return []client.Object{
358-
newClusterRole(common.ArgoCDApplicationControllerComponent, []v1.PolicyRule{}, argocd),
359-
newClusterRole(common.ArgoCDServerComponent, []v1.PolicyRule{}, argocd),
462+
newClusterRole(common.ArgoCDApplicationControllerComponent, []rbacv1.PolicyRule{}, argocd),
463+
newClusterRole(common.ArgoCDServerComponent, []rbacv1.PolicyRule{}, argocd),
360464
newClusterRoleBindingWithname(common.ArgoCDApplicationControllerComponent, argocd),
361465
newClusterRoleBindingWithname(common.ArgoCDServerComponent, argocd),
362466
}

0 commit comments

Comments
 (0)