Skip to content

Commit

Permalink
fix(uninstall): rely on OLM to delete operator resources via CSV dele…
Browse files Browse the repository at this point in the history
…tion (#27)

When multiple install plans are present for single operator,
select the resources of install plan containing the installed CSV
while uninstalling the operator.
  • Loading branch information
varshaprasad96 committed Nov 11, 2020
1 parent ff147ab commit fb6f935
Showing 1 changed file with 36 additions and 47 deletions.
83 changes: 36 additions & 47 deletions internal/pkg/action/operator_uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

v1 "github.com/operator-framework/api/pkg/operators/v1"
"github.com/operator-framework/api/pkg/operators/v1alpha1"
"github.com/operator-framework/operator-registry/pkg/lib/bundle"
"github.com/spf13/pflag"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -66,22 +65,13 @@ func (u *OperatorUninstall) Run(ctx context.Context) error {
return fmt.Errorf("operator package %q not found", u.Package)
}

// Since the install plan is owned by the subscription, we need to
// read all of the resource references from the install plan before
// deleting the subscription.
var crds, csvs, others []controllerutil.Object
if sub.Status.InstallPlanRef != nil {
ipKey := types.NamespacedName{
Namespace: sub.Status.InstallPlanRef.Namespace,
Name: sub.Status.InstallPlanRef.Name,
}
var err error
crds, csvs, others, err = u.getInstallPlanResources(ctx, ipKey)
if err != nil {
return fmt.Errorf("get install plan resources: %v", err)
}
csv, err := u.getInstalledCSV(ctx, sub)
if err != nil {
return fmt.Errorf("get installed CSV %q: %v", sub.Status.InstalledCSV, err)
}

crds := getCRDs(csv)

// Delete the subscription first, so that no further installs or upgrades
// of the operator occur while we're cleaning up.
if err := u.deleteObjects(ctx, sub); err != nil {
Expand All @@ -96,9 +86,10 @@ func (u *OperatorUninstall) Run(ctx context.Context) error {
}
}

// Delete CSVs and all other objects created by the install plan.
objects := append(csvs, others...)
if err := u.deleteObjects(ctx, objects...); err != nil {
// OLM puts an ownerref on every namespaced resource to the CSV,
// and an owner label on every cluster scoped resource. When CSV is deleted
// kube and olm gc will remove all the referenced resources.
if err := u.deleteObjects(ctx, csv); err != nil {
return err
}

Expand Down Expand Up @@ -140,43 +131,41 @@ func (u *OperatorUninstall) deleteObjects(ctx context.Context, objs ...controlle
return waitForDeletion(ctx, u.config.Client, objs...)
}

func (u *OperatorUninstall) getInstallPlanResources(ctx context.Context, installPlanKey types.NamespacedName) (crds, csvs, others []controllerutil.Object, err error) {
installPlan := &v1alpha1.InstallPlan{}
if err := u.config.Client.Get(ctx, installPlanKey, installPlan); err != nil {
return nil, nil, nil, fmt.Errorf("get install plan: %v", err)
func (u *OperatorUninstall) getInstalledCSV(ctx context.Context, subscription *v1alpha1.Subscription) (*v1alpha1.ClusterServiceVersion, error) {
key := types.NamespacedName{
Name: subscription.Status.InstalledCSV,
Namespace: subscription.GetNamespace(),
}

for _, step := range installPlan.Status.Plan {
obj := &unstructured.Unstructured{}
installedCSV := &v1alpha1.ClusterServiceVersion{}
if err := u.config.Client.Get(ctx, key, installedCSV); err != nil {
return nil, err
}

obj.SetGroupVersionKind(schema.GroupVersionKind{
Group: step.Resource.Group,
Version: step.Resource.Version,
Kind: step.Resource.Kind,
})
obj.SetName(step.Resource.Name)
installedCSV.SetGroupVersionKind(schema.GroupVersionKind{
Kind: csvKind,
Version: installedCSV.GroupVersionKind().Version,
Group: installedCSV.GroupVersionKind().Group,
})
return installedCSV, nil
}

// TODO: Use RESTMapper interface to identify if the object is namespaced or not.
// Reference: https://github.com/kubernetes-sigs/controller-runtime/blob/master/pkg/client/namespaced_client.go
if supported, namespaced := bundle.IsSupported(step.Resource.Kind); supported && bool(namespaced) {
obj.SetNamespace(installPlanKey.Namespace)
}
func getCRDs(csv *v1alpha1.ClusterServiceVersion) (crds []controllerutil.Object) {
for _, resource := range csv.Status.RequirementStatus {
if resource.Kind == crdKind {
obj := &unstructured.Unstructured{}
obj.SetGroupVersionKind(schema.GroupVersionKind{
Group: resource.Group,
Version: resource.Version,
Kind: resource.Kind,
})
obj.SetName(resource.Name)
obj.SetNamespace(csv.GetNamespace())

switch step.Resource.Kind {
case crdKind:
crds = append(crds, obj)
case csvKind:
csvs = append(csvs, obj)
default:
// Skip non-CRD/non-CSV resources in the install plan that were not created by the install plan.
// This means we avoid deleting things like the default service account.
if step.Status != v1alpha1.StepStatusCreated {
continue
}
others = append(others, obj)
}
}
return crds, csvs, others, nil
return
}

func contains(haystack []string, needle string) bool {
Expand Down

0 comments on commit fb6f935

Please sign in to comment.