Use own scheme rather than mutating a global shared one

Signed-off-by: Mikhail Mazurskiy <mmazurskiy@gitlab.com>
pull/11250/head
Mikhail Mazurskiy 3 months ago
parent 5534c01cdb
commit 515bab1c87
No known key found for this signature in database
GPG Key ID: 36AD574291509DB7

@ -20,13 +20,10 @@ import (
"slices"
"strconv"
"k8s.io/client-go/kubernetes/scheme"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
k8sversion "k8s.io/apimachinery/pkg/util/version"
helmversion "helm.sh/helm/v4/internal/version"
"helm.sh/helm/v4/pkg/kube"
)
var (
@ -109,13 +106,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())

@ -33,7 +33,6 @@ import (
jsonpatch "github.com/evanphx/json-patch/v5"
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"
"k8s.io/apimachinery/pkg/runtime"
@ -52,7 +51,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"
"k8s.io/client-go/util/csaupgrade"
"k8s.io/client-go/util/retry"
@ -102,17 +100,6 @@ const (
FieldValidationDirectiveStrict FieldValidationDirective = "Strict"
)
func init() {
// Add CRDs to the scheme. They are missing by default.
if err := apiextv1.AddToScheme(scheme.Scheme); err != nil {
// This should never happen.
panic(err)
}
if err := apiextv1beta1.AddToScheme(scheme.Scheme); err != nil {
panic(err)
}
}
func (c *Client) newStatusWatcher() (*statusWaiter, error) {
cfg, err := c.Factory.ToRESTConfig()
if err != nil {

@ -17,8 +17,6 @@ limitations under the License.
package kube // import "helm.sh/helm/v4/pkg/kube"
import (
"sync"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/api/meta"
@ -28,8 +26,28 @@ import (
"k8s.io/client-go/kubernetes/scheme"
)
var k8sNativeScheme *runtime.Scheme
var k8sNativeSchemeOnce sync.Once
// NativeScheme is 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.
// DO NOT MUTATE, this is a shared variable.
var NativeScheme *runtime.Scheme
func init() {
NativeScheme = runtime.NewScheme()
if err := scheme.AddToScheme(NativeScheme); err != nil {
panic(err)
}
// API extensions are not in the above scheme set,
// and must thus be added separately.
if err := apiextensionsv1beta1.AddToScheme(NativeScheme); err != nil {
panic(err)
}
if err := apiextensionsv1.AddToScheme(NativeScheme); err != nil {
panic(err)
}
}
// AsVersioned converts the given info into a runtime.Object with the correct
// group and version set
@ -40,30 +58,12 @@ 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()
var gv = runtime.GroupVersioner(schema.GroupVersions(s.PrioritizedVersionsAllGroups()))
var gv = runtime.GroupVersioner(schema.GroupVersions(NativeScheme.PrioritizedVersionsAllGroups()))
if mapping != nil {
gv = mapping.GroupVersionKind.GroupVersion()
}
if obj, err := runtime.ObjectConvertor(s).ConvertToVersion(obj, gv); err == nil {
if obj, err := NativeScheme.ConvertToVersion(obj, gv); err == nil {
return obj
}
return obj
}
// kubernetesNativeScheme 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 {
k8sNativeSchemeOnce.Do(func() {
k8sNativeScheme = runtime.NewScheme()
scheme.AddToScheme(k8sNativeScheme)
// API extensions are not in the above scheme set,
// and must thus be added separately.
apiextensionsv1beta1.AddToScheme(k8sNativeScheme)
apiextensionsv1.AddToScheme(k8sNativeScheme)
})
return k8sNativeScheme
}

@ -31,7 +31,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/v4/internal/third_party/k8s.io/kubernetes/deployment/util"
)
@ -144,7 +143,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) {
@ -155,7 +154,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) {

Loading…
Cancel
Save