Skip to content

Commit af9a037

Browse files
authored
Merge pull request #190 from seans3/inventory-client
Creates InventoryClient to refactor prune
2 parents aaa5c94 + 0062a26 commit af9a037

File tree

8 files changed

+354
-326
lines changed

8 files changed

+354
-326
lines changed

pkg/apply/applier.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ func NewApplier(factory util.Factory, ioStreams genericclioptions.IOStreams) *Ap
4545
factory: factory,
4646
ioStreams: ioStreams,
4747
}
48-
a.previousInventoriesFunc = a.PruneOptions.GetPreviousInventoryObjects
4948
a.infoHelperFactoryFunc = a.infoHelperFactory
5049
a.InventoryFactoryFunc = inventory.WrapInventoryObj
5150
a.PruneOptions.InventoryFactoryFunc = inventory.WrapInventoryObj
@@ -69,15 +68,8 @@ type Applier struct {
6968
ApplyOptions *apply.ApplyOptions
7069
PruneOptions *prune.PruneOptions
7170
StatusPoller poller.Poller
71+
invClient inventory.InventoryClient
7272

73-
//TODO(mortent): See if we can come up with a better structure here
74-
// so we don't need these functions to facilitate testing.
75-
//
76-
// previousInventoriesFunc is used to fetch the existing inventories
77-
// from the apiserver, taking the current inventory object as the
78-
// parameter. It is defined here so we can override it in
79-
// unit tests.
80-
previousInventoriesFunc func(*resource.Info) ([]inventory.Inventory, error)
8173
// infoHelperFactoryFunc is used to create a new instance of the
8274
// InfoHelper. It is defined here so we can override it in unit tests.
8375
infoHelperFactoryFunc func() info.InfoHelper
@@ -99,7 +91,11 @@ func (a *Applier) Initialize(cmd *cobra.Command) error {
9991
return errors.WrapPrefix(err, "error setting up ApplyOptions", 1)
10092
}
10193
a.ApplyOptions.PostProcessorFn = nil // Turn off the default kubectl pruning
102-
err = a.PruneOptions.Initialize(a.factory)
94+
a.invClient, err = inventory.NewInventoryClient(a.factory)
95+
if err != nil {
96+
return err
97+
}
98+
err = a.PruneOptions.Initialize(a.factory, a.invClient)
10399
if err != nil {
104100
return errors.WrapPrefix(err, "error setting up PruneOptions", 1)
105101
}
@@ -181,7 +177,7 @@ func (a *Applier) prepareObjects(infos []*resource.Info) (*ResourceObjects, erro
181177
}
182178

183179
// Fetch all previous inventories.
184-
previousInventories, err := a.previousInventoriesFunc(inventoryObject)
180+
previousInventories, err := a.invClient.GetPreviousInventoryObjects(inventoryObject)
185181
if err != nil {
186182
return nil, err
187183
}
@@ -204,7 +200,7 @@ func (a *Applier) prepareObjects(infos []*resource.Info) (*ResourceObjects, erro
204200
// resources that should be pruned.
205201
type ResourceObjects struct {
206202
CurrentInventory *resource.Info
207-
PreviousInventories []inventory.Inventory
203+
PreviousInventories []*resource.Info
208204
Resources []*resource.Info
209205
}
210206

@@ -228,7 +224,7 @@ func (r *ResourceObjects) IdsForApply() []object.ObjMetadata {
228224
// IdsForPrune returns the Ids for all resources that should
229225
// be pruned.
230226
func (r *ResourceObjects) IdsForPrune() []object.ObjMetadata {
231-
inventory, _ := prune.UnionPastObjs(r.PreviousInventories)
227+
inventory, _ := inventory.UnionPastObjs(r.PreviousInventories)
232228

233229
applyIds := make(map[object.ObjMetadata]bool)
234230
for _, id := range r.IdsForApply() {

pkg/apply/applier_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,9 +512,7 @@ func TestReadAndPrepareObjects(t *testing.T) {
512512
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams() //nolint:dogsled
513513
applier := NewApplier(tf, ioStreams)
514514

515-
applier.previousInventoriesFunc = func(currentInv *resource.Info) ([]inventory.Inventory, error) {
516-
return []inventory.Inventory{}, nil
517-
}
515+
applier.invClient = inventory.NewFakeInventoryClient([]*resource.Info{})
518516

519517
resourceObjects, err := applier.prepareObjects(tc.resources)
520518

pkg/apply/destroyer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ func (d *Destroyer) Initialize(cmd *cobra.Command, paths []string) error {
6060
if err != nil {
6161
return errors.WrapPrefix(err, "error setting up ApplyOptions", 1)
6262
}
63-
err = d.PruneOptions.Initialize(d.factory)
63+
invClient, err := inventory.NewInventoryClient(d.factory)
64+
if err != nil {
65+
return err
66+
}
67+
err = d.PruneOptions.Initialize(d.factory, invClient)
6468
if err != nil {
6569
return errors.WrapPrefix(err, "error setting up PruneOptions", 1)
6670
}

pkg/apply/prune/prune.go

Lines changed: 12 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,17 @@ import (
2222
"k8s.io/client-go/dynamic"
2323
"k8s.io/klog"
2424
"k8s.io/kubectl/pkg/cmd/util"
25-
"k8s.io/kubectl/pkg/validation"
2625
"sigs.k8s.io/cli-utils/pkg/apply/event"
2726
"sigs.k8s.io/cli-utils/pkg/common"
2827
"sigs.k8s.io/cli-utils/pkg/inventory"
29-
"sigs.k8s.io/cli-utils/pkg/object"
3028
)
3129

3230
// PruneOptions encapsulates the necessary information to
3331
// implement the prune functionality.
3432
type PruneOptions struct {
35-
client dynamic.Interface
36-
builder *resource.Builder
37-
mapper meta.RESTMapper
38-
// The currently applied objects (as Infos), including the
39-
// current inventory object. These objects are used to
40-
// calculate the prune set after retrieving the previous
41-
// inventory objects.
42-
currentInventoryObject *resource.Info
33+
invClient inventory.InventoryClient
34+
client dynamic.Interface
35+
mapper meta.RESTMapper
4336
// Stores the UID for each of the currently applied objects.
4437
// These UID's are written during the apply, and this data
4538
// structure is shared. IMPORTANT: the apply task must
@@ -49,9 +42,7 @@ type PruneOptions struct {
4942
// by the inventory label. This set should also include the
5043
// current inventory object. Stored here to make testing
5144
// easier by manually setting the retrieved inventory infos.
52-
pastInventoryObjects []*resource.Info
53-
retrievedInventoryObjects bool
54-
validator validation.Schema
45+
5546
// InventoryFactoryFunc wraps and returns an interface for the
5647
// object which will load and store the inventory.
5748
InventoryFactoryFunc func(*resource.Info) inventory.Inventory
@@ -66,134 +57,21 @@ func NewPruneOptions(currentUids sets.String) *PruneOptions {
6657
return po
6758
}
6859

69-
func (po *PruneOptions) Initialize(factory util.Factory) error {
60+
func (po *PruneOptions) Initialize(factory util.Factory, invClient inventory.InventoryClient) error {
7061
var err error
62+
po.invClient = invClient
7163
// Client/Builder fields from the Factory.
7264
po.client, err = factory.DynamicClient()
7365
if err != nil {
7466
return err
7567
}
76-
po.builder = factory.NewBuilder()
7768
po.mapper, err = factory.ToRESTMapper()
7869
if err != nil {
7970
return err
8071
}
81-
po.validator, err = factory.Validator(false)
82-
if err != nil {
83-
return err
84-
}
85-
// Initialize past inventory objects as empty.
86-
po.pastInventoryObjects = []*resource.Info{}
87-
po.retrievedInventoryObjects = false
8872
return nil
8973
}
9074

91-
// GetPreviousInventoryObjects returns the set of inventory objects
92-
// that have the same label as the current inventory object. Removes
93-
// the current inventory object from this set. Returns an error
94-
// if there is a problem retrieving the inventory objects.
95-
func (po *PruneOptions) GetPreviousInventoryObjects(currentInv *resource.Info) ([]inventory.Inventory, error) {
96-
current, err := infoToObjMetadata(currentInv)
97-
if err != nil {
98-
return nil, err
99-
}
100-
label, err := inventory.RetrieveInventoryLabel(currentInv.Object)
101-
if err != nil {
102-
return nil, err
103-
}
104-
if _, err := po.retrievePreviousInventoryObjects(current, label); err != nil {
105-
return nil, err
106-
}
107-
// Remove the current inventory info from the previous inventory infos.
108-
pastInventoryInfos := []*resource.Info{}
109-
pastInventories := []inventory.Inventory{}
110-
for _, pastInfo := range po.pastInventoryObjects {
111-
past, err := infoToObjMetadata(pastInfo)
112-
if err != nil {
113-
return nil, err
114-
}
115-
if !current.Equals(past) {
116-
pastInv := po.InventoryFactoryFunc(pastInfo)
117-
pastInventories = append(pastInventories, pastInv)
118-
pastInventoryInfos = append(pastInventoryInfos, pastInfo)
119-
}
120-
}
121-
po.pastInventoryObjects = pastInventoryInfos
122-
return pastInventories, nil
123-
}
124-
125-
// retrievePreviousInventoryObjects requests the previous inventory objects
126-
// using the inventory label from the current inventory object. Sets
127-
// the field "pastInventoryObjects". Returns an error if the inventory
128-
// label doesn't exist for the current currentInventoryObject does not
129-
// exist or if the call to retrieve the past inventory objects fails.
130-
func (po *PruneOptions) retrievePreviousInventoryObjects(current *object.ObjMetadata, label string) ([]*resource.Info, error) {
131-
if po.retrievedInventoryObjects {
132-
return po.pastInventoryObjects, nil
133-
}
134-
mapping, err := po.mapper.RESTMapping(current.GroupKind)
135-
if err != nil {
136-
return nil, err
137-
}
138-
groupResource := mapping.Resource.GroupResource().String()
139-
namespace := current.Namespace
140-
labelSelector := fmt.Sprintf("%s=%s", common.InventoryLabel, label)
141-
klog.V(4).Infof("prune inventory object fetch: %s/%s/%s", groupResource, namespace, labelSelector)
142-
retrievedInventoryInfos, err := po.builder.
143-
Unstructured().
144-
// TODO: Check if this validator is necessary.
145-
Schema(po.validator).
146-
ContinueOnError().
147-
NamespaceParam(namespace).DefaultNamespace().
148-
ResourceTypes(groupResource).
149-
LabelSelectorParam(labelSelector).
150-
Flatten().
151-
Do().
152-
Infos()
153-
if err != nil {
154-
return nil, err
155-
}
156-
po.pastInventoryObjects = retrievedInventoryInfos
157-
po.retrievedInventoryObjects = true
158-
klog.V(4).Infof("prune %d inventory objects found", len(po.pastInventoryObjects))
159-
return retrievedInventoryInfos, nil
160-
}
161-
162-
// infoToObjMetadata transforms the object represented by the passed "info"
163-
// into its Inventory representation. Returns error if the passed Info
164-
// is nil, or the Object in the Info is empty.
165-
func infoToObjMetadata(info *resource.Info) (*object.ObjMetadata, error) {
166-
if info == nil || info.Object == nil {
167-
return nil, fmt.Errorf("empty resource.Info can not calculate as inventory")
168-
}
169-
obj := info.Object
170-
gk := obj.GetObjectKind().GroupVersionKind().GroupKind()
171-
return object.CreateObjMetadata(info.Namespace, info.Name, gk)
172-
}
173-
174-
// UnionPastObjs takes a set of inventory objects (infos), returning the
175-
// union of the objects referenced by these inventory objects.
176-
// Returns an error if any of the passed objects are not inventory
177-
// objects, or if unable to retrieve the referenced objects from any
178-
// inventory object.
179-
func UnionPastObjs(pastInvs []inventory.Inventory) ([]object.ObjMetadata, error) {
180-
objSet := map[string]object.ObjMetadata{}
181-
for _, inv := range pastInvs {
182-
objs, err := inv.Load()
183-
if err != nil {
184-
return nil, err
185-
}
186-
for _, obj := range objs {
187-
objSet[obj.String()] = obj // De-duping
188-
}
189-
}
190-
pastObjs := make([]object.ObjMetadata, 0, len(objSet))
191-
for _, obj := range objSet {
192-
pastObjs = append(pastObjs, obj)
193-
}
194-
return pastObjs, nil
195-
}
196-
19775
// Options defines a set of parameters that can be used to tune
19876
// the behavior of the pruner.
19977
type Options struct {
@@ -213,17 +91,12 @@ func (po *PruneOptions) Prune(currentObjects []*resource.Info, eventChannel chan
21391
if !found {
21492
return fmt.Errorf("current inventory object not found during prune")
21593
}
216-
po.currentInventoryObject = currentInventoryObject
21794
klog.V(7).Infof("prune current inventory object: %s/%s",
21895
currentInventoryObject.Namespace, currentInventoryObject.Name)
21996

22097
// Retrieve previous inventory objects, and calculate the
22198
// union of the previous applies as an inventory set.
222-
pastInventories, err := po.GetPreviousInventoryObjects(currentInventoryObject)
223-
if err != nil {
224-
return err
225-
}
226-
pastObjs, err := UnionPastObjs(pastInventories)
99+
pastObjs, err := po.invClient.GetStoredObjRefs(currentInventoryObject)
227100
if err != nil {
228101
return err
229102
}
@@ -287,7 +160,11 @@ func (po *PruneOptions) Prune(currentObjects []*resource.Info, eventChannel chan
287160
}
288161
}
289162
// Delete previous inventory objects.
290-
for _, pastGroupInfo := range po.pastInventoryObjects {
163+
pastInventories, err := po.invClient.GetPreviousInventoryObjects(currentInventoryObject)
164+
if err != nil {
165+
return err
166+
}
167+
for _, pastGroupInfo := range pastInventories {
291168
if !o.DryRun {
292169
klog.V(7).Infof("prune delete previous inventory object: %s/%s",
293170
pastGroupInfo.Namespace, pastGroupInfo.Name)

0 commit comments

Comments
 (0)