Skip to content

Commit 6db68fd

Browse files
committed
Fix for final inventory update
1 parent b62349a commit 6db68fd

File tree

6 files changed

+251
-132
lines changed

6 files changed

+251
-132
lines changed

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -703,8 +703,6 @@ sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvO
703703
sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo=
704704
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
705705
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
706-
sigs.k8s.io/kustomize/kyaml v0.10.5 h1:PbJcsZsEM7O3hHtUWTR+4WkHVbQRW9crSy75or1gRbI=
707-
sigs.k8s.io/kustomize/kyaml v0.10.5/go.mod h1:P6Oy/ah/GZMKzJMIJA2a3/bc8YrBkuL5kJji13PSIzY=
708706
sigs.k8s.io/kustomize/kyaml v0.10.6 h1:xUJxc/k8JoWqHUahaB8DTqY0KwEPxTbTGStvW8TOcDc=
709707
sigs.k8s.io/kustomize/kyaml v0.10.6/go.mod h1:K9yg1k/HB/6xNOf5VH3LhTo1DK9/5ykSZO5uIv+Y/1k=
710708
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=

pkg/apply/applier.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"k8s.io/apimachinery/pkg/api/meta"
1414
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1515
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
16+
"k8s.io/klog"
1617
"sigs.k8s.io/cli-utils/pkg/apply/event"
1718
"sigs.k8s.io/cli-utils/pkg/apply/info"
1819
"sigs.k8s.io/cli-utils/pkg/apply/poller"
@@ -89,6 +90,7 @@ func (a *Applier) Initialize() error {
8990
// resources for the subsequent apply. Returns the sorted resources to
9091
// apply as well as the objects for the prune, or an error if one occurred.
9192
func (a *Applier) prepareObjects(localInv inventory.InventoryInfo, localObjs []*unstructured.Unstructured) (*ResourceObjects, error) {
93+
klog.V(4).Infof("applier preparing %d objects", len(localObjs))
9294
if localInv == nil {
9395
return nil, fmt.Errorf("the local inventory can't be nil")
9496
}
@@ -97,20 +99,22 @@ func (a *Applier) prepareObjects(localInv inventory.InventoryInfo, localObjs []*
9799
}
98100
// Ensures the namespace exists before applying the inventory object into it.
99101
if invNamespace := inventoryNamespaceInSet(localInv, localObjs); invNamespace != nil {
102+
klog.V(4).Infof("applier prepareObjects applying namespace %s", invNamespace.GetName())
100103
if err := a.invClient.ApplyInventoryNamespace(invNamespace); err != nil {
101104
return nil, err
102105
}
103106
}
104107

108+
klog.V(4).Infof("applier merging %d objects into inventory", len(localObjs))
105109
currentObjs := object.UnstructuredsToObjMetas(localObjs)
106110
// returns the objects (pruneIds) to prune after apply. The prune
107111
// algorithm requires stopping if the merge is not successful. Otherwise,
108112
// the stored objects in inventory could become inconsistent.
109113
pruneIds, err := a.invClient.Merge(localInv, currentObjs)
110-
111114
if err != nil {
112115
return nil, err
113116
}
117+
klog.V(4).Infof("after inventory merge; %d objects to prune", len(pruneIds))
114118
// Sort order for applied resources.
115119
sort.Sort(ordering.SortableUnstructureds(localObjs))
116120

@@ -173,6 +177,7 @@ func (r *ResourceObjects) AllIds() []object.ObjMetadata {
173177
// cancellation or timeout will only affect how long we Wait for the
174178
// resources to become current.
175179
func (a *Applier) Run(ctx context.Context, invInfo inventory.InventoryInfo, objects []*unstructured.Unstructured, options Options) <-chan event.Event {
180+
klog.V(4).Infof("apply run for %d objects", len(objects))
176181
eventChannel := make(chan event.Event)
177182
setDefaults(&options)
178183
a.invClient.SetDryRunStrategy(options.DryRunStrategy) // client shared with prune, so sets dry-run for prune too.
@@ -195,6 +200,7 @@ func (a *Applier) Run(ctx context.Context, invInfo inventory.InventoryInfo, obje
195200
}
196201

197202
// Fetch the queue (channel) of tasks that should be executed.
203+
klog.V(4).Infoln("applier building task queue...")
198204
taskQueue := (&solver.TaskQueueSolver{
199205
PruneOptions: a.PruneOptions,
200206
Factory: a.provider.Factory(),
@@ -229,7 +235,9 @@ func (a *Applier) Run(ctx context.Context, invInfo inventory.InventoryInfo, obje
229235
}
230236

231237
// Create a new TaskStatusRunner to execute the taskQueue.
238+
klog.V(4).Infoln("applier building TaskStatusRunner...")
232239
runner := taskrunner.NewTaskStatusRunner(resourceObjects.AllIds(), a.StatusPoller)
240+
klog.V(4).Infoln("applier running TaskStatusRunner...")
233241
err = runner.Run(ctx, taskQueue, eventChannel, taskrunner.Options{
234242
PollInterval: options.PollInterval,
235243
UseCache: true,

pkg/apply/prune/prune.go

Lines changed: 122 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -83,114 +83,174 @@ type Options struct {
8383
}
8484

8585
// 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
91105
if localInv == nil {
92106
return fmt.Errorf("the local inventory object can't be nil")
93107
}
94-
invNamespace := localInv.Namespace()
95-
klog.V(4).Infof("prune local inventory object: %s/%s", invNamespace, localInv.Name())
96108
// Get the list of Object Meta from the local objects.
97109
localIds := object.UnstructuredsToObjMetas(localObjs)
98110
// Create the set of namespaces for currently (locally) applied objects, including
99111
// the namespace the inventory object lives in (if it's not cluster-scoped). When
100112
// 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)
106115
if err != nil {
107116
return err
108117
}
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))
111123
// Sort the resources in reverse order using the same rules as is
112124
// 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)
124131
if err != nil {
125132
// Object not found in cluster, so no need to delete it; skip to next object.
126133
if apierrors.IsNotFound(err) {
134+
klog.V(5).Infof("%s/%s not found in cluster--skipping",
135+
pruneObj.Namespace, pruneObj.Name)
127136
continue
128137
}
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)
139145
continue
140146
}
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())
146149
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)
148151
continue
149152
}
150153
// Handle lifecycle directive preventing deletion.
151154
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)
154158
continue
155159
}
156160
// If regular pruning (not destroying), skip deleting namespace containing
157161
// currently applied objects.
158162
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)
165169
continue
166170
}
167171
}
168172
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)
171175
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)
175182
continue
176183
}
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)
177215
}
178-
taskContext.EventChannel() <- createPruneEvent(clusterObj, obj, event.Pruned)
179216
}
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)
181221
}
182222

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 {
187243
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))
190246
if namespace != "" {
191247
namespaces.Insert(namespace)
192248
}
193249
}
250+
invNamespace := strings.TrimSpace(strings.ToLower(localInv.Namespace()))
251+
if invNamespace != "" {
252+
namespaces.Insert(invNamespace)
253+
}
194254
return namespaces
195255
}
196256

0 commit comments

Comments
 (0)