Skip to content

Commit 3976ad1

Browse files
committed
ESO-396: incorporated review suggestions
Signed-off-by: Bharath B <bhb@redhat.com>
1 parent 728efda commit 3976ad1

7 files changed

Lines changed: 185 additions & 77 deletions

File tree

pkg/controller/external_secrets/controller.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -484,10 +484,7 @@ func (r *Reconciler) reconcileDeploymentFailureResult(
484484
errUpdate := r.updateStatusConditionsOnFailure(esc, degradedCond, readyCond, isFatal, reconcileErr)
485485

486486
if isFatal {
487-
if errUpdate != nil {
488-
return ctrl.Result{}, errUpdate
489-
}
490-
return ctrl.Result{}, reconcileErr
487+
return ctrl.Result{}, errUpdate
491488
}
492489
if isUserConfig {
493490
return userConfigurationFailureResult(reconcileErr, errUpdate)

pkg/controller/external_secrets/controller_test.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,12 +261,14 @@ func TestReconcileDeploymentFailureResult(t *testing.T) {
261261
),
262262
)
263263
irrecoverableErr := common.NewIrrecoverableError(errors.New("forbidden"), "permission denied")
264+
statusUpdateErr := errors.New("status update failed")
264265
retryErr := common.NewRetryRequiredError(errors.New("timeout"), "temporary failure")
265266
proxyErr := common.NewUserConfigurationError(errors.New("invalid proxy URL configured"), "proxy configuration validation failed")
266267

267268
tests := []struct {
268269
name string
269270
reconcileErr error
271+
statusUpdateErr error
270272
wantRequeue time.Duration
271273
wantReturnError error
272274
}{
@@ -276,9 +278,14 @@ func TestReconcileDeploymentFailureResult(t *testing.T) {
276278
wantRequeue: common.DefaultRequeueTime,
277279
},
278280
{
279-
name: "irrecoverable error does not requeue",
281+
name: "irrecoverable error does not requeue",
282+
reconcileErr: irrecoverableErr,
283+
},
284+
{
285+
name: "irrecoverable error returns status update failure",
280286
reconcileErr: irrecoverableErr,
281-
wantReturnError: irrecoverableErr,
287+
statusUpdateErr: statusUpdateErr,
288+
wantReturnError: statusUpdateErr,
282289
},
283290
{
284291
name: "proxy configuration error waits for CR update",
@@ -303,7 +310,7 @@ func TestReconcileDeploymentFailureResult(t *testing.T) {
303310
return nil
304311
})
305312
mock.StatusUpdateCalls(func(_ context.Context, _ client.Object, _ ...client.SubResourceUpdateOption) error {
306-
return nil
313+
return tt.statusUpdateErr
307314
})
308315
r.CtrlClient = mock
309316

@@ -314,7 +321,10 @@ func TestReconcileDeploymentFailureResult(t *testing.T) {
314321
1,
315322
)
316323
if tt.wantReturnError != nil {
317-
if err == nil || err.Error() != tt.wantReturnError.Error() {
324+
if err == nil {
325+
t.Fatalf("reconcileDeploymentFailureResult() err = nil, want %v", tt.wantReturnError)
326+
}
327+
if err.Error() != tt.wantReturnError.Error() && !strings.Contains(err.Error(), tt.wantReturnError.Error()) {
318328
t.Fatalf("reconcileDeploymentFailureResult() err = %v, want %v", err, tt.wantReturnError)
319329
}
320330
} else if err != nil {

pkg/controller/external_secrets/deployments.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ func (r *Reconciler) createOrApplyDeploymentFromAsset(esc *operatorv1alpha1.Exte
7070
externalSecretsConfigCreateRecon bool,
7171
) error {
7272
deployment, trustedCAErr := r.getDeploymentObject(assetName, esc, resourceMetadata)
73+
// trustedCABundle may fail in getDeploymentObject (e.g. missing ConfigMap) while still
74+
// returning a deployment with the stale user-ca-bundle mount removed. Apply that spec
75+
// first, then return the error so status becomes Degraded and the reconcile requeues.
7376
if deployment == nil {
7477
return trustedCAErr
7578
}
@@ -80,29 +83,35 @@ func (r *Reconciler) createOrApplyDeploymentFromAsset(esc *operatorv1alpha1.Exte
8083
if err != nil {
8184
return common.FromClientError(err, "failed to check %s deployment resource already exists", deploymentName)
8285
}
83-
if exist && externalSecretsConfigCreateRecon {
84-
r.eventRecorder.Eventf(esc, corev1.EventTypeWarning, "ResourceAlreadyExists", "%s deployment resource already exists", deploymentName)
85-
}
86-
switch {
87-
case exist && common.HasObjectChanged(deployment, fetched, &resourceMetadata):
88-
r.log.V(1).Info("deployment has been modified, updating to desired state", "name", deploymentName)
89-
common.RemoveObsoleteAnnotations(deployment, resourceMetadata)
90-
if err := r.UpdateWithRetry(r.ctx, deployment); err != nil {
91-
return common.FromClientError(err, "failed to update %s deployment resource", deploymentName)
92-
}
93-
r.eventRecorder.Eventf(esc, corev1.EventTypeNormal, "Reconciled", "deployment resource %s updated", deploymentName)
94-
case !exist:
86+
87+
if !exist {
9588
if err := r.Create(r.ctx, deployment); err != nil {
9689
return common.FromClientError(err, "failed to create %s deployment resource", deploymentName)
9790
}
9891
r.eventRecorder.Eventf(esc, corev1.EventTypeNormal, "Reconciled", "deployment resource %s created", deploymentName)
99-
default:
92+
return trustedCAErr
93+
}
94+
95+
if externalSecretsConfigCreateRecon {
96+
r.eventRecorder.Eventf(esc, corev1.EventTypeWarning, "ResourceAlreadyExists", "%s deployment resource already exists", deploymentName)
97+
}
98+
99+
if !common.HasObjectChanged(deployment, fetched, &resourceMetadata) {
100100
r.log.V(4).Info("deployment resource already exists and is in expected state", "name", deploymentName)
101+
return trustedCAErr
102+
}
103+
104+
r.log.V(1).Info("deployment has been modified, updating to desired state", "name", deploymentName)
105+
common.RemoveObsoleteAnnotations(deployment, resourceMetadata)
106+
if err := r.UpdateWithRetry(r.ctx, deployment); err != nil {
107+
return common.FromClientError(err, "failed to update %s deployment resource", deploymentName)
101108
}
109+
r.eventRecorder.Eventf(esc, corev1.EventTypeNormal, "Reconciled", "deployment resource %s updated", deploymentName)
102110

103111
if trustedCAErr != nil {
104112
return trustedCAErr
105113
}
114+
106115
return nil
107116
}
108117

@@ -233,7 +242,7 @@ func (r *Reconciler) updateResourceRequirement(deployment *appsv1.Deployment, es
233242
switch {
234243
case esc.Spec.ApplicationConfig.Resources != nil:
235244
esc.Spec.ApplicationConfig.Resources.DeepCopyInto(&rscReqs)
236-
case r.esm != nil && r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.Resources != nil:
245+
case r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.Resources != nil:
237246
r.esm.Spec.GlobalConfig.Resources.DeepCopyInto(&rscReqs)
238247
default:
239248
return nil
@@ -265,7 +274,7 @@ func (r *Reconciler) updateNodeSelector(deployment *appsv1.Deployment, esc *oper
265274

266275
if esc.Spec.ApplicationConfig.NodeSelector != nil {
267276
nodeSelector = esc.Spec.ApplicationConfig.NodeSelector
268-
} else if r.esm != nil && r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.NodeSelector != nil {
277+
} else if r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.NodeSelector != nil {
269278
nodeSelector = r.esm.Spec.GlobalConfig.NodeSelector
270279
}
271280

@@ -287,7 +296,7 @@ func (r *Reconciler) updateAffinityRules(deployment *appsv1.Deployment, esc *ope
287296

288297
if esc.Spec.ApplicationConfig.Affinity != nil {
289298
affinity = esc.Spec.ApplicationConfig.Affinity
290-
} else if r.esm != nil && r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.Affinity != nil {
299+
} else if r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.Affinity != nil {
291300
affinity = r.esm.Spec.GlobalConfig.Affinity
292301
}
293302

@@ -309,7 +318,7 @@ func (r *Reconciler) updatePodTolerations(deployment *appsv1.Deployment, esc *op
309318

310319
if esc.Spec.ApplicationConfig.Tolerations != nil {
311320
tolerations = esc.Spec.ApplicationConfig.Tolerations
312-
} else if r.esm != nil && r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.Tolerations != nil {
321+
} else if r.esm.Spec.GlobalConfig != nil && r.esm.Spec.GlobalConfig.Tolerations != nil {
313322
tolerations = r.esm.Spec.GlobalConfig.Tolerations
314323
}
315324

pkg/controller/external_secrets/deployments_test.go

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1999,7 +1999,7 @@ func TestApplyUserDeploymentConfigsWithOverrideEnv(t *testing.T) {
19991999

20002000
for _, tt := range tests {
20012001
t.Run(tt.name, func(t *testing.T) {
2002-
r := &Reconciler{}
2002+
r := testReconciler(t)
20032003
initEnv := []corev1.EnvVar{{Name: "INIT_ONLY_VAR", Value: "init-value"}}
20042004
deployment := &appsv1.Deployment{
20052005
Spec: appsv1.DeploymentSpec{
@@ -2395,3 +2395,81 @@ func TestApplyUserCABundleConfig(t *testing.T) {
23952395
})
23962396
}
23972397
}
2398+
2399+
func TestCreateOrApplyDeploymentFromAssetReturnsTrustedCAError(t *testing.T) {
2400+
esc := commontest.TestExternalSecretsConfig()
2401+
esc.Spec.ControllerConfig.TrustedCABundle = &v1alpha1.ConfigMapKeyReference{
2402+
Name: "user-ca-bundle",
2403+
Key: UserCABundleKeyPath,
2404+
}
2405+
resourceMetadata := testResourceMetadata(esc)
2406+
2407+
t.Setenv("RELATED_IMAGE_EXTERNAL_SECRETS", commontest.TestExternalSecretsImageName)
2408+
t.Setenv("RELATED_IMAGE_BITWARDEN_SDK_SERVER", commontest.TestBitwardenImageName)
2409+
2410+
setupMissingUserCAClients := func() (*fakes.FakeCtrlClient, *fakes.FakeCtrlClient) {
2411+
cached := &fakes.FakeCtrlClient{}
2412+
uncached := &fakes.FakeCtrlClient{}
2413+
notFound := func(_ context.Context, ns types.NamespacedName, _ client.Object) error {
2414+
return apierrors.NewNotFound(corev1.Resource("configmaps"), ns.Name)
2415+
}
2416+
cached.GetCalls(notFound)
2417+
uncached.GetCalls(notFound)
2418+
return cached, uncached
2419+
}
2420+
2421+
newReconciler := func(cached, uncached *fakes.FakeCtrlClient) *Reconciler {
2422+
r := testReconciler(t)
2423+
r.CtrlClient = cached
2424+
r.UncachedClient = uncached
2425+
return r
2426+
}
2427+
2428+
t.Run("returns TrustedCABundleError when deployment is unchanged", func(t *testing.T) {
2429+
t.Parallel()
2430+
2431+
cached, uncached := setupMissingUserCAClients()
2432+
r := newReconciler(cached, uncached)
2433+
2434+
desired, trustedCAErr := r.getDeploymentObject(controllerDeploymentAssetName, esc, resourceMetadata)
2435+
if trustedCAErr == nil {
2436+
t.Fatal("expected trustedCAErr from missing ConfigMap")
2437+
}
2438+
if !common.IsUserConfigurationNotFound(trustedCAErr) {
2439+
t.Fatalf("expected NotFound user configuration error, got %v", trustedCAErr)
2440+
}
2441+
2442+
cached.ExistsCalls(func(_ context.Context, _ types.NamespacedName, obj client.Object) (bool, error) {
2443+
desired.DeepCopyInto(obj.(*appsv1.Deployment))
2444+
return true, nil
2445+
})
2446+
2447+
err := r.createOrApplyDeploymentFromAsset(esc, controllerDeploymentAssetName, resourceMetadata, false)
2448+
if err == nil {
2449+
t.Fatal("createOrApplyDeploymentFromAsset() error = nil, want TrustedCABundleError")
2450+
}
2451+
if !common.IsUserConfigurationNotFound(err) {
2452+
t.Fatalf("expected NotFound user configuration error, got %v", err)
2453+
}
2454+
})
2455+
2456+
t.Run("returns TrustedCABundleError after create", func(t *testing.T) {
2457+
t.Parallel()
2458+
2459+
cached, uncached := setupMissingUserCAClients()
2460+
r := newReconciler(cached, uncached)
2461+
2462+
cached.ExistsCalls(doesNotExist())
2463+
cached.CreateCalls(func(context.Context, client.Object, ...client.CreateOption) error {
2464+
return nil
2465+
})
2466+
2467+
err := r.createOrApplyDeploymentFromAsset(esc, controllerDeploymentAssetName, resourceMetadata, false)
2468+
if err == nil {
2469+
t.Fatal("createOrApplyDeploymentFromAsset() error = nil, want TrustedCABundleError")
2470+
}
2471+
if !common.IsUserConfigurationNotFound(err) {
2472+
t.Fatalf("expected NotFound user configuration error, got %v", err)
2473+
}
2474+
})
2475+
}

pkg/controller/external_secrets/install_external_secrets.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,25 @@ func (r *Reconciler) createOrApplyNamespace(esc *operatorv1alpha1.ExternalSecret
160160
return fmt.Errorf("failed to check if namespace %s exists: %w", namespaceName, err)
161161
}
162162

163-
switch {
164-
case !exists:
163+
if !exists {
165164
r.log.V(4).Info("Creating namespace", "name", namespaceName)
166165
if err := r.Create(r.ctx, desired); err != nil {
167166
return fmt.Errorf("failed to create namespace %s: %w", namespaceName, err)
168167
}
169168
r.eventRecorder.Eventf(esc, corev1.EventTypeNormal, "Reconciled", "Namespace %s created", namespaceName)
170-
case r.resourceMetadataNeedsUpdate(fetched, resourceMetadata):
171-
if err := r.UpdateWithRetry(r.ctx, fetched); err != nil {
172-
return fmt.Errorf("failed to update namespace %s: %w", namespaceName, err)
173-
}
174-
r.eventRecorder.Eventf(esc, corev1.EventTypeNormal, "Reconciled", "Namespace %s updated", namespaceName)
175-
default:
169+
return nil
170+
}
171+
172+
if !r.resourceMetadataNeedsUpdate(fetched, resourceMetadata) {
176173
r.log.V(4).Info("Namespace already exists in desired state", "name", namespaceName)
174+
return nil
175+
}
176+
177+
r.log.V(1).Info("Namespace has been modified, updating to desired state", "name", namespaceName)
178+
if err := r.UpdateWithRetry(r.ctx, fetched); err != nil {
179+
return fmt.Errorf("failed to update namespace %s: %w", namespaceName, err)
177180
}
181+
r.eventRecorder.Eventf(esc, corev1.EventTypeNormal, "Reconciled", "Namespace %s updated", namespaceName)
178182

179183
return nil
180184
}
@@ -258,7 +262,7 @@ func (r *Reconciler) getResourceMetadata(esc *operatorv1alpha1.ExternalSecretsCo
258262
// and defaultLabels have the highest priority. Labels matching DisallowedLabelMatcher are skipped.
259263
func (r *Reconciler) getResourceLabels(esc *operatorv1alpha1.ExternalSecretsConfig, resourceMetadata *common.ResourceMetadata) {
260264
resourceMetadata.Labels = make(map[string]string)
261-
if r.esm != nil && common.IsESMSpecEmpty(r.esm) && r.esm.Spec.GlobalConfig != nil {
265+
if common.IsESMSpecEmpty(r.esm) && r.esm.Spec.GlobalConfig != nil {
262266
for k, v := range r.esm.Spec.GlobalConfig.Labels {
263267
if disallowedLabelMatcher.MatchString(k) {
264268
r.log.V(1).Info("skip adding unallowed label configured in externalsecretsmanagers.operator.openshift.io", "label", k, "value", v)

0 commit comments

Comments
 (0)