Merge pull request #22 from mortent/IntegratePruneWithApplier

Integrate prune with the applier
This commit is contained in:
Kubernetes Prow Robot 2020-02-04 13:29:27 -08:00 committed by GitHub
commit aae51d6f6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 49 deletions

View File

@ -32,6 +32,7 @@ func NewApplier(factory util.Factory, ioStreams genericclioptions.IOStreams) *Ap
return &Applier{
ApplyOptions: apply.NewApplyOptions(ioStreams),
StatusOptions: NewStatusOptions(),
PruneOptions: prune.NewPruneOptions(),
factory: factory,
ioStreams: ioStreams,
}
@ -51,6 +52,7 @@ type Applier struct {
ApplyOptions *apply.ApplyOptions
StatusOptions *StatusOptions
PruneOptions *prune.PruneOptions
resolver resolver
}
@ -63,9 +65,10 @@ func (a *Applier) Initialize(cmd *cobra.Command) error {
if err != nil {
return errors.WrapPrefix(err, "error setting up ApplyOptions", 1)
}
// Default PostProcessor is configured in "Complete" function,
// so the prune must happen after "Complete".
a.ApplyOptions.PostProcessorFn = pruneExec(a.factory, a.ApplyOptions)
err = a.PruneOptions.Initialize(a.factory, a.ApplyOptions.Namespace)
if err != nil {
return errors.WrapPrefix(err, "error setting up PruntOptions", 1)
}
resolver, err := a.newResolver(a.StatusOptions.period)
if err != nil {
@ -126,6 +129,7 @@ func (a *Applier) Run(ctx context.Context) <-chan Event {
// The adapter is used to intercept what is meant to be printing
// in the ApplyOptions, and instead turn those into events.
a.ApplyOptions.ToPrinter = adapter.toPrinterFunc()
a.PruneOptions.ToPrinter = adapter.toPrinterFunc()
// This provides us with a slice of all the objects that will be
// applied to the cluster.
infos, _ := a.ApplyOptions.GetObjects()
@ -154,6 +158,20 @@ func (a *Applier) Run(ctx context.Context) <-chan Event {
}
}
}
infos, _ = a.ApplyOptions.GetObjects()
err = a.PruneOptions.Prune(infos)
if err != nil {
// If we see an error here we just report it on the channel and then
// give up. Eventually we might be able to determine which errors
// are fatal and which might allow us to continue.
ch <- Event{
EventType: ErrorEventType,
ErrorEvent: ErrorEvent{
Err: errors.WrapPrefix(err, "error pruning resources", 1),
},
}
return
}
}()
return ch
}
@ -228,16 +246,3 @@ func prependGroupingObject(o *apply.ApplyOptions) func() error {
return nil
}
}
// Prune deletes previously applied objects that have been
// omitted in the current apply. The previously applied objects
// are reached through ConfigMap grouping objects.
func pruneExec(f util.Factory, o *apply.ApplyOptions) func() error {
return func() error {
po, err := prune.NewPruneOptions(f, o)
if err != nil {
return err
}
return po.Prune()
}
}

View File

@ -14,14 +14,12 @@ package prune
import (
"fmt"
"io"
"strings"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/dynamic"
"k8s.io/kubectl/pkg/cmd/apply"
"k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/validation"
)
@ -45,7 +43,7 @@ type PruneOptions struct {
pastGroupingObjects []*resource.Info
retrievedGroupingObjects bool
toPrinter func(string) (printers.ResourcePrinter, error)
ToPrinter func(string) (printers.ResourcePrinter, error)
out io.Writer
validator validation.Schema
@ -57,42 +55,30 @@ type PruneOptions struct {
// information to run the prune. Returns an error if an error occurs
// gathering this information.
// TODO: Add dry-run options.
func NewPruneOptions(f util.Factory, ao *apply.ApplyOptions) (*PruneOptions, error) {
func NewPruneOptions() *PruneOptions {
po := &PruneOptions{}
return po
}
func (po *PruneOptions) Initialize(factory util.Factory, namespace string) error {
var err error
// Fields copied from ApplyOptions.
po.namespace = ao.Namespace
po.toPrinter = ao.ToPrinter
po.out = ao.Out
po.namespace = namespace
// Client/Builder fields from the Factory.
po.client, err = f.DynamicClient()
po.client, err = factory.DynamicClient()
if err != nil {
return nil, err
return err
}
po.builder = f.NewBuilder()
po.mapper, err = f.ToRESTMapper()
po.builder = factory.NewBuilder()
po.mapper, err = factory.ToRESTMapper()
if err != nil {
return nil, err
return err
}
po.validator, err = f.Validator(false)
po.validator, err = factory.Validator(false)
if err != nil {
return nil, err
return err
}
// Retrieve/store the grouping object for current apply.
currentObjects, err := ao.GetObjects()
if err != nil {
return nil, err
}
currentGroupingObject, found := FindGroupingObject(currentObjects)
if !found {
return nil, fmt.Errorf("current grouping object not found during prune")
}
po.currentGroupingObject = currentGroupingObject
// Initialize past grouping objects as empty.
po.pastGroupingObjects = []*resource.Info{}
po.retrievedGroupingObjects = false
return po, nil
return nil
}
// getPreviousGroupingObjects returns the set of grouping objects
@ -216,7 +202,16 @@ func (po *PruneOptions) calcPruneSet(pastGroupingInfos []*resource.Info) (*Inven
// (retrieved from previous grouping objects) but omitted in
// the current apply. Prune also delete all previous grouping
// objects. Returns an error if there was a problem.
func (po *PruneOptions) Prune() error {
func (po *PruneOptions) Prune(currentObjects []*resource.Info) error {
currentGroupingObject, found := FindGroupingObject(currentObjects)
if !found {
return fmt.Errorf("current grouping object not found during prune")
}
po.currentGroupingObject = currentGroupingObject
// Initialize past grouping objects as empty.
po.pastGroupingObjects = []*resource.Info{}
po.retrievedGroupingObjects = false
// Retrieve previous grouping objects, and calculate the
// union of the previous applies as an inventory set.
pastGroupingInfos, err := po.getPreviousGroupingObjects()
@ -233,11 +228,24 @@ func (po *PruneOptions) Prune() error {
if err != nil {
return err
}
err = po.client.Resource(mapping.Resource).Namespace(inv.Namespace).Delete(inv.Name, &metav1.DeleteOptions{})
// Fetching the resource here before deletion seems a bit unnecessary, but
// it allows us to work with the ResourcePrinter.
namespacedClient := po.client.Resource(mapping.Resource).Namespace(inv.Namespace)
obj, err := namespacedClient.Get(inv.Name, metav1.GetOptions{})
if err != nil {
return err
}
fmt.Fprintf(po.out, "%s/%s deleted\n", strings.ToLower(inv.GroupKind.Kind), inv.Name)
err = namespacedClient.Delete(inv.Name, &metav1.DeleteOptions{})
if err != nil {
return err
}
printer, err := po.ToPrinter("deleted")
if err != nil {
return err
}
if err = printer.PrintObj(obj, po.out); err != nil {
return err
}
}
// Delete previous grouping objects.
for _, pastGroupInfo := range pastGroupingInfos {
@ -247,7 +255,7 @@ func (po *PruneOptions) Prune() error {
if err != nil {
return err
}
printer, err := po.toPrinter("deleted")
printer, err := po.ToPrinter("deleted")
if err != nil {
return err
}