Skip to content

Commit

Permalink
Merge pull request #358 from seans3/inv-task-refactor
Browse files Browse the repository at this point in the history
Move inventory operations into tasks
  • Loading branch information
k8s-ci-robot authored May 27, 2021
2 parents edb6879 + 42e330d commit d696804
Show file tree
Hide file tree
Showing 20 changed files with 533 additions and 188 deletions.
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -869,8 +869,6 @@ sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvO
sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo=
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
sigs.k8s.io/kustomize/kyaml v0.10.14 h1:8zftx3bT0r2355kE/cZfwCMq9SlTWMBvadwwtl+jcbU=
sigs.k8s.io/kustomize/kyaml v0.10.14/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg=
sigs.k8s.io/kustomize/kyaml v0.10.16 h1:4rn0PTEK4STOA5kbpz72oGskjpKYlmwru4YRgVQFv+c=
sigs.k8s.io/kustomize/kyaml v0.10.16/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
Expand Down
53 changes: 7 additions & 46 deletions pkg/apply/applier.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"time"

"github.com/go-errors/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/klog"
Expand Down Expand Up @@ -84,11 +83,7 @@ func (a *Applier) Initialize() error {
return nil
}

// prepareObjects merges the currently applied objects into the
// set of stored objects in the cluster inventory. In the process, it
// calculates the set of objects to be pruned (pruneIds), and orders the
// resources for the subsequent apply. Returns the sorted resources to
// apply as well as the objects for the prune, or an error if one occurred.
// prepareObjects returns ResourceObjects or an error if one occurred.
func (a *Applier) prepareObjects(localInv inventory.InventoryInfo, localObjs []*unstructured.Unstructured) (*ResourceObjects, error) {
klog.V(4).Infof("applier preparing %d objects", len(localObjs))
if localInv == nil {
Expand Down Expand Up @@ -120,30 +115,15 @@ func (a *Applier) prepareObjects(localInv inventory.InventoryInfo, localObjs []*
}
}

// Ensures the namespace exists before applying the inventory object into it.
if invNamespace := inventoryNamespaceInSet(localInv, localObjs); invNamespace != nil {
klog.V(4).Infof("applier prepareObjects applying namespace %s", invNamespace.GetName())
if err := a.invClient.ApplyInventoryNamespace(invNamespace); err != nil {
return nil, err
}
}
// Retrieve previous inventory objects. Must happen before inventory client merge.
// Retrieve previous inventory objects to calculate prune ids.
prevInv, err := a.invClient.GetClusterObjs(localInv)
if err != nil {
return nil, err
}
klog.V(4).Infof("%d previous inventory objects in cluster", len(prevInv))

klog.V(4).Infof("applier merging %d objects into inventory", len(localObjs))
currentObjs := object.UnstructuredsToObjMetas(localObjs)
// returns the objects (pruneIds) to prune after apply. The prune
// algorithm requires stopping if the merge is not successful. Otherwise,
// the stored objects in inventory could become inconsistent.
pruneIds, err := a.invClient.Merge(localInv, currentObjs)
if err != nil {
return nil, err
}
klog.V(4).Infof("after inventory merge; %d objects to prune", len(pruneIds))
locals := object.UnstructuredsToObjMetas(localObjs)
pruneIds := object.SetDiff(prevInv, locals)
klog.V(4).Infof("applier calculated %d prune objects", len(pruneIds))

// Sort order for applied resources.
sort.Sort(ordering.SortableUnstructureds(localObjs))

Expand Down Expand Up @@ -244,6 +224,7 @@ func (a *Applier) Run(ctx context.Context, invInfo inventory.InventoryInfo, obje
Factory: a.provider.Factory(),
InfoHelper: a.infoHelper,
Mapper: mapper,
InvClient: a.invClient,
}).BuildTaskQueue(resourceObjects, solver.Options{
ServerSideOptions: options.ServerSideOptions,
ReconcileTimeout: options.ReconcileTimeout,
Expand Down Expand Up @@ -337,23 +318,3 @@ func handleError(eventChannel chan event.Event, err error) {
},
}
}

// inventoryNamespaceInSet returns the the namespace the passed inventory
// object will be applied to, or nil if this namespace object does not exist
// in the passed slice "infos" or the inventory object is cluster-scoped.
func inventoryNamespaceInSet(inv inventory.InventoryInfo, objs []*unstructured.Unstructured) *unstructured.Unstructured {
if inv == nil {
return nil
}
invNamespace := inv.Namespace()

for _, obj := range objs {
acc, _ := meta.Accessor(obj)
gvk := obj.GetObjectKind().GroupVersionKind()
if gvk == object.CoreV1Namespace && acc.GetName() == invNamespace {
inventory.AddInventoryIDAnnotation(obj, inv)
return obj
}
}
return nil
}
68 changes: 0 additions & 68 deletions pkg/apply/applier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,17 +689,6 @@ var obj2 = &unstructured.Unstructured{
},
}

var obj3 = &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "obj3",
"namespace": "different-namespace",
},
},
}

var clusterScopedObj = &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "rbac.authorization.k8s.io/v1",
Expand All @@ -710,63 +699,6 @@ var clusterScopedObj = &unstructured.Unstructured{
},
}

func createNamespace(ns string) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": map[string]interface{}{
"name": ns,
},
},
}
}

func TestInventoryNamespaceInSet(t *testing.T) {
inventoryNamespace := createNamespace(namespace)

tests := map[string]struct {
inv inventory.InventoryInfo
objects []*unstructured.Unstructured
namespace *unstructured.Unstructured
}{
"Nil inventory object, no resources returns nil namespace": {
inv: nil,
objects: []*unstructured.Unstructured{},
namespace: nil,
},
"Inventory object, but no resources returns nil namespace": {
inv: localInv,
objects: []*unstructured.Unstructured{},
namespace: nil,
},
"Inventory object, resources with no namespace returns nil namespace": {
inv: localInv,
objects: []*unstructured.Unstructured{obj1, obj2},
namespace: nil,
},
"Inventory object, different namespace returns nil namespace": {
inv: localInv,
objects: []*unstructured.Unstructured{createNamespace("foo")},
namespace: nil,
},
"Inventory object, inventory namespace returns inventory namespace": {
inv: localInv,
objects: []*unstructured.Unstructured{obj1, inventoryNamespace, obj3},
namespace: inventoryNamespace,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
actualNamespace := inventoryNamespaceInSet(tc.inv, tc.objects)
if tc.namespace != actualNamespace {
t.Fatalf("expected namespace (%v), got (%v)", tc.namespace, actualNamespace)
}
})
}
}

func TestReadAndPrepareObjects(t *testing.T) {
testCases := map[string]struct {
// local inventory input into applier.prepareObjects
Expand Down
3 changes: 3 additions & 0 deletions pkg/apply/event/actiongroupeventtype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/apply/event/applyeventoperation_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/apply/event/deleteeventoperation_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/apply/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const (
PruneAction
DeleteAction
WaitAction
InventoryAction
)

type ActionGroup struct {
Expand Down
3 changes: 3 additions & 0 deletions pkg/apply/event/pruneeventoperation_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions pkg/apply/event/resourceaction_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/apply/event/type_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 6 additions & 15 deletions pkg/apply/prune/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,6 @@ func (po *PruneOptions) Prune(localInv inventory.InventoryInfo,
// Sort the resources in reverse order using the same rules as is
// used for apply.
sort.Sort(sort.Reverse(ordering.SortableMetas(pruneObjs)))
// Store prune failures to ensure they remain in the inventory.
pruneFailures := []object.ObjMetadata{}
for _, pruneObj := range pruneObjs {
klog.V(5).Infof("attempting prune: %s", pruneObj)
obj, err := po.getObject(pruneObj)
Expand All @@ -139,9 +137,8 @@ func (po *PruneOptions) Prune(localInv inventory.InventoryInfo,
klog.Errorf("prune obj (%s/%s) UID retrival error: %s",
pruneObj.Namespace, pruneObj.Name, err)
}
pruneFailures = append(pruneFailures, pruneObj)
taskContext.EventChannel() <- createPruneFailedEvent(pruneObj, err)
taskContext.CaptureResourceFailure(pruneObj)
taskContext.CapturePruneFailure(pruneObj)
continue
}
// Do not prune objects that are in set of currently applied objects.
Expand All @@ -154,7 +151,7 @@ func (po *PruneOptions) Prune(localInv inventory.InventoryInfo,
if !canPrune(localInv, obj, o.InventoryPolicy, uid) {
klog.V(4).Infof("skip prune for lifecycle directive %s/%s", pruneObj.Namespace, pruneObj.Name)
taskContext.EventChannel() <- createPruneEvent(pruneObj, obj, event.PruneSkipped)
pruneFailures = append(pruneFailures, pruneObj)
taskContext.CapturePruneFailure(pruneObj)
continue
}
// If regular pruning (not destroying), skip deleting namespace containing
Expand All @@ -164,8 +161,7 @@ func (po *PruneOptions) Prune(localInv inventory.InventoryInfo,
localNamespaces.Has(pruneObj.Name) {
klog.V(4).Infof("skip pruning namespace: %s", pruneObj.Name)
taskContext.EventChannel() <- createPruneEvent(pruneObj, obj, event.PruneSkipped)
pruneFailures = append(pruneFailures, pruneObj)
taskContext.CaptureResourceFailure(pruneObj)
taskContext.CapturePruneFailure(pruneObj)
continue
}
}
Expand All @@ -177,8 +173,7 @@ func (po *PruneOptions) Prune(localInv inventory.InventoryInfo,
klog.Errorf("prune failed for %s/%s (%s)", pruneObj.Namespace, pruneObj.Name, err)
}
taskContext.EventChannel() <- createPruneFailedEvent(pruneObj, err)
pruneFailures = append(pruneFailures, pruneObj)
taskContext.CaptureResourceFailure(pruneObj)
taskContext.CapturePruneFailure(pruneObj)
continue
}
err = namespacedClient.Delete(context.TODO(), pruneObj.Name, metav1.DeleteOptions{})
Expand All @@ -187,17 +182,13 @@ func (po *PruneOptions) Prune(localInv inventory.InventoryInfo,
klog.Errorf("prune failed for %s/%s (%s)", pruneObj.Namespace, pruneObj.Name, err)
}
taskContext.EventChannel() <- createPruneFailedEvent(pruneObj, err)
pruneFailures = append(pruneFailures, pruneObj)
taskContext.CaptureResourceFailure(pruneObj)
taskContext.CapturePruneFailure(pruneObj)
continue
}
}
taskContext.EventChannel() <- createPruneEvent(pruneObj, obj, event.Pruned)
}
// Final inventory equals applied objects and prune failures.
appliedResources := taskContext.AppliedResources()
finalInventory := append(appliedResources, pruneFailures...)
return po.InvClient.Replace(localInv, finalInventory)
return nil
}

func (po *PruneOptions) namespacedClient(obj object.ObjMetadata) (dynamic.ResourceInterface, error) {
Expand Down
Loading

0 comments on commit d696804

Please sign in to comment.