Skip to content

Commit

Permalink
backport clusterctl discovery fix
Browse files Browse the repository at this point in the history
This patch was originally introduced in PR kubernetes-sigs#5684.
Original name: "clusterctl discovery should ignore provider's resources"
Original commit id: db5b183

Original description:

While managing components (for cert-manager or providers) clusterctl
implements a discovery function to seek for all the objects
part of the component.

This commit makes this code to ignore resources for a provider
(e.g Cluster for CAPI, AWSCluster for CAPA, Certificates for cert-manager)
given that those resources are not part of the component itself.

This will make operations like upgrade plan or apply and delete resilient to actual
state of cert-manager web hooks; in fact, those operations can now work when
web-hooks are not functioning (due to provider's deployment already deleted,
to provider scaled down to 0, to other errors)

This commit also introduces some logic originally implemented in commit
f5a9d76 that implements the ability to skip excluded CRD during
resource listing.

Reason for backporting:

The issues that were solved by commit db5b183 and f5a9d76  on the main
branch are also effecting older releases of CAPI currently in use thus backporting
the "discovery fix" and some related code from f5a9d76 would solve a lot of issue
faced by users e.g related to upgrade process as mentioned in the original db5b183 commit.
  • Loading branch information
fabriziopandini authored and Rozzii committed Nov 24, 2021
1 parent 75ddb72 commit 1a9e86f
Showing 1 changed file with 48 additions and 0 deletions.
48 changes: 48 additions & 0 deletions cmd/clusterctl/client/cluster/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ import (
"time"

"github.com/pkg/errors"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
utilversion "k8s.io/apimachinery/pkg/util/version"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4"
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme"
"sigs.k8s.io/cluster-api/version"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -150,6 +155,12 @@ func (k *proxy) NewClient() (client.Client, error) {
return c, nil
}

// ListResources lists namespaced and cluster-wide resources for a component matching the labels. Namespaced resources are only listed
// in the given namespaces.
// Please note that we are not returning resources for the component's CRD (e.g. we are not returning
// Certificates for cert-manager, Clusters for CAPI, AWSCluster for CAPA and so on).
// This is done to avoid errors when listing resources of providers which have already been deleted/scaled down to 0 replicas/with
// malfunctioning webhooks.
func (k *proxy) ListResources(labels map[string]string, namespaces ...string) ([]unstructured.Unstructured, error) {
cs, err := k.newClientSet()
if err != nil {
Expand All @@ -171,6 +182,30 @@ func (k *proxy) ListResources(labels map[string]string, namespaces ...string) ([
return nil, errors.Wrap(err, "failed to list api resources")
}

// Exclude from discovery the objects from the cert-manager/provider's CRDs.
// Those objects are not part of the components, and they will eventually be removed when removing the CRD definition.
crdsToExclude := sets.String{}

crdList := &apiextensionsv1.CustomResourceDefinitionList{}
if err := retryWithExponentialBackoff(newReadBackoff(), func() error {
return c.List(ctx, crdList)
}); err != nil {
return nil, errors.Wrap(err, "failed to list CRDs")
}
for _, crd := range crdList.Items {
component, isCoreComponent := labels[clusterctlv1.ClusterctlCoreLabelName]
_, isProviderResource := crd.Labels[clusterv1.ProviderLabelName]
if (isCoreComponent && component == clusterctlv1.ClusterctlCoreLabelCertManagerValue) || isProviderResource {
for _, version := range crd.Spec.Versions {
crdsToExclude.Insert(metav1.GroupVersionKind{
Group: crd.Spec.Group,
Version: version.Name,
Kind: crd.Spec.Names.Kind,
}.String())
}
}
}

// Select resources with list and delete methods (list is required by this method, delete by the callers of this method)
resourceList = discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"list", "delete"}}, resourceList)

Expand All @@ -183,6 +218,19 @@ func (k *proxy) ListResources(labels map[string]string, namespaces ...string) ([
continue
}

// Continue if the resource is an excluded CRD.
gv, err := schema.ParseGroupVersion(resourceGroup.GroupVersion)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse GroupVersion")
}
if crdsToExclude.Has(metav1.GroupVersionKind{
Group: gv.Group,
Version: gv.Version,
Kind: resourceKind.Kind,
}.String()) {
continue
}

// List all the object instances of this resourceKind with the given labels
if resourceKind.Namespaced {
for _, namespace := range namespaces {
Expand Down

0 comments on commit 1a9e86f

Please sign in to comment.