@@ -22,14 +22,18 @@ import (
22
22
"time"
23
23
24
24
"github.com/pkg/errors"
25
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
25
26
apierrors "k8s.io/apimachinery/pkg/api/errors"
26
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
28
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
29
+ "k8s.io/apimachinery/pkg/runtime/schema"
30
+ "k8s.io/apimachinery/pkg/util/sets"
28
31
utilversion "k8s.io/apimachinery/pkg/util/version"
29
32
"k8s.io/client-go/discovery"
30
33
"k8s.io/client-go/kubernetes"
31
34
"k8s.io/client-go/rest"
32
35
"k8s.io/client-go/tools/clientcmd"
36
+ clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
33
37
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme"
34
38
"sigs.k8s.io/cluster-api/version"
35
39
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -56,7 +60,10 @@ type Proxy interface {
56
60
// CheckClusterAvailable checks if a a cluster is available and reachable.
57
61
CheckClusterAvailable () error
58
62
59
- // ListResources returns all the Kubernetes objects with the given labels existing the listed namespaces.
63
+ // ListResources lists namespaced and cluster-wide resources matching the labels. Namespaced resources are only listed
64
+ // in the given namespaces.
65
+ // If labels contains the ProviderLabelName label, CRDs of other providers are excluded.
66
+ // This is done to avoid errors when listing resources of providers which have already been deleted.
60
67
ListResources (labels map [string ]string , namespaces ... string ) ([]unstructured.Unstructured , error )
61
68
62
69
// GetContexts returns the list of contexts in kubeconfig which begin with prefix.
@@ -198,6 +205,17 @@ func (k *proxy) CheckClusterAvailable() error {
198
205
return nil
199
206
}
200
207
208
+ // ListResources lists namespaced and cluster-wide resources matching the labels. Namespaced resources are only listed
209
+ // in the given namespaces.
210
+ // If labels contains the ProviderLabelName label, CRDs of other providers are excluded.
211
+ // This is done to avoid errors when listing resources of providers which have already been deleted.
212
+ // For example:
213
+ // * The AWS provider has already been deleted, but there are still cluster-wide resources of AWSClusterControllerIdentity.
214
+ // * The AWSClusterControllerIdentity resources are still stored in an older version (e.g. v1alpha4, when the preferred
215
+ // version is v1beta1)
216
+ // * If we now want to delete e.g. the kubeadm bootstrap provider, we cannot list AWSClusterControllerIdentity resources
217
+ // as the conversion would fail, because the AWS controller hosting the conversion webhook has already been deleted.
218
+ // * Thus we exclude resources of other providers if we detect that ListResources is called to list resources of a provider.
201
219
func (k * proxy ) ListResources (labels map [string ]string , namespaces ... string ) ([]unstructured.Unstructured , error ) {
202
220
cs , err := k .newClientSet ()
203
221
if err != nil {
@@ -219,6 +237,31 @@ func (k *proxy) ListResources(labels map[string]string, namespaces ...string) ([
219
237
return nil , errors .Wrap (err , "failed to list api resources" )
220
238
}
221
239
240
+ // If labels indicates that resources of a specific provider should be listed, exclude CRDs of other providers.
241
+ crdsToExclude := sets.String {}
242
+ if providerName , ok := labels [clusterv1 .ProviderLabelName ]; ok {
243
+ // List all CRDs in the cluster.
244
+ crdList := & apiextensionsv1.CustomResourceDefinitionList {}
245
+ if err := retryWithExponentialBackoff (newReadBackoff (), func () error {
246
+ return c .List (ctx , crdList )
247
+ }); err != nil {
248
+ return nil , errors .Wrap (err , "failed to list CRDs" )
249
+ }
250
+
251
+ // Exclude CRDs of other providers.
252
+ for _ , crd := range crdList .Items {
253
+ if v , ok := crd .Labels [clusterv1 .ProviderLabelName ]; ok && v != providerName {
254
+ for _ , version := range crd .Spec .Versions {
255
+ crdsToExclude .Insert (metav1.GroupVersionKind {
256
+ Group : crd .Spec .Group ,
257
+ Version : version .Name ,
258
+ Kind : crd .Spec .Names .Kind ,
259
+ }.String ())
260
+ }
261
+ }
262
+ }
263
+ }
264
+
222
265
// Select resources with list and delete methods (list is required by this method, delete by the callers of this method)
223
266
resourceList = discovery .FilteredBy (discovery.SupportsAllVerbs {Verbs : []string {"list" , "delete" }}, resourceList )
224
267
@@ -231,6 +274,19 @@ func (k *proxy) ListResources(labels map[string]string, namespaces ...string) ([
231
274
continue
232
275
}
233
276
277
+ // Continue if the resource is an excluded CRD.
278
+ gv , err := schema .ParseGroupVersion (resourceGroup .GroupVersion )
279
+ if err != nil {
280
+ return nil , errors .Wrapf (err , "failed to parse GroupVersion" )
281
+ }
282
+ if crdsToExclude .Has (metav1.GroupVersionKind {
283
+ Group : gv .Group ,
284
+ Version : gv .Version ,
285
+ Kind : resourceKind .Kind ,
286
+ }.String ()) {
287
+ continue
288
+ }
289
+
234
290
// List all the object instances of this resourceKind with the given labels
235
291
if resourceKind .Namespaced {
236
292
for _ , namespace := range namespaces {
0 commit comments