Skip to content

Commit 728efda

Browse files
committed
ESO-396: Refactor Proxy NetworkPolicy and user CA bundle implementation for improved handling
Signed-off-by: Bharath B <bhb@redhat.com>
1 parent 059d02b commit 728efda

19 files changed

Lines changed: 856 additions & 830 deletions

bindata/external-secrets/networkpolicy_allow-dns.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ spec:
3333
- protocol: UDP
3434
port: 53
3535
policyTypes:
36-
- Egress
36+
- Egress

pkg/controller/common/errors.go

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@ const (
2727
// The operator sets Degraded. Recovery is driven by watches on the affected resource;
2828
// NotFound errors still use periodic requeue until the referenced object exists.
2929
UserConfigurationError ErrorReason = "UserConfigurationError"
30-
31-
// UserTrustedCABundleError indicates user configured trustedCABundle is invalid or incomplete.
32-
// The operator sets Degraded. Recovery for existing ConfigMaps is driven by ConfigMap watches;
33-
// NotFound errors still use periodic requeue until the ConfigMap is created.
34-
UserTrustedCABundleError ErrorReason = "UserTrustedCABundleError"
3530
)
3631

3732
// ReconcileError represents an error that occurred during reconciliation.
@@ -88,18 +83,6 @@ func NewUserConfigurationError(err error, message string, args ...any) *Reconcil
8883
}
8984
}
9085

91-
// NewUserTrustedCABundleError creates a ReconcileError for user trustedCABundle misconfiguration.
92-
func NewUserTrustedCABundleError(err error, message string, args ...any) *ReconcileError {
93-
if err == nil {
94-
return nil
95-
}
96-
return &ReconcileError{
97-
Reason: UserTrustedCABundleError,
98-
Message: fmt.Sprintf(message, args...),
99-
Err: err,
100-
}
101-
}
102-
10386
// IsIrrecoverableError checks if the given error is a ReconcileError
10487
// with IrrecoverableError reason. Returns false if err is nil or
10588
// not a ReconcileError.
@@ -138,24 +121,6 @@ func IsUserConfigurationNotFound(err error) bool {
138121
return apierrors.IsNotFound(rerr.Err)
139122
}
140123

141-
// IsUserTrustedCABundleError checks if the given error is a ReconcileError with UserTrustedCABundleError reason.
142-
func IsUserTrustedCABundleError(err error) bool {
143-
rerr := &ReconcileError{}
144-
if errors.As(err, &rerr) {
145-
return rerr.Reason == UserTrustedCABundleError
146-
}
147-
return false
148-
}
149-
150-
// IsUserTrustedCABundleNotFound reports whether err is a UserTrustedCABundleError caused by a missing ConfigMap.
151-
func IsUserTrustedCABundleNotFound(err error) bool {
152-
rerr := &ReconcileError{}
153-
if !errors.As(err, &rerr) || rerr.Reason != UserTrustedCABundleError {
154-
return false
155-
}
156-
return apierrors.IsNotFound(rerr.Err)
157-
}
158-
159124
// Error implements the error interface, returning a formatted string
160125
// containing both the message and the underlying error.
161126
func (e *ReconcileError) Error() string {

pkg/controller/common/errors_test.go

Lines changed: 110 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -22,70 +22,51 @@ func TestIsUserConfigurationNotFound(t *testing.T) {
2222
}{
2323
{
2424
name: "user configuration error wrapping NotFound",
25-
err: NewUserConfigurationError(notFound, "issuer %q not found", "external-secrets/missing"),
25+
err: NewUserConfigurationError(notFound, "trustedCABundle ConfigMap %q not found", "external-secrets/missing"),
2626
want: true,
2727
},
2828
{
2929
name: "wrapped user configuration NotFound",
30-
err: fmt.Errorf("reconcile deployment: %w", NewUserConfigurationError(notFound, "issuer %q not found", "external-secrets/missing")),
30+
err: fmt.Errorf("reconcile deployment: %w", NewUserConfigurationError(notFound, "trustedCABundle ConfigMap %q not found", "external-secrets/missing")),
3131
want: true,
3232
},
33+
{
34+
name: "user configuration error missing key",
35+
err: NewUserConfigurationError(
36+
fmt.Errorf("key %q not found", "ca.crt"),
37+
"trustedCABundle ConfigMap %q does not contain key %q",
38+
"external-secrets/cm", "ca.crt",
39+
),
40+
want: false,
41+
},
3342
{
3443
name: "user configuration error invalid PEM",
35-
err: NewUserConfigurationError(errors.New("invalid pem"), "invalid issuer configuration"),
44+
err: NewUserConfigurationError(errors.New("trusted CA bundle contains no valid PEM-encoded CA certificates"), "trustedCABundle ConfigMap %q key %q has invalid PEM", "external-secrets/cm", "ca.crt"),
3645
want: false,
3746
},
3847
{
39-
name: "bare NotFound",
40-
err: notFound,
48+
name: "user configuration error invalid proxy URL",
49+
err: NewUserConfigurationError(errors.New("invalid proxy URL configured"), "proxy configuration validation failed"),
4150
want: false,
4251
},
43-
{name: "nil error", err: nil, want: false},
44-
}
45-
46-
for _, tt := range tests {
47-
t.Run(tt.name, func(t *testing.T) {
48-
t.Parallel()
49-
if got := IsUserConfigurationNotFound(tt.err); got != tt.want {
50-
t.Fatalf("IsUserConfigurationNotFound() = %v, want %v", got, tt.want)
51-
}
52-
})
53-
}
54-
}
55-
56-
func TestIsUserTrustedCABundleNotFound(t *testing.T) {
57-
t.Parallel()
58-
59-
cmGR := schema.GroupResource{Resource: "configmaps"}
60-
notFound := apierrors.NewNotFound(cmGR, "missing")
61-
62-
tests := []struct {
63-
name string
64-
err error
65-
want bool
66-
}{
6752
{
68-
name: "trusted CA bundle error wrapping NotFound",
69-
err: NewUserTrustedCABundleError(notFound, "trustedCABundle ConfigMap %q not found", "external-secrets/missing"),
70-
want: true,
53+
name: "bare NotFound",
54+
err: notFound,
55+
want: false,
7156
},
7257
{
73-
name: "wrapped trusted CA bundle NotFound",
74-
err: fmt.Errorf("reconcile deployment: %w", NewUserTrustedCABundleError(notFound, "trustedCABundle ConfigMap %q not found", "external-secrets/missing")),
75-
want: true,
58+
name: "retry required reconcile error",
59+
err: NewRetryRequiredError(notFound, "fetch configmap %q", "user-ca"),
60+
want: false,
7661
},
7762
{
78-
name: "trusted CA bundle error missing key",
79-
err: NewUserTrustedCABundleError(
80-
fmt.Errorf("key %q not found", "ca.crt"),
81-
"trustedCABundle ConfigMap %q does not contain key %q",
82-
"external-secrets/cm", "ca.crt",
83-
),
63+
name: "irrecoverable reconcile error",
64+
err: NewIrrecoverableError(apierrors.NewForbidden(cmGR, "user-ca", errors.New("denied")), "forbidden"),
8465
want: false,
8566
},
8667
{
87-
name: "user configuration NotFound is not trusted CA NotFound",
88-
err: NewUserConfigurationError(notFound, "issuer %q not found", "external-secrets/missing"),
68+
name: "generic error",
69+
err: errors.New("something failed"),
8970
want: false,
9071
},
9172
{name: "nil error", err: nil, want: false},
@@ -94,8 +75,8 @@ func TestIsUserTrustedCABundleNotFound(t *testing.T) {
9475
for _, tt := range tests {
9576
t.Run(tt.name, func(t *testing.T) {
9677
t.Parallel()
97-
if got := IsUserTrustedCABundleNotFound(tt.err); got != tt.want {
98-
t.Fatalf("IsUserTrustedCABundleNotFound() = %v, want %v", got, tt.want)
78+
if got := IsUserConfigurationNotFound(tt.err); got != tt.want {
79+
t.Fatalf("IsUserConfigurationNotFound() = %v, want %v", got, tt.want)
9980
}
10081
})
10182
}
@@ -112,56 +93,44 @@ func TestIsUserConfigurationError(t *testing.T) {
11293
want bool
11394
}{
11495
{
115-
name: "user configuration error",
116-
err: NewUserConfigurationError(notFound, "issuer %q not found", "external-secrets/missing"),
96+
name: "trusted CA bundle user configuration error",
97+
err: NewUserConfigurationError(notFound, "trustedCABundle ConfigMap %q not found", "external-secrets/missing"),
11798
want: true,
11899
},
119100
{
120-
name: "trusted CA bundle error is not user configuration",
121-
err: NewUserTrustedCABundleError(notFound, "trustedCABundle ConfigMap %q not found", "external-secrets/missing"),
122-
want: false,
101+
name: "proxy user configuration error",
102+
err: NewUserConfigurationError(errors.New("invalid proxy URL"), "proxy configuration validation failed"),
103+
want: true,
123104
},
124-
{name: "nil error", err: nil, want: false},
125-
}
126-
127-
for _, tt := range tests {
128-
t.Run(tt.name, func(t *testing.T) {
129-
t.Parallel()
130-
if got := IsUserConfigurationError(tt.err); got != tt.want {
131-
t.Fatalf("IsUserConfigurationError() = %v, want %v", got, tt.want)
132-
}
133-
})
134-
}
135-
}
136-
137-
func TestIsUserTrustedCABundleError(t *testing.T) {
138-
t.Parallel()
139-
140-
notFound := apierrors.NewNotFound(schema.GroupResource{Resource: "configmaps"}, "missing")
141-
142-
tests := []struct {
143-
name string
144-
err error
145-
want bool
146-
}{
147105
{
148-
name: "trusted CA bundle error",
149-
err: NewUserTrustedCABundleError(notFound, "trustedCABundle ConfigMap %q not found", "external-secrets/missing"),
106+
name: "wrapped user configuration error",
107+
err: fmt.Errorf("apply user CA: %w", NewUserConfigurationError(errors.New("invalid pem"), "invalid PEM")),
150108
want: true,
151109
},
152110
{
153-
name: "user configuration error is not trusted CA bundle",
154-
err: NewUserConfigurationError(notFound, "issuer %q not found", "external-secrets/missing"),
111+
name: "client NotFound maps to retry required",
112+
err: FromClientError(notFound, "failed to fetch trustedCABundle ConfigMap %q", "external-secrets/missing"),
155113
want: false,
156114
},
115+
{
116+
name: "irrecoverable reconcile error",
117+
err: NewIrrecoverableError(apierrors.NewForbidden(schema.GroupResource{Resource: "configmaps"}, "user-ca", errors.New("denied")), "forbidden"),
118+
want: false,
119+
},
120+
{
121+
name: "retry required reconcile error",
122+
err: NewRetryRequiredError(errors.New("timeout"), "temporary failure"),
123+
want: false,
124+
},
125+
{name: "bare NotFound", err: notFound, want: false},
157126
{name: "nil error", err: nil, want: false},
158127
}
159128

160129
for _, tt := range tests {
161130
t.Run(tt.name, func(t *testing.T) {
162131
t.Parallel()
163-
if got := IsUserTrustedCABundleError(tt.err); got != tt.want {
164-
t.Fatalf("IsUserTrustedCABundleError() = %v, want %v", got, tt.want)
132+
if got := IsUserConfigurationError(tt.err); got != tt.want {
133+
t.Fatalf("IsUserConfigurationError() = %v, want %v", got, tt.want)
165134
}
166135
})
167136
}
@@ -182,14 +151,34 @@ func TestIsIrrecoverableError(t *testing.T) {
182151
err: NewIrrecoverableError(errors.New("bad config"), "invalid configuration"),
183152
want: true,
184153
},
154+
{
155+
name: "forbidden client error",
156+
err: FromClientError(apierrors.NewForbidden(cmGR, "user-ca", errors.New("denied")), "patch configmap %q", "user-ca"),
157+
want: true,
158+
},
159+
{
160+
name: "unauthorized client error",
161+
err: FromClientError(apierrors.NewUnauthorized("unauthorized"), "get configmap"),
162+
want: true,
163+
},
164+
{
165+
name: "invalid client error",
166+
err: FromClientError(apierrors.NewInvalid(schema.GroupKind{Kind: "ConfigMap"}, "user-ca", nil), "invalid configmap"),
167+
want: true,
168+
},
169+
{
170+
name: "NotFound client error is retry required",
171+
err: FromClientError(apierrors.NewNotFound(cmGR, "user-ca"), "get configmap %q", "user-ca"),
172+
want: false,
173+
},
185174
{
186175
name: "user configuration error",
187-
err: NewUserConfigurationError(apierrors.NewNotFound(cmGR, "missing"), "issuer %q not found", "external-secrets/missing"),
176+
err: NewUserConfigurationError(apierrors.NewNotFound(cmGR, "missing"), "trustedCABundle ConfigMap %q not found", "external-secrets/missing"),
188177
want: false,
189178
},
190179
{
191-
name: "trusted CA bundle error",
192-
err: NewUserTrustedCABundleError(apierrors.NewNotFound(cmGR, "missing"), "trustedCABundle ConfigMap %q not found", "external-secrets/missing"),
180+
name: "retry required reconcile error",
181+
err: NewRetryRequiredError(errors.New("conflict"), "update conflict"),
193182
want: false,
194183
},
195184
{name: "nil error", err: nil, want: false},
@@ -227,11 +216,31 @@ func TestFromClientError(t *testing.T) {
227216
err: apierrors.NewForbidden(cmGR, "user-ca", errors.New("denied")),
228217
wantReason: IrrecoverableError,
229218
},
219+
{
220+
name: "Unauthorized",
221+
err: apierrors.NewUnauthorized("unauthorized"),
222+
wantReason: IrrecoverableError,
223+
},
224+
{
225+
name: "Invalid",
226+
err: apierrors.NewInvalid(schema.GroupKind{Kind: "ConfigMap"}, "user-ca", nil),
227+
wantReason: IrrecoverableError,
228+
},
229+
{
230+
name: "BadRequest",
231+
err: apierrors.NewBadRequest("bad request"),
232+
wantReason: IrrecoverableError,
233+
},
230234
{
231235
name: "ServiceUnavailable",
232236
err: apierrors.NewServiceUnavailable("service unavailable"),
233237
wantReason: RetryRequiredError,
234238
},
239+
{
240+
name: "Conflict",
241+
err: apierrors.NewConflict(cmGR, "user-ca", errors.New("conflict")),
242+
wantReason: RetryRequiredError,
243+
},
235244
}
236245

237246
for _, tt := range tests {
@@ -250,6 +259,9 @@ func TestFromClientError(t *testing.T) {
250259
if got.Reason != tt.wantReason {
251260
t.Fatalf("Reason = %q, want %q", got.Reason, tt.wantReason)
252261
}
262+
if !errors.Is(got, tt.err) {
263+
t.Fatalf("expected wrapped error %v, got %v", tt.err, got.Err)
264+
}
253265
})
254266
}
255267
}
@@ -261,11 +273,22 @@ func TestReconcileErrorConstructorsNil(t *testing.T) {
261273
name string
262274
got *ReconcileError
263275
}{
264-
{name: "NewIrrecoverableError", got: NewIrrecoverableError(nil, "msg")},
265-
{name: "NewRetryRequiredError", got: NewRetryRequiredError(nil, "msg")},
266-
{name: "NewUserConfigurationError", got: NewUserConfigurationError(nil, "msg")},
267-
{name: "NewUserTrustedCABundleError", got: NewUserTrustedCABundleError(nil, "msg")},
268-
{name: "FromClientError", got: FromClientError(nil, "msg")},
276+
{
277+
name: "NewIrrecoverableError",
278+
got: NewIrrecoverableError(nil, "msg"),
279+
},
280+
{
281+
name: "NewRetryRequiredError",
282+
got: NewRetryRequiredError(nil, "msg"),
283+
},
284+
{
285+
name: "NewUserConfigurationError",
286+
got: NewUserConfigurationError(nil, "msg"),
287+
},
288+
{
289+
name: "FromClientError",
290+
got: FromClientError(nil, "msg"),
291+
},
269292
}
270293

271294
for _, tt := range tests {

pkg/controller/external_secrets/configmap_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,11 @@ func TestEnsureTrustedCABundleConfigMap(t *testing.T) {
232232
} else {
233233
esc = testESCWithProxy()
234234
}
235-
r.setProxyStatus(esc)
235+
if proxyConfig, err := r.resolveProxyConfiguration(esc); err != nil {
236+
t.Fatalf("resolveProxyConfiguration() error = %v", err)
237+
} else {
238+
r.proxyConfig = proxyConfig
239+
}
236240

237241
err := r.ensureTrustedCABundleConfigMap(esc, tt.resourceMetadata)
238242

0 commit comments

Comments
 (0)