Skip to content

Commit fdca85f

Browse files
Improve uninstall command (#29)
Refactor uninstall command to clean up all the resources, and report whether package existed correctly. Co-authored by: Eric Stroczynski <[email protected]>
1 parent d321b71 commit fdca85f

File tree

1 file changed

+46
-24
lines changed

1 file changed

+46
-24
lines changed

internal/pkg/action/operator_uninstall.go

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ func NewOperatorUninstall(cfg *Configuration) *OperatorUninstall {
3434
}
3535
}
3636

37+
type ErrPackageNotFound struct {
38+
PackageName string
39+
}
40+
41+
func (e ErrPackageNotFound) Error() string {
42+
return fmt.Sprintf("package %q not found", e.PackageName)
43+
}
44+
3745
func (u *OperatorUninstall) Run(ctx context.Context) error {
3846
if u.DeleteAll {
3947
u.DeleteCRDs = true
@@ -57,16 +65,41 @@ func (u *OperatorUninstall) Run(ctx context.Context) error {
5765
return fmt.Errorf("operator package %q not found", u.Package)
5866
}
5967

60-
csv, err := u.getInstalledCSV(ctx, sub)
61-
if err != nil {
62-
return fmt.Errorf("get installed CSV %q: %v", sub.Status.InstalledCSV, err)
68+
var subObj, csvObj controllerutil.Object
69+
var crds []controllerutil.Object
70+
if sub != nil {
71+
subObj = sub
72+
// CSV name may either be the installed or current name in a subscription's status,
73+
// depending on installation state.
74+
csvKey := types.NamespacedName{
75+
Name: sub.Status.InstalledCSV,
76+
Namespace: u.config.Namespace,
77+
}
78+
if csvKey.Name == "" {
79+
csvKey.Name = sub.Status.CurrentCSV
80+
}
81+
82+
// This value can be empty which will cause errors.
83+
if csvKey.Name != "" {
84+
csv := &v1alpha1.ClusterServiceVersion{}
85+
if err := u.config.Client.Get(ctx, csvKey, csv); err != nil && !apierrors.IsNotFound(err) {
86+
return fmt.Errorf("error getting installed CSV %q: %v", csvKey.Name, err)
87+
} else if err == nil {
88+
crds = getCRDs(csv)
89+
}
90+
csvObj = csv
91+
}
6392
}
6493

65-
crds := getCRDs(csv)
94+
// Deletion order:
95+
//
96+
// 1. Subscription to prevent further installs or upgrades of the operator while cleaning up.
97+
// 2. CustomResourceDefinitions so the operator has a chance to handle CRs that have finalizers.
98+
// 3. ClusterServiceVersion. OLM puts an ownerref on every namespaced resource to the CSV,
99+
// and an owner label on every cluster scoped resource so they get gc'd on deletion.
66100

67-
// Delete the subscription first, so that no further installs or upgrades
68-
// of the operator occur while we're cleaning up.
69-
if err := u.deleteObjects(ctx, sub); err != nil {
101+
// Subscriptions can be deleted asynchronously.
102+
if err := u.deleteObjects(ctx, subObj); err != nil {
70103
return err
71104
}
72105

@@ -81,7 +114,7 @@ func (u *OperatorUninstall) Run(ctx context.Context) error {
81114
// OLM puts an ownerref on every namespaced resource to the CSV,
82115
// and an owner label on every cluster scoped resource. When CSV is deleted
83116
// kube and olm gc will remove all the referenced resources.
84-
if err := u.deleteObjects(ctx, csv); err != nil {
117+
if err := u.deleteObjects(ctx, csvObj); err != nil {
85118
return err
86119
}
87120

@@ -107,6 +140,11 @@ func (u *OperatorUninstall) Run(ctx context.Context) error {
107140
}
108141
}
109142

143+
// If no objects were cleaned up, it means the package was not found
144+
if subObj == nil && csvObj == nil && len(crds) == 0 {
145+
return &ErrPackageNotFound{u.Package}
146+
}
147+
110148
return nil
111149
}
112150

@@ -123,22 +161,6 @@ func (u *OperatorUninstall) deleteObjects(ctx context.Context, objs ...controlle
123161
return waitForDeletion(ctx, u.config.Client, objs...)
124162
}
125163

126-
// getInstalledCSV looks up the installed CSV name from the provided subscription and fetches it.
127-
func (u *OperatorUninstall) getInstalledCSV(ctx context.Context, subscription *v1alpha1.Subscription) (*v1alpha1.ClusterServiceVersion, error) {
128-
key := types.NamespacedName{
129-
Name: subscription.Status.InstalledCSV,
130-
Namespace: subscription.GetNamespace(),
131-
}
132-
133-
installedCSV := &v1alpha1.ClusterServiceVersion{}
134-
if err := u.config.Client.Get(ctx, key, installedCSV); err != nil {
135-
return nil, err
136-
}
137-
138-
installedCSV.SetGroupVersionKind(v1alpha1.SchemeGroupVersion.WithKind(csvKind))
139-
return installedCSV, nil
140-
}
141-
142164
// getCRDs returns the list of CRDs required by a CSV.
143165
func getCRDs(csv *v1alpha1.ClusterServiceVersion) (crds []controllerutil.Object) {
144166
for _, resource := range csv.Status.RequirementStatus {

0 commit comments

Comments
 (0)