Skip to content

Commit bc336d5

Browse files
Merge pull request #660 from erikgb/split-target-apply-cleanup
refactor: split target apply and cleanup
2 parents 834957c + a4f4d90 commit bc336d5

File tree

3 files changed

+177
-553
lines changed

3 files changed

+177
-553
lines changed

pkg/bundle/bundle.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func (b *bundle) reconcileBundle(ctx context.Context, req ctrl.Request) (result
169169
return ctrl.Result{}, statusPatch, nil
170170
}
171171

172-
targetResources := map[target.Resource]bool{}
172+
targetResources := map[target.Resource]struct{}{}
173173

174174
namespaceSelector, err := b.bundleTargetNamespaceSelector(&bundle)
175175
if err != nil {
@@ -202,10 +202,10 @@ func (b *bundle) reconcileBundle(ctx context.Context, req ctrl.Request) (result
202202
}
203203

204204
if bundle.Spec.Target.Secret != nil {
205-
targetResources[target.Resource{Kind: target.KindSecret, NamespacedName: namespacedName}] = true
205+
targetResources[target.Resource{Kind: target.KindSecret, NamespacedName: namespacedName}] = struct{}{}
206206
}
207207
if bundle.Spec.Target.ConfigMap != nil {
208-
targetResources[target.Resource{Kind: target.KindConfigMap, NamespacedName: namespacedName}] = true
208+
targetResources[target.Resource{Kind: target.KindConfigMap, NamespacedName: namespacedName}] = struct{}{}
209209
}
210210
}
211211
}
@@ -260,15 +260,18 @@ func (b *bundle) reconcileBundle(ctx context.Context, req ctrl.Request) (result
260260
continue
261261
}
262262

263-
targetResources[key] = false
263+
if _, err := b.targetReconciler.CleanupTarget(ctx, key, &bundle); err != nil {
264+
// Failing target cleanup is not considered critical, log error and continue.
265+
targetLog.Error(err, "failed to cleanup bundle target")
266+
}
264267
}
265268
}
266269

267270
var needsUpdate bool
268271

269-
for t, shouldExist := range targetResources {
272+
for t := range targetResources {
270273
targetLog := log.WithValues("target", t)
271-
synced, err := b.targetReconciler.Sync(logf.IntoContext(ctx, targetLog), t, &bundle, resolvedBundle, shouldExist)
274+
synced, err := b.targetReconciler.ApplyTarget(logf.IntoContext(ctx, targetLog), t, &bundle, resolvedBundle)
272275
if err != nil {
273276
targetLog.Error(err, "failed sync bundle to target namespace")
274277
b.recorder.Eventf(&bundle, corev1.EventTypeWarning, fmt.Sprintf("Sync%sTargetFailed", t.Kind), "Failed to sync target %s in Namespace %q: %s", t.Kind, t.Namespace, err)

pkg/bundle/internal/target/target.go

Lines changed: 48 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -56,32 +56,68 @@ type Reconciler struct {
5656
PatchResourceOverwrite func(ctx context.Context, obj interface{}) error
5757
}
5858

59-
// Sync syncs the given data to the target resource.
59+
// CleanupTarget ensures the obsolete bundle target is cleanup up.
60+
// It will delete the target resource if it contains no data after removing the bundle data.
61+
// Returns true if the resource has been deleted.
62+
func (r *Reconciler) CleanupTarget(
63+
ctx context.Context,
64+
target Resource,
65+
bundle *trustapi.Bundle,
66+
) (bool, error) {
67+
switch target.Kind {
68+
case KindConfigMap:
69+
// Apply an empty patch to remove the key(s).
70+
patch := prepareTargetPatch(coreapplyconfig.ConfigMap(target.Name, target.Namespace), *bundle)
71+
configMap, err := r.patchConfigMap(ctx, patch)
72+
if err != nil {
73+
return false, fmt.Errorf("failed to patch %s %s: %w", target.Kind, target.NamespacedName, err)
74+
}
75+
// If the ConfigMap is empty, delete it.
76+
if configMap != nil && len(configMap.Data) == 0 && len(configMap.BinaryData) == 0 {
77+
return false, client.IgnoreNotFound(r.Client.Delete(ctx, configMap))
78+
}
79+
case KindSecret:
80+
// Apply an empty patch to remove the key(s).
81+
patch := prepareTargetPatch(coreapplyconfig.Secret(target.Name, target.Namespace), *bundle)
82+
secret, err := r.patchSecret(ctx, patch)
83+
if err != nil {
84+
return false, fmt.Errorf("failed to patch %s %s: %w", target.Kind, target.NamespacedName, err)
85+
}
86+
// If the Secret is empty, delete it.
87+
if secret != nil && len(secret.Data) == 0 {
88+
return true, client.IgnoreNotFound(r.Client.Delete(ctx, secret))
89+
}
90+
default:
91+
return false, fmt.Errorf("don't know how to clean target of kind: %s", target.Kind)
92+
}
93+
94+
return false, nil
95+
}
96+
97+
// ApplyTarget applies the bundle data to the target resource.
6098
// Ensures the resource is owned by the given Bundle, and the data is up to date.
61-
// Returns true if the resource has been created, updated or deleted.
62-
func (r *Reconciler) Sync(
99+
// Returns true if the resource has been created or updated.
100+
func (r *Reconciler) ApplyTarget(
63101
ctx context.Context,
64102
target Resource,
65103
bundle *trustapi.Bundle,
66104
resolvedBundle source.BundleData,
67-
shouldExist bool,
68105
) (bool, error) {
69106
switch target.Kind {
70107
case KindConfigMap:
71-
return r.syncConfigMap(ctx, target, bundle, resolvedBundle, shouldExist)
108+
return r.applyConfigMap(ctx, target, bundle, resolvedBundle)
72109
case KindSecret:
73-
return r.syncSecret(ctx, target, bundle, resolvedBundle, shouldExist)
110+
return r.applySecret(ctx, target, bundle, resolvedBundle)
74111
default:
75-
return false, fmt.Errorf("don't know how to sync target of kind: %s", target.Kind)
112+
return false, fmt.Errorf("don't know how to apply target of kind: %s", target.Kind)
76113
}
77114
}
78115

79-
func (r *Reconciler) syncConfigMap(
116+
func (r *Reconciler) applyConfigMap(
80117
ctx context.Context,
81118
target Resource,
82119
bundle *trustapi.Bundle,
83120
resolvedBundle source.BundleData,
84-
shouldExist bool,
85121
) (bool, error) {
86122
targetObj := &metav1.PartialObjectMetadata{
87123
TypeMeta: metav1.TypeMeta{
@@ -94,26 +130,6 @@ func (r *Reconciler) syncConfigMap(
94130
return false, fmt.Errorf("failed to get %s %s: %w", target.Kind, target.NamespacedName, err)
95131
}
96132

97-
// If the resource is not found, and should not exist, we are done.
98-
if apierrors.IsNotFound(err) && !shouldExist {
99-
return false, nil
100-
}
101-
102-
// If the resource exists, but should not, delete it.
103-
if !apierrors.IsNotFound(err) && !shouldExist {
104-
// Apply empty patch to remove the key(s).
105-
patch := prepareTargetPatch(coreapplyconfig.ConfigMap(target.Name, target.Namespace), *bundle)
106-
configMap, err := r.patchConfigMap(ctx, patch)
107-
if err != nil {
108-
return false, fmt.Errorf("failed to patch %s %s: %w", target.Kind, target.NamespacedName, err)
109-
}
110-
// If the ConfigMap is empty, delete it.
111-
if configMap != nil && len(configMap.Data) == 0 && len(configMap.BinaryData) == 0 {
112-
return true, r.Client.Delete(ctx, configMap)
113-
}
114-
return true, nil
115-
}
116-
117133
bundleTarget := bundle.Spec.Target
118134
if bundleTarget.ConfigMap == nil {
119135
return false, errors.New("target not defined")
@@ -150,17 +166,16 @@ func (r *Reconciler) syncConfigMap(
150166
return false, fmt.Errorf("failed to patch %s %s: %w", target.Kind, target.NamespacedName, err)
151167
}
152168

153-
logf.FromContext(ctx).V(2).Info("synced bundle to namespace")
169+
logf.FromContext(ctx).V(2).Info("applied bundle to namespace")
154170

155171
return true, nil
156172
}
157173

158-
func (r *Reconciler) syncSecret(
174+
func (r *Reconciler) applySecret(
159175
ctx context.Context,
160176
target Resource,
161177
bundle *trustapi.Bundle,
162178
resolvedBundle source.BundleData,
163-
shouldExist bool,
164179
) (bool, error) {
165180
targetObj := &metav1.PartialObjectMetadata{
166181
TypeMeta: metav1.TypeMeta{
@@ -173,26 +188,6 @@ func (r *Reconciler) syncSecret(
173188
return false, fmt.Errorf("failed to get %s %s: %w", target.Kind, target.NamespacedName, err)
174189
}
175190

176-
// If the resource is not found, and should not exist, we are done.
177-
if apierrors.IsNotFound(err) && !shouldExist {
178-
return false, nil
179-
}
180-
181-
// If the resource exists, but should not, delete it.
182-
if !apierrors.IsNotFound(err) && !shouldExist {
183-
// Apply empty patch to remove the key(s).
184-
patch := prepareTargetPatch(coreapplyconfig.Secret(target.Name, target.Namespace), *bundle)
185-
secret, err := r.patchSecret(ctx, patch)
186-
if err != nil {
187-
return false, fmt.Errorf("failed to patch %s %s: %w", target.Kind, target.NamespacedName, err)
188-
}
189-
// If the Secret is empty, delete it.
190-
if secret != nil && len(secret.Data) == 0 {
191-
return true, r.Client.Delete(ctx, secret)
192-
}
193-
return true, nil
194-
}
195-
196191
bundleTarget := bundle.Spec.Target
197192
if bundleTarget.Secret == nil {
198193
return false, errors.New("target not defined")
@@ -231,7 +226,7 @@ func (r *Reconciler) syncSecret(
231226
return false, fmt.Errorf("failed to patch %s %s: %w", target.Kind, target.NamespacedName, err)
232227
}
233228

234-
logf.FromContext(ctx).V(2).Info("synced bundle to namespace")
229+
logf.FromContext(ctx).V(2).Info("applied bundle to namespace")
235230

236231
return true, nil
237232
}

0 commit comments

Comments
 (0)