@@ -83,114 +83,174 @@ type Options struct {
83
83
}
84
84
85
85
// Prune deletes the set of resources which were previously applied
86
- // (retrieved from previous inventory objects) but omitted in
87
- // the current apply. Prune also delete all previous inventory
88
- // objects. Returns an error if there was a problem.
89
- func (po * PruneOptions ) Prune (localInv inventory.InventoryInfo , localObjs []* unstructured.Unstructured , currentUIDs sets.String ,
90
- taskContext * taskrunner.TaskContext , o Options ) error {
86
+ // but omitted in the current apply. Calculates the set of objects
87
+ // to prune by removing the currently applied objects from the union
88
+ // set of the previously applied objects and currently applied objects
89
+ // stored in the cluster inventory. As a final step, stores the current
90
+ // inventory which is all the successfully applied objects and the
91
+ // prune failures. Does not stop when encountering prune failures.
92
+ // Returns an error for unrecoverable errors.
93
+ //
94
+ // Parameters:
95
+ // localInv - locally read inventory object
96
+ // localObjs - locally read, currently applied (attempted) objects
97
+ // currentUIDs - UIDs for successfully applied objects
98
+ // taskContext - task for apply/prune
99
+ func (po * PruneOptions ) Prune (localInv inventory.InventoryInfo ,
100
+ localObjs []* unstructured.Unstructured ,
101
+ currentUIDs sets.String ,
102
+ taskContext * taskrunner.TaskContext ,
103
+ o Options ) error {
104
+ // Validate parameters
91
105
if localInv == nil {
92
106
return fmt .Errorf ("the local inventory object can't be nil" )
93
107
}
94
- invNamespace := localInv .Namespace ()
95
- klog .V (4 ).Infof ("prune local inventory object: %s/%s" , invNamespace , localInv .Name ())
96
108
// Get the list of Object Meta from the local objects.
97
109
localIds := object .UnstructuredsToObjMetas (localObjs )
98
110
// Create the set of namespaces for currently (locally) applied objects, including
99
111
// the namespace the inventory object lives in (if it's not cluster-scoped). When
100
112
// pruning, check this set of namespaces to ensure these namespaces are not deleted.
101
- localNamespaces := mergeObjNamespaces (localObjs )
102
- if invNamespace != "" {
103
- localNamespaces .Insert (invNamespace )
104
- }
105
- clusterObjs , err := po .InvClient .GetClusterObjs (localInv )
113
+ localNamespaces := localNamespaces (localInv , localIds )
114
+ clusterInv , err := po .InvClient .GetClusterObjs (localInv )
106
115
if err != nil {
107
116
return err
108
117
}
109
- klog .V (4 ).Infof ("prune %d currently applied objects" , len (currentUIDs ))
110
- klog .V (4 ).Infof ("prune %d previously applied objects" , len (clusterObjs ))
118
+ klog .V (4 ).Infof ("prune: %d objects attempted to apply" , len (localIds ))
119
+ klog .V (4 ).Infof ("prune: %d objects successfully applied" , len (currentUIDs ))
120
+ klog .V (4 ).Infof ("prune: %d union objects stored in cluster inventory" , len (clusterInv ))
121
+ pruneObjs := object .SetDiff (clusterInv , localIds )
122
+ klog .V (4 ).Infof ("prune: %d objects to prune (clusterInv - localIds)" , len (pruneObjs ))
111
123
// Sort the resources in reverse order using the same rules as is
112
124
// used for apply.
113
- sort .Sort (sort .Reverse (ordering .SortableMetas (clusterObjs )))
114
- for _ , clusterObj := range clusterObjs {
115
- mapping , err := po .mapper .RESTMapping (clusterObj .GroupKind )
116
- if err != nil {
117
- localIds = append (localIds , clusterObj )
118
- taskContext .EventChannel () <- createPruneFailedEvent (clusterObj , err )
119
- taskContext .CaptureResourceFailure (clusterObj )
120
- continue
121
- }
122
- namespacedClient := po .client .Resource (mapping .Resource ).Namespace (clusterObj .Namespace )
123
- obj , err := namespacedClient .Get (context .TODO (), clusterObj .Name , metav1.GetOptions {})
125
+ sort .Sort (sort .Reverse (ordering .SortableMetas (pruneObjs )))
126
+ // Store prune failures to ensure they remain in the inventory.
127
+ pruneFailures := []object.ObjMetadata {}
128
+ for _ , pruneObj := range pruneObjs {
129
+ klog .V (5 ).Infof ("attempting prune: %s" , pruneObj )
130
+ obj , err := po .getObject (pruneObj )
124
131
if err != nil {
125
132
// Object not found in cluster, so no need to delete it; skip to next object.
126
133
if apierrors .IsNotFound (err ) {
134
+ klog .V (5 ).Infof ("%s/%s not found in cluster--skipping" ,
135
+ pruneObj .Namespace , pruneObj .Name )
127
136
continue
128
137
}
129
- localIds = append (localIds , clusterObj )
130
- taskContext .EventChannel () <- createPruneFailedEvent (clusterObj , err )
131
- taskContext .CaptureResourceFailure (clusterObj )
132
- continue
133
- }
134
- metadata , err := meta .Accessor (obj )
135
- if err != nil {
136
- localIds = append (localIds , clusterObj )
137
- taskContext .EventChannel () <- createPruneFailedEvent (clusterObj , err )
138
- taskContext .CaptureResourceFailure (clusterObj )
138
+ if klog .V (5 ) {
139
+ klog .Errorf ("prune obj (%s/%s) UID retrival error: %s" ,
140
+ pruneObj .Namespace , pruneObj .Name , err )
141
+ }
142
+ pruneFailures = append (pruneFailures , pruneObj )
143
+ taskContext .EventChannel () <- createPruneFailedEvent (pruneObj , err )
144
+ taskContext .CaptureResourceFailure (pruneObj )
139
145
continue
140
146
}
141
- // If this cluster object is not also a currently applied
142
- // object, then it has been omitted--prune it. If the cluster
143
- // object is part of the local apply set, skip it.
144
- uid := string (metadata .GetUID ())
145
- klog .V (7 ).Infof ("prune previously applied object UID: %s" , uid )
147
+ // Do not prune objects that are in set of currently applied objects.
148
+ uid := string (obj .GetUID ())
146
149
if currentUIDs .Has (uid ) {
147
- klog .V (7 ).Infof ("prune object in current apply; do not prune: %s" , uid )
150
+ klog .V (5 ).Infof ("prune object in current apply; do not prune: %s" , uid )
148
151
continue
149
152
}
150
153
// Handle lifecycle directive preventing deletion.
151
154
if ! canPrune (localInv , obj , o .InventoryPolicy , uid ) {
152
- taskContext .EventChannel () <- createPruneEvent (clusterObj , obj , event .PruneSkipped )
153
- localIds = append (localIds , clusterObj )
155
+ klog .V (4 ).Infof ("skip prune for lifecycle directive %s/%s" , pruneObj .Namespace , pruneObj .Name )
156
+ taskContext .EventChannel () <- createPruneEvent (pruneObj , obj , event .PruneSkipped )
157
+ pruneFailures = append (pruneFailures , pruneObj )
154
158
continue
155
159
}
156
160
// If regular pruning (not destroying), skip deleting namespace containing
157
161
// currently applied objects.
158
162
if ! po .Destroy {
159
- if clusterObj .GroupKind == object .CoreV1Namespace .GroupKind () &&
160
- localNamespaces .Has (clusterObj .Name ) {
161
- klog .V (4 ).Infof ("skip pruning namespace: %s" , clusterObj .Name )
162
- taskContext .EventChannel () <- createPruneEvent (clusterObj , obj , event .PruneSkipped )
163
- localIds = append (localIds , clusterObj )
164
- taskContext .CaptureResourceFailure (clusterObj )
163
+ if pruneObj .GroupKind == object .CoreV1Namespace .GroupKind () &&
164
+ localNamespaces .Has (pruneObj .Name ) {
165
+ klog .V (4 ).Infof ("skip pruning namespace: %s" , pruneObj .Name )
166
+ taskContext .EventChannel () <- createPruneEvent (pruneObj , obj , event .PruneSkipped )
167
+ pruneFailures = append (pruneFailures , pruneObj )
168
+ taskContext .CaptureResourceFailure (pruneObj )
165
169
continue
166
170
}
167
171
}
168
172
if ! o .DryRunStrategy .ClientOrServerDryRun () {
169
- klog .V (4 ).Infof ("prune object delete: %s/%s" , clusterObj .Namespace , clusterObj .Name )
170
- err = namespacedClient . Delete ( context . TODO (), clusterObj . Name , metav1. DeleteOptions {} )
173
+ klog .V (4 ).Infof ("prune object delete: %s/%s" , pruneObj .Namespace , pruneObj .Name )
174
+ namespacedClient , err := po . namespacedClient ( pruneObj )
171
175
if err != nil {
172
- taskContext .EventChannel () <- createPruneFailedEvent (clusterObj , err )
173
- localIds = append (localIds , clusterObj )
174
- taskContext .CaptureResourceFailure (clusterObj )
176
+ if klog .V (4 ) {
177
+ klog .Errorf ("prune failed for %s/%s (%s)" , pruneObj .Namespace , pruneObj .Name , err )
178
+ }
179
+ taskContext .EventChannel () <- createPruneFailedEvent (pruneObj , err )
180
+ pruneFailures = append (pruneFailures , pruneObj )
181
+ taskContext .CaptureResourceFailure (pruneObj )
175
182
continue
176
183
}
184
+ err = namespacedClient .Delete (context .TODO (), pruneObj .Name , metav1.DeleteOptions {})
185
+ if err != nil {
186
+ if klog .V (4 ) {
187
+ klog .Errorf ("prune failed for %s/%s (%s)" , pruneObj .Namespace , pruneObj .Name , err )
188
+ }
189
+ taskContext .EventChannel () <- createPruneFailedEvent (pruneObj , err )
190
+ pruneFailures = append (pruneFailures , pruneObj )
191
+ taskContext .CaptureResourceFailure (pruneObj )
192
+ continue
193
+ }
194
+ }
195
+ taskContext .EventChannel () <- createPruneEvent (pruneObj , obj , event .Pruned )
196
+ }
197
+ // Calculate final inventory items, ensuring only successfully applied
198
+ // objects are in the inventory along with prune failures.
199
+ finalInventory := []object.ObjMetadata {}
200
+ for _ , localObj := range localIds {
201
+ obj , err := po .getObject (localObj )
202
+ if err != nil {
203
+ if klog .V (4 ) {
204
+ klog .Errorf ("error retrieving object for inventory determination: %s" , err )
205
+ }
206
+ continue
207
+ }
208
+ uid := string (obj .GetUID ())
209
+ if currentUIDs .Has (uid ) {
210
+ klog .V (5 ).Infof ("adding final inventory object %s/%s" , localObj .Namespace , localObj .Name )
211
+ finalInventory = append (finalInventory , localObj )
212
+ } else {
213
+ klog .V (5 ).Infof ("uid not found (%s); not adding final inventory obj %s/%s" ,
214
+ uid , localObj .Namespace , localObj .Name )
177
215
}
178
- taskContext .EventChannel () <- createPruneEvent (clusterObj , obj , event .Pruned )
179
216
}
180
- return po .InvClient .Replace (localInv , localIds )
217
+ klog .V (4 ).Infof ("final inventory %d successfully applied objects" , len (finalInventory ))
218
+ finalInventory = append (finalInventory , pruneFailures ... )
219
+ klog .V (4 ).Infof ("final inventory %d objects after appending prune failures" , len (finalInventory ))
220
+ return po .InvClient .Replace (localInv , finalInventory )
181
221
}
182
222
183
- // mergeObjNamespaces returns a set of strings of all the namespaces
184
- // for non cluster-scoped objects. These namespaces are forced to
185
- // lower-case.
186
- func mergeObjNamespaces (objs []* unstructured.Unstructured ) sets.String {
223
+ func (po * PruneOptions ) namespacedClient (obj object.ObjMetadata ) (dynamic.ResourceInterface , error ) {
224
+ mapping , err := po .mapper .RESTMapping (obj .GroupKind )
225
+ if err != nil {
226
+ return nil , err
227
+ }
228
+ return po .client .Resource (mapping .Resource ).Namespace (obj .Namespace ), nil
229
+ }
230
+
231
+ func (po * PruneOptions ) getObject (obj object.ObjMetadata ) (* unstructured.Unstructured , error ) {
232
+ namespacedClient , err := po .namespacedClient (obj )
233
+ if err != nil {
234
+ return nil , err
235
+ }
236
+ return namespacedClient .Get (context .TODO (), obj .Name , metav1.GetOptions {})
237
+ }
238
+
239
+ // localNamespaces returns a set of strings of all the namespaces
240
+ // for the passed non cluster-scoped localObjs, plus the namespace
241
+ // of the passed inventory object.
242
+ func localNamespaces (localInv inventory.InventoryInfo , localObjs []object.ObjMetadata ) sets.String {
187
243
namespaces := sets .NewString ()
188
- for _ , obj := range objs {
189
- namespace := strings .TrimSpace (strings .ToLower (obj .GetNamespace () ))
244
+ for _ , obj := range localObjs {
245
+ namespace := strings .TrimSpace (strings .ToLower (obj .Namespace ))
190
246
if namespace != "" {
191
247
namespaces .Insert (namespace )
192
248
}
193
249
}
250
+ invNamespace := strings .TrimSpace (strings .ToLower (localInv .Namespace ()))
251
+ if invNamespace != "" {
252
+ namespaces .Insert (invNamespace )
253
+ }
194
254
return namespaces
195
255
}
196
256
0 commit comments