@@ -22,7 +22,6 @@ import (
22
22
23
23
v1 "github.com/operator-framework/api/pkg/operators/v1"
24
24
"github.com/operator-framework/api/pkg/operators/v1alpha1"
25
- "github.com/operator-framework/operator-registry/pkg/lib/bundle"
26
25
apierrors "k8s.io/apimachinery/pkg/api/errors"
27
26
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28
27
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -31,7 +30,11 @@ import (
31
30
"k8s.io/kubectl/pkg/util/slice"
32
31
"sigs.k8s.io/controller-runtime/pkg/client"
33
32
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
34
- "sigs.k8s.io/yaml"
33
+ )
34
+
35
+ const (
36
+ csvKind = "ClusterServiceVersion"
37
+ crdKind = "CustomResourceDefinition"
35
38
)
36
39
37
40
type Uninstall struct {
@@ -91,22 +94,13 @@ func (u *Uninstall) Run(ctx context.Context) error {
91
94
return fmt .Errorf ("get catalog source: %v" , err )
92
95
}
93
96
94
- // Since the install plan is owned by the subscription, we need to
95
- // read all of the resource references from the install plan before
96
- // deleting the subscription.
97
- var crds , csvs , others []controllerutil.Object
98
- if sub .Status .InstallPlanRef != nil {
99
- ipKey := types.NamespacedName {
100
- Namespace : sub .Status .InstallPlanRef .Namespace ,
101
- Name : sub .Status .InstallPlanRef .Name ,
102
- }
103
- var err error
104
- crds , csvs , others , err = u .getInstallPlanResources (ctx , ipKey )
105
- if err != nil {
106
- return fmt .Errorf ("get install plan resources: %v" , err )
107
- }
97
+ csv , err := u .getInstalledCSV (ctx , sub )
98
+ if err != nil {
99
+ return fmt .Errorf ("get installed CSV %q: %v" , sub .Status .InstalledCSV , err )
108
100
}
109
101
102
+ crds := getCRDs (csv )
103
+
110
104
// Delete the subscription first, so that no further installs or upgrades
111
105
// of the operator occur while we're cleaning up.
112
106
if err := u .deleteObjects (ctx , false , sub ); err != nil {
@@ -121,11 +115,13 @@ func (u *Uninstall) Run(ctx context.Context) error {
121
115
}
122
116
}
123
117
124
- // Delete CSVs and all other objects created by the install plan.
125
- objects := append (csvs , others ... )
126
- if err := u .deleteObjects (ctx , true , objects ... ); err != nil {
118
+ // OLM puts an ownerref on every namespaced resource to the CSV,
119
+ // and an owner label on every cluster scoped resource. When CSV is deleted
120
+ // kube and olm gc will remove all the referenced resources.
121
+ if err := u .deleteObjects (ctx , true , csv ); err != nil {
127
122
return err
128
123
}
124
+
129
125
} else {
130
126
catsrc .SetNamespace (u .config .Namespace )
131
127
catsrc .SetName (CatalogNameForPackage (u .Package ))
@@ -194,43 +190,35 @@ func (u *Uninstall) deleteObjects(ctx context.Context, waitForDelete bool, objs
194
190
return nil
195
191
}
196
192
197
- func (u * Uninstall ) getInstallPlanResources (ctx context.Context , installPlanKey types.NamespacedName ) (crds , csvs , others []controllerutil.Object , err error ) {
198
- installPlan := & v1alpha1.InstallPlan {}
199
- if err := u .config .Client .Get (ctx , installPlanKey , installPlan ); err != nil {
200
- return nil , nil , nil , fmt .Errorf ("get install plan: %v" , err )
193
+ // getInstalledCSV looks up the installed CSV name from the provided subscription and fetches it.
194
+ func (u * Uninstall ) getInstalledCSV (ctx context.Context , subscription * v1alpha1.Subscription ) (* v1alpha1.ClusterServiceVersion , error ) {
195
+ key := types.NamespacedName {
196
+ Name : subscription .Status .InstalledCSV ,
197
+ Namespace : subscription .GetNamespace (),
201
198
}
202
199
203
- for _ , step := range installPlan .Status .Plan {
204
- lowerKind := strings .ToLower (step .Resource .Kind )
205
- obj := & unstructured.Unstructured {Object : map [string ]interface {}{}}
206
- if err := yaml .Unmarshal ([]byte (step .Resource .Manifest ), & obj .Object ); err != nil {
207
- return nil , nil , nil , fmt .Errorf ("parse %s manifest %q: %v" , lowerKind , step .Resource .Name , err )
208
- }
209
- obj .SetGroupVersionKind (schema.GroupVersionKind {
210
- Group : step .Resource .Group ,
211
- Version : step .Resource .Version ,
212
- Kind : step .Resource .Kind ,
213
- })
214
-
215
- // TODO(joelanford): This seems necessary for namespaced resources
216
- // See: https://github.com/operator-framework/operator-lifecycle-manager/blob/c9405d035bc50d9aa290220cb8d75b0402e72707/pkg/controller/registry/resolver/rbac.go#L133
217
- if supported , namespaced := bundle .IsSupported (step .Resource .Kind ); supported && bool (namespaced ) {
218
- obj .SetNamespace (installPlanKey .Namespace )
219
- }
200
+ installedCSV := & v1alpha1.ClusterServiceVersion {}
201
+ if err := u .config .Client .Get (ctx , key , installedCSV ); err != nil {
202
+ return nil , err
203
+ }
220
204
221
- switch step .Resource .Kind {
222
- case "CustomResourceDefinition" :
205
+ installedCSV .SetGroupVersionKind (v1alpha1 .SchemeGroupVersion .WithKind (csvKind ))
206
+ return installedCSV , nil
207
+ }
208
+
209
+ // getCRDs returns the list of CRDs required by a CSV.
210
+ func getCRDs (csv * v1alpha1.ClusterServiceVersion ) (crds []controllerutil.Object ) {
211
+ for _ , resource := range csv .Status .RequirementStatus {
212
+ if resource .Kind == crdKind {
213
+ obj := & unstructured.Unstructured {}
214
+ obj .SetGroupVersionKind (schema.GroupVersionKind {
215
+ Group : resource .Group ,
216
+ Version : resource .Version ,
217
+ Kind : resource .Kind ,
218
+ })
219
+ obj .SetName (resource .Name )
223
220
crds = append (crds , obj )
224
- case "ClusterServiceVersion" :
225
- csvs = append (csvs , obj )
226
- default :
227
- // Skip non-CRD/non-CSV resources in the install plan that were not created by the install plan.
228
- // This means we avoid deleting things like the default service account.
229
- if step .Status != v1alpha1 .StepStatusCreated {
230
- continue
231
- }
232
- others = append (others , obj )
233
221
}
234
222
}
235
- return crds , csvs , others , nil
223
+ return
236
224
}
0 commit comments