mirror of https://github.com/fluxcd/cli-utils.git
Use builder for creating the destroyer
This commit is contained in:
parent
7c25ad672c
commit
5240fc4cdb
|
|
@ -118,7 +118,10 @@ func (r *Runner) RunE(cmd *cobra.Command, args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d, err := apply.NewDestroyer(r.factory, invClient)
|
d, err := apply.NewDestroyerBuilder().
|
||||||
|
WithFactory(r.factory).
|
||||||
|
WithInventoryClient(invClient).
|
||||||
|
Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,10 @@ func (r *Runner) RunE(cmd *cobra.Command, args []string) error {
|
||||||
InventoryPolicy: inventoryPolicy,
|
InventoryPolicy: inventoryPolicy,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
d, err := apply.NewDestroyer(r.factory, invClient)
|
d, err := apply.NewDestroyerBuilder().
|
||||||
|
WithFactory(r.factory).
|
||||||
|
WithInventoryClient(invClient).
|
||||||
|
Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,6 @@
|
||||||
package apply
|
package apply
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/cli-runtime/pkg/resource"
|
"k8s.io/cli-runtime/pkg/resource"
|
||||||
"k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
|
|
@ -20,15 +17,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApplierBuilder struct {
|
type ApplierBuilder struct {
|
||||||
// factory is only used to retrieve things that have not been provided explicitly.
|
commonBuilder
|
||||||
factory util.Factory
|
|
||||||
invClient inventory.Client
|
|
||||||
client dynamic.Interface
|
|
||||||
discoClient discovery.CachedDiscoveryInterface
|
|
||||||
mapper meta.RESTMapper
|
|
||||||
restConfig *rest.Config
|
|
||||||
unstructuredClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)
|
|
||||||
statusWatcher watcher.StatusWatcher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApplierBuilder returns a new ApplierBuilder.
|
// NewApplierBuilder returns a new ApplierBuilder.
|
||||||
|
|
@ -58,60 +47,6 @@ func (b *ApplierBuilder) Build() (*Applier, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ApplierBuilder) finalize() (*ApplierBuilder, error) {
|
|
||||||
bx := *b // make a copy before mutating any fields. Shallow copy is good enough.
|
|
||||||
var err error
|
|
||||||
if bx.invClient == nil {
|
|
||||||
return nil, errors.New("inventory client must be provided")
|
|
||||||
}
|
|
||||||
if bx.client == nil {
|
|
||||||
if bx.factory == nil {
|
|
||||||
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
|
||||||
}
|
|
||||||
bx.client, err = bx.factory.DynamicClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error getting dynamic client: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bx.discoClient == nil {
|
|
||||||
if bx.factory == nil {
|
|
||||||
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
|
||||||
}
|
|
||||||
bx.discoClient, err = bx.factory.ToDiscoveryClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error getting discovery client: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bx.mapper == nil {
|
|
||||||
if bx.factory == nil {
|
|
||||||
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
|
||||||
}
|
|
||||||
bx.mapper, err = bx.factory.ToRESTMapper()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error getting rest mapper: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bx.restConfig == nil {
|
|
||||||
if bx.factory == nil {
|
|
||||||
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
|
||||||
}
|
|
||||||
bx.restConfig, err = bx.factory.ToRESTConfig()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error getting rest config: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bx.unstructuredClientForMapping == nil {
|
|
||||||
if bx.factory == nil {
|
|
||||||
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
|
||||||
}
|
|
||||||
bx.unstructuredClientForMapping = bx.factory.UnstructuredClientForMapping
|
|
||||||
}
|
|
||||||
if bx.statusWatcher == nil {
|
|
||||||
bx.statusWatcher = watcher.NewDefaultStatusWatcher(bx.client, bx.mapper)
|
|
||||||
}
|
|
||||||
return &bx, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *ApplierBuilder) WithFactory(factory util.Factory) *ApplierBuilder {
|
func (b *ApplierBuilder) WithFactory(factory util.Factory) *ApplierBuilder {
|
||||||
b.factory = factory
|
b.factory = factory
|
||||||
return b
|
return b
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright 2022 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package apply
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/cli-runtime/pkg/resource"
|
||||||
|
"k8s.io/client-go/discovery"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/kubectl/pkg/cmd/util"
|
||||||
|
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||||
|
"sigs.k8s.io/cli-utils/pkg/kstatus/watcher"
|
||||||
|
)
|
||||||
|
|
||||||
|
type commonBuilder struct {
|
||||||
|
// factory is only used to retrieve things that have not been provided explicitly.
|
||||||
|
factory util.Factory
|
||||||
|
invClient inventory.Client
|
||||||
|
client dynamic.Interface
|
||||||
|
discoClient discovery.CachedDiscoveryInterface
|
||||||
|
mapper meta.RESTMapper
|
||||||
|
restConfig *rest.Config
|
||||||
|
unstructuredClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)
|
||||||
|
statusWatcher watcher.StatusWatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cb *commonBuilder) finalize() (*commonBuilder, error) {
|
||||||
|
cx := *cb // make a copy before mutating any fields. Shallow copy is good enough.
|
||||||
|
var err error
|
||||||
|
if cx.invClient == nil {
|
||||||
|
return nil, errors.New("inventory client must be provided")
|
||||||
|
}
|
||||||
|
if cx.client == nil {
|
||||||
|
if cx.factory == nil {
|
||||||
|
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
||||||
|
}
|
||||||
|
cx.client, err = cx.factory.DynamicClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting dynamic client: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cx.discoClient == nil {
|
||||||
|
if cx.factory == nil {
|
||||||
|
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
||||||
|
}
|
||||||
|
cx.discoClient, err = cx.factory.ToDiscoveryClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting discovery client: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cx.mapper == nil {
|
||||||
|
if cx.factory == nil {
|
||||||
|
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
||||||
|
}
|
||||||
|
cx.mapper, err = cx.factory.ToRESTMapper()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting rest mapper: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cx.restConfig == nil {
|
||||||
|
if cx.factory == nil {
|
||||||
|
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
||||||
|
}
|
||||||
|
cx.restConfig, err = cx.factory.ToRESTConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting rest config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cx.unstructuredClientForMapping == nil {
|
||||||
|
if cx.factory == nil {
|
||||||
|
return nil, fmt.Errorf("a factory must be provided or all other options: %v", err)
|
||||||
|
}
|
||||||
|
cx.unstructuredClientForMapping = cx.factory.UnstructuredClientForMapping
|
||||||
|
}
|
||||||
|
if cx.statusWatcher == nil {
|
||||||
|
cx.statusWatcher = watcher.NewDefaultStatusWatcher(cx.client, cx.mapper)
|
||||||
|
}
|
||||||
|
return &cx, nil
|
||||||
|
}
|
||||||
|
|
@ -109,7 +109,10 @@ func newTestDestroyer(
|
||||||
|
|
||||||
invClient := newTestInventory(t, tf)
|
invClient := newTestInventory(t, tf)
|
||||||
|
|
||||||
destroyer, err := NewDestroyer(tf, invClient)
|
destroyer, err := NewDestroyerBuilder().
|
||||||
|
WithFactory(tf).
|
||||||
|
WithInventoryClient(invClient).
|
||||||
|
Build()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
destroyer.statusWatcher = statusWatcher
|
destroyer.statusWatcher = statusWatcher
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/discovery"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
||||||
"sigs.k8s.io/cli-utils/pkg/apis/actuation"
|
"sigs.k8s.io/cli-utils/pkg/apis/actuation"
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply/cache"
|
"sigs.k8s.io/cli-utils/pkg/apply/cache"
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||||
|
|
@ -26,41 +28,16 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDestroyer returns a new destroyer. It will set up the ApplyOptions and
|
|
||||||
// PruneOptions which are responsible for capturing any command line flags.
|
|
||||||
// It currently requires IOStreams, but this is a legacy from when
|
|
||||||
// the ApplyOptions were responsible for printing progress. This is now
|
|
||||||
// handled by a separate printer with the KubectlPrinterAdapter bridging
|
|
||||||
// between the two.
|
|
||||||
func NewDestroyer(factory cmdutil.Factory, invClient inventory.Client) (*Destroyer, error) {
|
|
||||||
pruner, err := prune.NewPruner(factory, invClient)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error setting up PruneOptions: %w", err)
|
|
||||||
}
|
|
||||||
client, err := factory.DynamicClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mapper, err := factory.ToRESTMapper()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
statusWatcher := watcher.NewDefaultStatusWatcher(client, mapper)
|
|
||||||
return &Destroyer{
|
|
||||||
pruner: pruner,
|
|
||||||
statusWatcher: statusWatcher,
|
|
||||||
factory: factory,
|
|
||||||
invClient: invClient,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroyer performs the step of grabbing all the previous inventory objects and
|
// Destroyer performs the step of grabbing all the previous inventory objects and
|
||||||
// prune them. This also deletes all the previous inventory objects
|
// prune them. This also deletes all the previous inventory objects
|
||||||
type Destroyer struct {
|
type Destroyer struct {
|
||||||
pruner *prune.Pruner
|
pruner *prune.Pruner
|
||||||
statusWatcher watcher.StatusWatcher
|
statusWatcher watcher.StatusWatcher
|
||||||
factory cmdutil.Factory
|
|
||||||
invClient inventory.Client
|
invClient inventory.Client
|
||||||
|
mapper meta.RESTMapper
|
||||||
|
client dynamic.Interface
|
||||||
|
openAPIGetter discovery.OpenAPISchemaInterface
|
||||||
|
infoHelper info.Helper
|
||||||
}
|
}
|
||||||
|
|
||||||
type DestroyerOptions struct {
|
type DestroyerOptions struct {
|
||||||
|
|
@ -112,18 +89,13 @@ func (d *Destroyer) Run(ctx context.Context, invInfo inventory.Info, options Des
|
||||||
handleError(eventChannel, err)
|
handleError(eventChannel, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mapper, err := d.factory.ToRESTMapper()
|
|
||||||
if err != nil {
|
|
||||||
handleError(eventChannel, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the resources to make sure we catch those problems early
|
// Validate the resources to make sure we catch those problems early
|
||||||
// before anything has been updated in the cluster.
|
// before anything has been updated in the cluster.
|
||||||
vCollector := &validation.Collector{}
|
vCollector := &validation.Collector{}
|
||||||
validator := &validation.Validator{
|
validator := &validation.Validator{
|
||||||
Collector: vCollector,
|
Collector: vCollector,
|
||||||
Mapper: mapper,
|
Mapper: d.mapper,
|
||||||
}
|
}
|
||||||
validator.Validate(deleteObjs)
|
validator.Validate(deleteObjs)
|
||||||
|
|
||||||
|
|
@ -132,11 +104,6 @@ func (d *Destroyer) Run(ctx context.Context, invInfo inventory.Info, options Des
|
||||||
taskContext := taskrunner.NewTaskContext(eventChannel, resourceCache)
|
taskContext := taskrunner.NewTaskContext(eventChannel, resourceCache)
|
||||||
|
|
||||||
klog.V(4).Infoln("destroyer building task queue...")
|
klog.V(4).Infoln("destroyer building task queue...")
|
||||||
dynamicClient, err := d.factory.DynamicClient()
|
|
||||||
if err != nil {
|
|
||||||
handleError(eventChannel, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
deleteFilters := []filter.ValidationFilter{
|
deleteFilters := []filter.ValidationFilter{
|
||||||
filter.PreventRemoveFilter{},
|
filter.PreventRemoveFilter{},
|
||||||
filter.InventoryPolicyPruneFilter{
|
filter.InventoryPolicyPruneFilter{
|
||||||
|
|
@ -151,10 +118,10 @@ func (d *Destroyer) Run(ctx context.Context, invInfo inventory.Info, options Des
|
||||||
}
|
}
|
||||||
taskBuilder := &solver.TaskQueueBuilder{
|
taskBuilder := &solver.TaskQueueBuilder{
|
||||||
Pruner: d.pruner,
|
Pruner: d.pruner,
|
||||||
DynamicClient: dynamicClient,
|
DynamicClient: d.client,
|
||||||
OpenAPIGetter: d.factory.OpenAPIGetter(),
|
OpenAPIGetter: d.openAPIGetter,
|
||||||
InfoHelper: info.NewHelper(mapper, d.factory.UnstructuredClientForMapping),
|
InfoHelper: d.infoHelper,
|
||||||
Mapper: mapper,
|
Mapper: d.mapper,
|
||||||
InvClient: d.invClient,
|
InvClient: d.invClient,
|
||||||
Collector: vCollector,
|
Collector: vCollector,
|
||||||
PruneFilters: deleteFilters,
|
PruneFilters: deleteFilters,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright 2022 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package apply
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/cli-runtime/pkg/resource"
|
||||||
|
"k8s.io/client-go/discovery"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/kubectl/pkg/cmd/util"
|
||||||
|
"sigs.k8s.io/cli-utils/pkg/apply/info"
|
||||||
|
"sigs.k8s.io/cli-utils/pkg/apply/prune"
|
||||||
|
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||||
|
"sigs.k8s.io/cli-utils/pkg/kstatus/watcher"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DestroyerBuilder struct {
|
||||||
|
commonBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDestroyerBuilder returns a new DestroyerBuilder.
|
||||||
|
func NewDestroyerBuilder() *DestroyerBuilder {
|
||||||
|
return &DestroyerBuilder{
|
||||||
|
// Defaults, if any, go here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) Build() (*Destroyer, error) {
|
||||||
|
bx, err := b.finalize()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Destroyer{
|
||||||
|
pruner: &prune.Pruner{
|
||||||
|
InvClient: bx.invClient,
|
||||||
|
Client: bx.client,
|
||||||
|
Mapper: bx.mapper,
|
||||||
|
},
|
||||||
|
statusWatcher: bx.statusWatcher,
|
||||||
|
invClient: bx.invClient,
|
||||||
|
mapper: bx.mapper,
|
||||||
|
client: bx.client,
|
||||||
|
openAPIGetter: bx.discoClient,
|
||||||
|
infoHelper: info.NewHelper(bx.mapper, bx.unstructuredClientForMapping),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithFactory(factory util.Factory) *DestroyerBuilder {
|
||||||
|
b.factory = factory
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithInventoryClient(invClient inventory.Client) *DestroyerBuilder {
|
||||||
|
b.invClient = invClient
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithDynamicClient(client dynamic.Interface) *DestroyerBuilder {
|
||||||
|
b.client = client
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithDiscoveryClient(discoClient discovery.CachedDiscoveryInterface) *DestroyerBuilder {
|
||||||
|
b.discoClient = discoClient
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithRestMapper(mapper meta.RESTMapper) *DestroyerBuilder {
|
||||||
|
b.mapper = mapper
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithRestConfig(restConfig *rest.Config) *DestroyerBuilder {
|
||||||
|
b.restConfig = restConfig
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithUnstructuredClientForMapping(unstructuredClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)) *DestroyerBuilder {
|
||||||
|
b.unstructuredClientForMapping = unstructuredClientForMapping
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *DestroyerBuilder) WithStatusWatcher(statusWatcher watcher.StatusWatcher) *DestroyerBuilder {
|
||||||
|
b.statusWatcher = statusWatcher
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
@ -79,7 +79,10 @@ func newDestroyer(invFactory inventory.ClientFactory, cfg *rest.Config) *apply.D
|
||||||
invClient, err := invFactory.NewClient(f)
|
invClient, err := invFactory.NewClient(f)
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
|
|
||||||
d, err := apply.NewDestroyer(f, invClient)
|
d, err := apply.NewDestroyerBuilder().
|
||||||
|
WithFactory(f).
|
||||||
|
WithInventoryClient(invClient).
|
||||||
|
Build()
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue