From e3196143e8e3cb9340da4a27e1ca07020395e391 Mon Sep 17 00:00:00 2001 From: Mikhail Mazurskiy Date: Fri, 19 Aug 2022 21:18:52 +1000 Subject: [PATCH] Use own scheme rather than mutating a global shared one Signed-off-by: Mikhail Mazurskiy --- pkg/chartutil/capabilities.go | 13 ++----------- pkg/kube/client.go | 17 +---------------- pkg/kube/converter.go | 20 +++++++++++++------- pkg/kube/ready.go | 5 ++--- 4 files changed, 18 insertions(+), 37 deletions(-) diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index 5f57e11a5..7879b52a9 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -20,12 +20,9 @@ import ( "strconv" "github.com/Masterminds/semver/v3" - "k8s.io/client-go/kubernetes/scheme" - - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" helmversion "helm.sh/helm/v3/internal/version" + "helm.sh/helm/v3/pkg/kube" ) var ( @@ -111,13 +108,7 @@ func (v VersionSet) Has(apiVersion string) bool { } func allKnownVersions() VersionSet { - // We should register the built in extension APIs as well so CRDs are - // supported in the default version set. This has caused problems with `helm - // template` in the past, so let's be safe - apiextensionsv1beta1.AddToScheme(scheme.Scheme) - apiextensionsv1.AddToScheme(scheme.Scheme) - - groups := scheme.Scheme.PrioritizedVersionsAllGroups() + groups := kube.NativeScheme().PrioritizedVersionsAllGroups() vs := make(VersionSet, 0, len(groups)) for _, gv := range groups { vs = append(vs, gv.String()) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 1ab59f25d..aa4182151 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -30,14 +30,12 @@ import ( "time" jsonpatch "github.com/evanphx/json-patch" + multierror "github.com/hashicorp/go-multierror" "github.com/pkg/errors" batch "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" - apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" - - multierror "github.com/hashicorp/go-multierror" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -51,7 +49,6 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" cachetools "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" @@ -77,23 +74,11 @@ type Client struct { kubeClient *kubernetes.Clientset } -var addToScheme sync.Once - // New creates a new Client. func New(getter genericclioptions.RESTClientGetter) *Client { if getter == nil { getter = genericclioptions.NewConfigFlags(true) } - // Add CRDs to the scheme. They are missing by default. - addToScheme.Do(func() { - if err := apiextv1.AddToScheme(scheme.Scheme); err != nil { - // This should never happen. - panic(err) - } - if err := apiextv1beta1.AddToScheme(scheme.Scheme); err != nil { - panic(err) - } - }) return &Client{ Factory: cmdutil.NewFactory(getter), Log: nopLogger, diff --git a/pkg/kube/converter.go b/pkg/kube/converter.go index 3bf0e358c..90e57aac2 100644 --- a/pkg/kube/converter.go +++ b/pkg/kube/converter.go @@ -40,30 +40,36 @@ func AsVersioned(info *resource.Info) runtime.Object { // convertWithMapper converts the given object with the optional provided // RESTMapping. If no mapping is provided, the default schema versioner is used func convertWithMapper(obj runtime.Object, mapping *meta.RESTMapping) runtime.Object { - s := kubernetesNativeScheme() + s := NativeScheme() var gv = runtime.GroupVersioner(schema.GroupVersions(s.PrioritizedVersionsAllGroups())) if mapping != nil { gv = mapping.GroupVersionKind.GroupVersion() } - if obj, err := runtime.ObjectConvertor(s).ConvertToVersion(obj, gv); err == nil { + if obj, err := s.ConvertToVersion(obj, gv); err == nil { return obj } return obj } -// kubernetesNativeScheme returns a clean *runtime.Scheme with _only_ Kubernetes +// NativeScheme returns a clean *runtime.Scheme with _only_ Kubernetes // native resources added to it. This is required to break free of custom resources // that may have been added to scheme.Scheme due to Helm being used as a package in // combination with e.g. a versioned kube client. If we would not do this, the client // may attempt to perform e.g. a 3-way-merge strategy patch for custom resources. -func kubernetesNativeScheme() *runtime.Scheme { +func NativeScheme() *runtime.Scheme { k8sNativeSchemeOnce.Do(func() { k8sNativeScheme = runtime.NewScheme() - scheme.AddToScheme(k8sNativeScheme) + if err := scheme.AddToScheme(k8sNativeScheme); err != nil { + panic(err) + } // API extensions are not in the above scheme set, // and must thus be added separately. - apiextensionsv1beta1.AddToScheme(k8sNativeScheme) - apiextensionsv1.AddToScheme(k8sNativeScheme) + if err := apiextensionsv1beta1.AddToScheme(k8sNativeScheme); err != nil { + panic(err) + } + if err := apiextensionsv1.AddToScheme(k8sNativeScheme); err != nil { + panic(err) + } }) return k8sNativeScheme } diff --git a/pkg/kube/ready.go b/pkg/kube/ready.go index bdad3af08..95b497ffe 100644 --- a/pkg/kube/ready.go +++ b/pkg/kube/ready.go @@ -32,7 +32,6 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" deploymentutil "helm.sh/helm/v3/internal/third_party/k8s.io/kubernetes/deployment/util" ) @@ -155,7 +154,7 @@ func (c *ReadyChecker) IsReady(ctx context.Context, v *resource.Info) (bool, err return false, err } crd := &apiextv1beta1.CustomResourceDefinition{} - if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil { + if err := NativeScheme().Convert(v.Object, crd, nil); err != nil { return false, err } if !c.crdBetaReady(*crd) { @@ -166,7 +165,7 @@ func (c *ReadyChecker) IsReady(ctx context.Context, v *resource.Info) (bool, err return false, err } crd := &apiextv1.CustomResourceDefinition{} - if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil { + if err := NativeScheme().Convert(v.Object, crd, nil); err != nil { return false, err } if !c.crdReady(*crd) {