cli-utils/pkg/apply/task/inv_set_task.go

127 lines
5.1 KiB
Go

// Copyright 2021 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package task
import (
"k8s.io/klog/v2"
"sigs.k8s.io/cli-utils/pkg/apply/event"
"sigs.k8s.io/cli-utils/pkg/apply/taskrunner"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/inventory"
"sigs.k8s.io/cli-utils/pkg/object"
)
// InvSetTask encapsulates structures necessary to set the
// inventory references at the end of the apply/prune.
type InvSetTask struct {
TaskName string
InvClient inventory.InventoryClient
InvInfo inventory.InventoryInfo
PrevInventory object.ObjMetadataSet
DryRun common.DryRunStrategy
}
func (i *InvSetTask) Name() string {
return i.TaskName
}
func (i *InvSetTask) Action() event.ResourceAction {
return event.InventoryAction
}
func (i *InvSetTask) Identifiers() object.ObjMetadataSet {
return object.ObjMetadataSet{}
}
// Start sets (creates or replaces) the inventory.
//
// The guiding principal is that anything in the cluster should be in the
// inventory, unless it was explicitly abandoned.
//
// This task must run after all the apply and prune tasks have completed.
//
// Added objects:
// - Applied resources (successful)
//
// Retained objects:
// - Applied resources (filtered/skipped)
// - Applied resources (failed)
// - Deleted resources (filtered/skipped) that were not abandoned
// - Deleted resources (failed)
// - Abandoned resources (failed)
//
// Removed objects:
// - Deleted resources (successful)
// - Abandoned resources (successful)
func (i *InvSetTask) Start(taskContext *taskrunner.TaskContext) {
go func() {
klog.V(2).Infof("inventory set task starting (name: %q)", i.Name())
invObjs := object.ObjMetadataSet{}
// If an object applied successfully, keep or add it to the inventory.
appliedObjs := taskContext.SuccessfulApplies()
klog.V(4).Infof("set inventory %d successful applies", len(appliedObjs))
invObjs = invObjs.Union(appliedObjs)
// If an object failed to apply and was previously stored in the inventory,
// then keep it in the inventory so it can be applied/pruned next time.
// This will remove new resources that failed to apply from the inventory,
// because even tho they were added by InvAddTask, the PrevInventory
// represents the inventory before the pipeline has run.
applyFailures := i.PrevInventory.Intersection(taskContext.FailedApplies())
klog.V(4).Infof("keep in inventory %d failed applies", len(applyFailures))
invObjs = invObjs.Union(applyFailures)
// If an object skipped apply and was previously stored in the inventory,
// then keep it in the inventory so it can be applied/pruned next time.
// It's likely that all the skipped applies are already in the inventory,
// because the apply filters all currently depend on cluster state,
// but we're doing the intersection anyway just to be sure.
applySkips := i.PrevInventory.Intersection(taskContext.SkippedApplies())
klog.V(4).Infof("keep in inventory %d skipped applies", len(applySkips))
invObjs = invObjs.Union(applySkips)
// If an object failed to delete and was previously stored in the inventory,
// then keep it in the inventory so it can be applied/pruned next time.
// It's likely that all the delete failures are already in the inventory,
// because the set of resources to prune comes from the inventory,
// but we're doing the intersection anyway just to be sure.
pruneFailures := i.PrevInventory.Intersection(taskContext.FailedDeletes())
klog.V(4).Infof("set inventory %d failed prunes", len(pruneFailures))
invObjs = invObjs.Union(pruneFailures)
// If an object skipped delete and was previously stored in the inventory,
// then keep it in the inventory so it can be applied/pruned next time.
// It's likely that all the skipped deletes are already in the inventory,
// because the set of resources to prune comes from the inventory,
// but we're doing the intersection anyway just to be sure.
pruneSkips := i.PrevInventory.Intersection(taskContext.SkippedDeletes())
klog.V(4).Infof("keep in inventory %d skipped prunes", len(pruneSkips))
invObjs = invObjs.Union(pruneSkips)
// If an object is abandoned, then remove it from the inventory.
abandonedObjects := taskContext.AbandonedObjects()
klog.V(4).Infof("remove from inventory %d abandoned objects", len(abandonedObjects))
invObjs = invObjs.Diff(abandonedObjects)
// If an object is invalid and was previously stored in the inventory,
// then keep it in the inventory so it can be applied/pruned next time.
invalidObjects := i.PrevInventory.Intersection(taskContext.InvalidObjects())
klog.V(4).Infof("keep in inventory %d invalid objects", len(invalidObjects))
invObjs = invObjs.Union(invalidObjects)
klog.V(4).Infof("set inventory %d total objects", len(invObjs))
err := i.InvClient.Replace(i.InvInfo, invObjs, i.DryRun)
klog.V(2).Infof("inventory set task completing (name: %q)", i.Name())
taskContext.TaskChannel() <- taskrunner.TaskResult{Err: err}
}()
}
// Cancel is not supported by the InvSetTask.
func (i *InvSetTask) Cancel(_ *taskrunner.TaskContext) {}
// StatusUpdate is not supported by the InvSetTask.
func (i *InvSetTask) StatusUpdate(_ *taskrunner.TaskContext, _ object.ObjMetadata) {}