Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aggregate errors in uninstall functions #3294

Merged
merged 2 commits into from Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -30,7 +30,6 @@ require (
github.com/gonvenience/ytbx v1.4.4
github.com/google/go-cmp v0.5.9
github.com/google/go-containerregistry v0.12.1
github.com/hashicorp/go-multierror v1.1.1
github.com/homeport/dyff v1.5.6
github.com/lucasb-eyer/go-colorful v1.2.0
github.com/manifoldco/promptui v0.9.0
Expand Down Expand Up @@ -141,6 +140,7 @@ require (
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/imdario/mergo v0.3.13 // indirect
Expand Down
18 changes: 10 additions & 8 deletions internal/build/diff.go
Expand Up @@ -27,20 +27,22 @@ import (
"sort"
"strings"

"github.com/fluxcd/flux2/pkg/printers"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/ssa"
"github.com/gonvenience/bunt"
"github.com/gonvenience/ytbx"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
"github.com/homeport/dyff/pkg/dyff"
"github.com/lucasb-eyer/go-colorful"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/errors"
"sigs.k8s.io/cli-utils/pkg/kstatus/polling"
"sigs.k8s.io/cli-utils/pkg/object"
"sigs.k8s.io/yaml"

"github.com/fluxcd/pkg/ssa"

"github.com/fluxcd/flux2/pkg/printers"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)

func (b *Builder) Manager() (*ssa.ResourceManager, error) {
Expand Down Expand Up @@ -85,7 +87,7 @@ func (b *Builder) Diff() (string, bool, error) {
}
}

var diffErrs error
var diffErrs []error
// create an inventory of objects to be reconciled
newInventory := newInventory()
for _, obj := range objects {
Expand All @@ -97,7 +99,7 @@ func (b *Builder) Diff() (string, bool, error) {
change, liveObject, mergedObject, err := resourceManager.Diff(ctx, obj, diffOptions)
if err != nil {
// gather errors and continue, as we want to see all the diffs
diffErrs = multierror.Append(diffErrs, err)
diffErrs = append(diffErrs, err)
continue
}

Expand Down Expand Up @@ -135,7 +137,7 @@ func (b *Builder) Diff() (string, bool, error) {
b.spinner.Message("processing inventory")
}

if b.kustomization.Spec.Prune && diffErrs == nil {
if b.kustomization.Spec.Prune && len(diffErrs) == 0 {
oldStatus := b.kustomization.Status.DeepCopy()
if oldStatus.Inventory != nil {
diffObjects, err := diffInventory(oldStatus.Inventory, newInventory)
Expand All @@ -155,7 +157,7 @@ func (b *Builder) Diff() (string, bool, error) {
}
}

return output.String(), createdOrDrifted, diffErrs
return output.String(), createdOrDrifted, errors.Reduce(errors.Flatten(errors.NewAggregate(diffErrs)))
}

func writeYamls(liveObject, mergedObject *unstructured.Unstructured) (string, string, string, error) {
Expand Down
39 changes: 35 additions & 4 deletions pkg/uninstall/uninstall.go
Expand Up @@ -25,6 +25,7 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/errors"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/fluxcd/flux2/pkg/log"
Expand All @@ -38,7 +39,8 @@ import (
)

// Components removes all Kubernetes components that are part of Flux excluding the CRDs and namespace.
func Components(ctx context.Context, logger log.Logger, kubeClient client.Client, namespace string, dryRun bool) {
func Components(ctx context.Context, logger log.Logger, kubeClient client.Client, namespace string, dryRun bool) error {
var aggregateErr []error
opts, dryRunStr := getDeleteOptions(dryRun)
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
{
Expand All @@ -47,6 +49,7 @@ func Components(ctx context.Context, logger log.Logger, kubeClient client.Client
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("Deployment/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("Deployment/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -59,6 +62,7 @@ func Components(ctx context.Context, logger log.Logger, kubeClient client.Client
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("Service/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("Service/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -71,6 +75,7 @@ func Components(ctx context.Context, logger log.Logger, kubeClient client.Client
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("NetworkPolicy/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("NetworkPolicy/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -83,6 +88,7 @@ func Components(ctx context.Context, logger log.Logger, kubeClient client.Client
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("ServiceAccount/%s/%s deletion failed: %s", r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("ServiceAccount/%s/%s deleted %s", r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -95,6 +101,7 @@ func Components(ctx context.Context, logger log.Logger, kubeClient client.Client
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("ClusterRole/%s deletion failed: %s", r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("ClusterRole/%s deleted %s", r.Name, dryRunStr)
}
Expand All @@ -107,16 +114,20 @@ func Components(ctx context.Context, logger log.Logger, kubeClient client.Client
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("ClusterRoleBinding/%s deletion failed: %s", r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("ClusterRoleBinding/%s deleted %s", r.Name, dryRunStr)
}
}
}
}

return errors.Reduce(errors.Flatten(errors.NewAggregate(aggregateErr)))
}

// Finalizers removes all finalizes on Kubernetes components that have been added by a Flux controller.
func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client, dryRun bool) {
func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client, dryRun bool) error {
var aggregateErr []error
opts, dryRunStr := getUpdateOptions(dryRun)
{
var list sourcev1.GitRepositoryList
Expand All @@ -125,6 +136,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -138,6 +150,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -151,6 +164,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -164,6 +178,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -177,6 +192,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -190,6 +206,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -203,6 +220,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -216,6 +234,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -229,6 +248,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -242,6 +262,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -255,6 +276,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -268,6 +290,7 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
Expand All @@ -281,16 +304,19 @@ func Finalizers(ctx context.Context, logger log.Logger, kubeClient client.Client
r.Finalizers = []string{}
if err := kubeClient.Update(ctx, &r, opts); err != nil {
logger.Failuref("%s/%s/%s removing finalizers failed: %s", r.Kind, r.Namespace, r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("%s/%s/%s finalizers deleted %s", r.Kind, r.Namespace, r.Name, dryRunStr)
}
}
}
}
return errors.Reduce(errors.Flatten(errors.NewAggregate(aggregateErr)))
}

// CustomResourceDefinitions removes all Kubernetes CRDs that are a part of Flux.
func CustomResourceDefinitions(ctx context.Context, logger log.Logger, kubeClient client.Client, dryRun bool) {
func CustomResourceDefinitions(ctx context.Context, logger log.Logger, kubeClient client.Client, dryRun bool) error {
var aggregateErr []error
opts, dryRunStr := getDeleteOptions(dryRun)
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
{
Expand All @@ -299,23 +325,28 @@ func CustomResourceDefinitions(ctx context.Context, logger log.Logger, kubeClien
for _, r := range list.Items {
if err := kubeClient.Delete(ctx, &r, opts); err != nil {
logger.Failuref("CustomResourceDefinition/%s deletion failed: %s", r.Name, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("CustomResourceDefinition/%s deleted %s", r.Name, dryRunStr)
}
}
}
}
return errors.Reduce(errors.Flatten(errors.NewAggregate(aggregateErr)))
}

// Namespace removes the namespace Flux is installed in.
func Namespace(ctx context.Context, logger log.Logger, kubeClient client.Client, namespace string, dryRun bool) {
func Namespace(ctx context.Context, logger log.Logger, kubeClient client.Client, namespace string, dryRun bool) error {
var aggregateErr []error
opts, dryRunStr := getDeleteOptions(dryRun)
ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
if err := kubeClient.Delete(ctx, &ns, opts); err != nil {
logger.Failuref("Namespace/%s deletion failed: %s", namespace, err.Error())
aggregateErr = append(aggregateErr, err)
} else {
logger.Successf("Namespace/%s deleted %s", namespace, dryRunStr)
}
return errors.Reduce(errors.Flatten(errors.NewAggregate(aggregateErr)))
}

func getDeleteOptions(dryRun bool) (*client.DeleteOptions, string) {
Expand Down