mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-02-22 07:03:28 +00:00
Merge pull request #131616 from jpbetz/typeconverter-cleanup
Reorganize scheme type converter into apimachinery utils
This commit is contained in:
@@ -20,9 +20,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"k8s.io/kubernetes/pkg/generated/openapi"
|
||||
)
|
||||
@@ -38,7 +38,7 @@ func main() {
|
||||
|
||||
func output() error {
|
||||
refFunc := func(name string) spec.Ref {
|
||||
return spec.MustCreateRef(fmt.Sprintf("#/definitions/%s", friendlyName(name)))
|
||||
return spec.MustCreateRef(fmt.Sprintf("#/definitions/%s", util.ToRESTFriendlyName(name)))
|
||||
}
|
||||
defs := openapi.GetOpenAPIDefinitions(refFunc)
|
||||
schemaDefs := make(map[string]spec.Schema, len(defs))
|
||||
@@ -50,12 +50,12 @@ func output() error {
|
||||
// the type.
|
||||
if schema, ok := v.Schema.Extensions[common.ExtensionV2Schema]; ok {
|
||||
if v2Schema, isOpenAPISchema := schema.(spec.Schema); isOpenAPISchema {
|
||||
schemaDefs[friendlyName(k)] = v2Schema
|
||||
schemaDefs[util.ToRESTFriendlyName(k)] = v2Schema
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
schemaDefs[friendlyName(k)] = v.Schema
|
||||
schemaDefs[util.ToRESTFriendlyName(k)] = v.Schema
|
||||
}
|
||||
data, err := json.Marshal(&spec.Swagger{
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
@@ -75,17 +75,3 @@ func output() error {
|
||||
os.Stdout.Write(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// From k8s.io/apiserver/pkg/endpoints/openapi/openapi.go
|
||||
func friendlyName(name string) string {
|
||||
nameParts := strings.Split(name, "/")
|
||||
// Reverse first part. e.g., io.k8s... instead of k8s.io...
|
||||
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
|
||||
parts := strings.Split(nameParts[0], ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
nameParts[0] = strings.Join(parts, ".")
|
||||
}
|
||||
return strings.Join(nameParts, ".")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
internal "k8s.io/apiextensions-apiserver/examples/client-go/pkg/client/applyconfiguration/internal"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
testing "k8s.io/client-go/testing"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
)
|
||||
|
||||
// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no
|
||||
@@ -43,6 +43,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
internal "k8s.io/apiextensions-apiserver/pkg/client/applyconfiguration/internal"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
testing "k8s.io/client-go/testing"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
)
|
||||
|
||||
// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no
|
||||
@@ -111,6 +111,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
@@ -743,3 +743,67 @@ func (s *Scheme) Name() string {
|
||||
// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
|
||||
// call chains to NewReflector, so they'd be low entropy names for reflectors
|
||||
var internalPackages = []string{"k8s.io/apimachinery/pkg/runtime/scheme.go"}
|
||||
|
||||
// ToOpenAPIDefinitionName returns the REST-friendly OpenAPI definition name known type identified by groupVersionKind.
|
||||
// If the groupVersionKind does not identify a known type, an error is returned.
|
||||
// The Version field of groupVersionKind is required, and the Group and Kind fields are required for unstructured.Unstructured
|
||||
// types. If a required field is empty, an error is returned.
|
||||
//
|
||||
// The OpenAPI definition name is the canonical name of the type, with the group and version removed.
|
||||
// For example, the OpenAPI definition name of Pod is `io.k8s.api.core.v1.Pod`.
|
||||
//
|
||||
// A known type that is registered as an unstructured.Unstructured type is treated as a custom resource and
|
||||
// which has an OpenAPI definition name of the form `<reversed-group>.<version.<kind>`.
|
||||
// For example, the OpenAPI definition name of `group: stable.example.com, version: v1, kind: Pod` is
|
||||
// `com.example.stable.v1.Pod`.
|
||||
func (s *Scheme) ToOpenAPIDefinitionName(groupVersionKind schema.GroupVersionKind) (string, error) {
|
||||
if groupVersionKind.Version == "" { // Empty version is not allowed by New() so check it first to avoid a panic.
|
||||
return "", fmt.Errorf("version is required on all types: %v", groupVersionKind)
|
||||
}
|
||||
example, err := s.New(groupVersionKind)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, ok := example.(Unstructured); ok {
|
||||
if groupVersionKind.Group == "" || groupVersionKind.Kind == "" {
|
||||
return "", fmt.Errorf("unable to convert GroupVersionKind with empty fields to unstructured type to an OpenAPI definition name: %v", groupVersionKind)
|
||||
}
|
||||
return reverseParts(groupVersionKind.Group) + "." + groupVersionKind.Version + "." + groupVersionKind.Kind, nil
|
||||
}
|
||||
rtype := reflect.TypeOf(example).Elem()
|
||||
name := toOpenAPIDefinitionName(rtype.PkgPath() + "." + rtype.Name())
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// toOpenAPIDefinitionName converts Golang package/type canonical name into REST friendly OpenAPI name.
|
||||
// Input is expected to be `PkgPath + "." TypeName.
|
||||
//
|
||||
// Examples of REST friendly OpenAPI name:
|
||||
//
|
||||
// Input: k8s.io/api/core/v1.Pod
|
||||
// Output: io.k8s.api.core.v1.Pod
|
||||
//
|
||||
// Input: k8s.io/api/core/v1
|
||||
// Output: io.k8s.api.core.v1
|
||||
//
|
||||
// Input: csi.storage.k8s.io/v1alpha1.CSINodeInfo
|
||||
// Output: io.k8s.storage.csi.v1alpha1.CSINodeInfo
|
||||
//
|
||||
// Note that this is a copy of ToRESTFriendlyName from k8s.io/kube-openapi/pkg/util. It is duplicated here to avoid
|
||||
// a dependency on kube-openapi.
|
||||
func toOpenAPIDefinitionName(name string) string {
|
||||
nameParts := strings.Split(name, "/")
|
||||
// Reverse first part. e.g., io.k8s... instead of k8s.io...
|
||||
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
|
||||
nameParts[0] = reverseParts(nameParts[0])
|
||||
}
|
||||
return strings.Join(nameParts, ".")
|
||||
}
|
||||
|
||||
func reverseParts(dotSeparatedName string) string {
|
||||
parts := strings.Split(dotSeparatedName, ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
return strings.Join(parts, ".")
|
||||
}
|
||||
|
||||
@@ -27,11 +27,13 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/operation"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
runtimetesting "k8s.io/apimachinery/pkg/runtime/testing"
|
||||
runtimetestingv1 "k8s.io/apimachinery/pkg/runtime/testing/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
@@ -1114,3 +1116,72 @@ type TestType2 struct {
|
||||
func (TestType2) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
|
||||
func (TestType2) DeepCopyObject() runtime.Object { return nil }
|
||||
|
||||
func TestToOpenAPIDefinitionName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerGvk *schema.GroupVersionKind // defaults to gvk unless set
|
||||
registerObj runtime.Object
|
||||
gvk schema.GroupVersionKind
|
||||
out string
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "built-registerObj type",
|
||||
registerObj: &runtimetestingv1.ExternalSimple{},
|
||||
gvk: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Simple"},
|
||||
out: "io.k8s.apimachinery.pkg.runtime.testing.v1.ExternalSimple",
|
||||
},
|
||||
{
|
||||
name: "unstructured type",
|
||||
registerObj: &unstructured.Unstructured{},
|
||||
gvk: schema.GroupVersionKind{Group: "stable.example.com", Version: "v1", Kind: "CronTab"},
|
||||
out: "com.example.stable.v1.CronTab",
|
||||
},
|
||||
{
|
||||
name: "unregistered type: empty group",
|
||||
registerObj: &unstructured.Unstructured{},
|
||||
gvk: schema.GroupVersionKind{Version: "v1", Kind: "CronTab"},
|
||||
wantErr: fmt.Errorf("unable to convert GroupVersionKind with empty fields to unstructured type to an OpenAPI definition name: %v", schema.GroupVersionKind{Version: "v1", Kind: "CronTab"}),
|
||||
},
|
||||
{
|
||||
name: "unregistered type: empty version",
|
||||
registerObj: &unstructured.Unstructured{},
|
||||
registerGvk: &schema.GroupVersionKind{Group: "stable.example.com", Version: "v1", Kind: "CronTab"},
|
||||
gvk: schema.GroupVersionKind{Group: "stable.example.com", Kind: "CronTab"},
|
||||
wantErr: fmt.Errorf("version is required on all types: %v", schema.GroupVersionKind{Group: "stable.example.com", Kind: "CronTab"}),
|
||||
},
|
||||
{
|
||||
name: "unregistered type: empty kind",
|
||||
registerObj: &unstructured.Unstructured{},
|
||||
gvk: schema.GroupVersionKind{Group: "stable.example.com", Version: "v1"},
|
||||
wantErr: fmt.Errorf("unable to convert GroupVersionKind with empty fields to unstructured type to an OpenAPI definition name: %v", schema.GroupVersionKind{Group: "stable.example.com", Version: "v1"}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.registerGvk == nil {
|
||||
test.registerGvk = &test.gvk
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName(*test.registerGvk, test.registerObj)
|
||||
utilruntime.Must(runtimetesting.RegisterConversions(scheme))
|
||||
|
||||
out, err := scheme.ToOpenAPIDefinitionName(test.gvk)
|
||||
if test.wantErr != nil {
|
||||
if err == nil || err.Error() != test.wantErr.Error() {
|
||||
t.Errorf("expected error: %v but got %v", test.wantErr, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if out != test.out {
|
||||
t.Errorf("expected %s, got %s", test.out, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package v1
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type ExternalSimple struct {
|
||||
runtime.TypeMeta `json:",inline"`
|
||||
TestString string `json:"testString"`
|
||||
}
|
||||
51
staging/src/k8s.io/apimachinery/pkg/runtime/testing/v1/zz_generated.deepcopy.go
generated
Normal file
51
staging/src/k8s.io/apimachinery/pkg/runtime/testing/v1/zz_generated.deepcopy.go
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExternalSimple) DeepCopyInto(out *ExternalSimple) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalSimple.
|
||||
func (in *ExternalSimple) DeepCopy() *ExternalSimple {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExternalSimple)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ExternalSimple) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
)
|
||||
|
||||
type schemeTypeConverter struct {
|
||||
scheme *runtime.Scheme
|
||||
parser *typed.Parser
|
||||
}
|
||||
|
||||
var _ TypeConverter = &schemeTypeConverter{}
|
||||
|
||||
// NewSchemeTypeConverter creates a TypeConverter that uses the provided scheme to
|
||||
// convert between runtime.Objects and TypedValues.
|
||||
func NewSchemeTypeConverter(scheme *runtime.Scheme, parser *typed.Parser) TypeConverter {
|
||||
return &schemeTypeConverter{scheme: scheme, parser: parser}
|
||||
}
|
||||
|
||||
func (tc schemeTypeConverter) ObjectToTyped(obj runtime.Object, opts ...typed.ValidationOptions) (*typed.TypedValue, error) {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
name, err := tc.scheme.ToOpenAPIDefinitionName(gvk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := tc.parser.Type(name)
|
||||
switch o := obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return t.FromUnstructured(o.UnstructuredContent(), opts...)
|
||||
default:
|
||||
return t.FromStructured(obj, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
func (tc schemeTypeConverter) TypedToObject(value *typed.TypedValue) (runtime.Object, error) {
|
||||
vu := value.AsValue().Unstructured()
|
||||
switch o := vu.(type) {
|
||||
case map[string]interface{}:
|
||||
return &unstructured.Unstructured{Object: o}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("failed to convert value to unstructured for type %T", vu)
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@ limitations under the License.
|
||||
package managedfields
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/managedfields/internal"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
@@ -45,3 +48,9 @@ func NewDeducedTypeConverter() TypeConverter {
|
||||
func NewTypeConverter(openapiSpec map[string]*spec.Schema, preserveUnknownFields bool) (TypeConverter, error) {
|
||||
return internal.NewTypeConverter(openapiSpec, preserveUnknownFields)
|
||||
}
|
||||
|
||||
// NewSchemeTypeConverter creates a TypeConverter that uses the provided scheme to
|
||||
// convert between runtime.Objects and TypedValues.
|
||||
func NewSchemeTypeConverter(scheme *runtime.Scheme, parser *typed.Parser) TypeConverter {
|
||||
return internal.NewSchemeTypeConverter(scheme, parser)
|
||||
}
|
||||
|
||||
@@ -133,19 +133,6 @@ func gvkConvert(gvk schema.GroupVersionKind) v1.GroupVersionKind {
|
||||
}
|
||||
}
|
||||
|
||||
func friendlyName(name string) string {
|
||||
nameParts := strings.Split(name, "/")
|
||||
// Reverse first part. e.g., io.k8s... instead of k8s.io...
|
||||
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
|
||||
parts := strings.Split(nameParts[0], ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
nameParts[0] = strings.Join(parts, ".")
|
||||
}
|
||||
return strings.Join(nameParts, ".")
|
||||
}
|
||||
|
||||
func typeName(t reflect.Type) string {
|
||||
path := t.PkgPath()
|
||||
if strings.Contains(path, "/vendor/") {
|
||||
@@ -183,9 +170,9 @@ func NewDefinitionNamer(schemes ...*runtime.Scheme) *DefinitionNamer {
|
||||
// GetDefinitionName returns the name and tags for a given definition
|
||||
func (d *DefinitionNamer) GetDefinitionName(name string) (string, spec.Extensions) {
|
||||
if groupVersionKinds, ok := d.typeGroupVersionKinds[name]; ok {
|
||||
return friendlyName(name), spec.Extensions{
|
||||
return util.ToRESTFriendlyName(name), spec.Extensions{
|
||||
extensionGVK: groupVersionKinds.JSON(),
|
||||
}
|
||||
}
|
||||
return friendlyName(name), nil
|
||||
return util.ToRESTFriendlyName(name), nil
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
admissionregistrationv1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1"
|
||||
admissionregistrationv1alpha1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1"
|
||||
admissionregistrationv1beta1 "k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1"
|
||||
@@ -126,7 +127,6 @@ import (
|
||||
applyconfigurationsstoragev1alpha1 "k8s.io/client-go/applyconfigurations/storage/v1alpha1"
|
||||
applyconfigurationsstoragev1beta1 "k8s.io/client-go/applyconfigurations/storage/v1beta1"
|
||||
applyconfigurationsstoragemigrationv1alpha1 "k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no
|
||||
@@ -1941,6 +1941,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package testing
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
"sigs.k8s.io/yaml"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -945,62 +944,3 @@ func assertOptionalSingleArgument[T any](arguments []T) (T, error) {
|
||||
return a, fmt.Errorf("expected only one option argument but got %d", len(arguments))
|
||||
}
|
||||
}
|
||||
|
||||
type TypeResolver interface {
|
||||
Type(openAPIName string) typed.ParseableType
|
||||
}
|
||||
|
||||
type TypeConverter struct {
|
||||
Scheme *runtime.Scheme
|
||||
TypeResolver TypeResolver
|
||||
}
|
||||
|
||||
func (tc TypeConverter) ObjectToTyped(obj runtime.Object, opts ...typed.ValidationOptions) (*typed.TypedValue, error) {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
name, err := tc.openAPIName(gvk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := tc.TypeResolver.Type(name)
|
||||
switch o := obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return t.FromUnstructured(o.UnstructuredContent(), opts...)
|
||||
default:
|
||||
return t.FromStructured(obj, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
func (tc TypeConverter) TypedToObject(value *typed.TypedValue) (runtime.Object, error) {
|
||||
vu := value.AsValue().Unstructured()
|
||||
switch o := vu.(type) {
|
||||
case map[string]interface{}:
|
||||
return &unstructured.Unstructured{Object: o}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("failed to convert value to unstructured for type %T", vu)
|
||||
}
|
||||
}
|
||||
|
||||
func (tc TypeConverter) openAPIName(kind schema.GroupVersionKind) (string, error) {
|
||||
example, err := tc.Scheme.New(kind)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
rtype := reflect.TypeOf(example).Elem()
|
||||
name := friendlyName(rtype.PkgPath() + "." + rtype.Name())
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// This is a copy of openapi.friendlyName.
|
||||
// TODO: consider introducing a shared version of this function in apimachinery.
|
||||
func friendlyName(name string) string {
|
||||
nameParts := strings.Split(name, "/")
|
||||
// Reverse first part. e.g., io.k8s... instead of k8s.io...
|
||||
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
|
||||
parts := strings.Split(nameParts[0], ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
nameParts[0] = strings.Join(parts, ".")
|
||||
}
|
||||
return strings.Join(nameParts, ".")
|
||||
}
|
||||
|
||||
@@ -572,7 +572,7 @@ func configMapTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter
|
||||
panic(fmt.Sprintf("Failed to parse schema: %v", err))
|
||||
}
|
||||
|
||||
return TypeConverter{Scheme: scheme, TypeResolver: parser}
|
||||
return managedfields.NewSchemeTypeConverter(scheme, parser)
|
||||
}
|
||||
|
||||
var configMapTypedSchema = typed.YAMLObject(`types:
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
|
||||
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
|
||||
"k8s.io/gengo/v2/types"
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
utilproto "k8s.io/kube-openapi/pkg/util/proto"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
@@ -62,7 +63,7 @@ func newTypeModels(openAPISchemaFilePath string, pkgTypes map[string]*types.Pack
|
||||
tags := genclientTags(t)
|
||||
hasApply := tags.HasVerb("apply") || tags.HasVerb("applyStatus")
|
||||
if tags.GenerateClient && hasApply {
|
||||
openAPIType := friendlyName(typeName(t))
|
||||
openAPIType := util.ToRESTFriendlyName(typeName(t))
|
||||
gvk := gv.WithKind(clientgentypes.Kind(t.Name.Name))
|
||||
rootDefs[openAPIType] = openAPISchema.Definitions[openAPIType]
|
||||
gvkToOpenAPIType[gvk] = openAPIType
|
||||
|
||||
@@ -145,19 +145,6 @@ func GetTargets(context *generator.Context, args *args.Args) []generator.Target
|
||||
return targetList
|
||||
}
|
||||
|
||||
func friendlyName(name string) string {
|
||||
nameParts := strings.Split(name, "/")
|
||||
// Reverse first part. e.g., io.k8s... instead of k8s.io...
|
||||
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
|
||||
parts := strings.Split(nameParts[0], ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
nameParts[0] = strings.Join(parts, ".")
|
||||
}
|
||||
return strings.Join(nameParts, ".")
|
||||
}
|
||||
|
||||
func typeName(t *types.Type) string {
|
||||
typePackage := t.Name.Package
|
||||
return fmt.Sprintf("%s.%s", typePackage, t.Name.Name)
|
||||
|
||||
@@ -19,18 +19,19 @@ package generators
|
||||
import "k8s.io/gengo/v2/types"
|
||||
|
||||
var (
|
||||
fmtSprintf = types.Ref("fmt", "Sprintf")
|
||||
syncOnce = types.Ref("sync", "Once")
|
||||
applyConfiguration = types.Ref("k8s.io/apimachinery/pkg/runtime", "ApplyConfiguration")
|
||||
groupVersionKind = types.Ref("k8s.io/apimachinery/pkg/runtime/schema", "GroupVersionKind")
|
||||
typeMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "TypeMeta")
|
||||
objectMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "ObjectMeta")
|
||||
rawExtension = types.Ref("k8s.io/apimachinery/pkg/runtime", "RawExtension")
|
||||
unknown = types.Ref("k8s.io/apimachinery/pkg/runtime", "Unknown")
|
||||
extractInto = types.Ref("k8s.io/apimachinery/pkg/util/managedfields", "ExtractInto")
|
||||
runtimeScheme = types.Ref("k8s.io/apimachinery/pkg/runtime", "Scheme")
|
||||
smdNewParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "NewParser")
|
||||
smdParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "Parser")
|
||||
testingTypeConverter = types.Ref("k8s.io/client-go/testing", "TypeConverter")
|
||||
yamlObject = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "YAMLObject")
|
||||
fmtSprintf = types.Ref("fmt", "Sprintf")
|
||||
syncOnce = types.Ref("sync", "Once")
|
||||
applyConfiguration = types.Ref("k8s.io/apimachinery/pkg/runtime", "ApplyConfiguration")
|
||||
groupVersionKind = types.Ref("k8s.io/apimachinery/pkg/runtime/schema", "GroupVersionKind")
|
||||
typeMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "TypeMeta")
|
||||
objectMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "ObjectMeta")
|
||||
rawExtension = types.Ref("k8s.io/apimachinery/pkg/runtime", "RawExtension")
|
||||
unknown = types.Ref("k8s.io/apimachinery/pkg/runtime", "Unknown")
|
||||
extractInto = types.Ref("k8s.io/apimachinery/pkg/util/managedfields", "ExtractInto")
|
||||
typeConverter = types.Ref("k8s.io/apimachinery/pkg/util/managedfields", "TypeConverter")
|
||||
newSchemeTypeConverter = types.Ref("k8s.io/apimachinery/pkg/util/managedfields", "NewSchemeTypeConverter")
|
||||
runtimeScheme = types.Ref("k8s.io/apimachinery/pkg/runtime", "Scheme")
|
||||
smdNewParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "NewParser")
|
||||
smdParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "Parser")
|
||||
yamlObject = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "YAMLObject")
|
||||
)
|
||||
|
||||
@@ -142,17 +142,18 @@ func (g *utilGenerator) GenerateType(c *generator.Context, _ *types.Type, w io.W
|
||||
"runtimeScheme": runtimeScheme,
|
||||
"schemeGVs": schemeGVs,
|
||||
"schemaGroupVersionKind": groupVersionKind,
|
||||
"testingTypeConverter": testingTypeConverter,
|
||||
"typeConverter": typeConverter,
|
||||
"newSchemeTypeConverter": newSchemeTypeConverter,
|
||||
}
|
||||
sw.Do(forKindFunc, m)
|
||||
sw.Do(typeConverter, m)
|
||||
sw.Do(newTypeConverterFunc, m)
|
||||
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
var typeConverter = `
|
||||
func NewTypeConverter(scheme *{{.runtimeScheme|raw}}) *{{.testingTypeConverter|raw}} {
|
||||
return &{{.testingTypeConverter|raw}}{Scheme: scheme, TypeResolver: {{.internalParser|raw}}()}
|
||||
var newTypeConverterFunc = `
|
||||
func NewTypeConverter(scheme *{{.runtimeScheme|raw}}) {{.typeConverter|raw}} {
|
||||
return {{.newSchemeTypeConverter|raw}}(scheme, {{.internalParser|raw}}())
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ package applyconfiguration
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
testing "k8s.io/client-go/testing"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
v1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1"
|
||||
examplev1 "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/example/v1"
|
||||
internal "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/internal"
|
||||
@@ -45,6 +45,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ package applyconfiguration
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
testing "k8s.io/client-go/testing"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
v1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1"
|
||||
examplev1 "k8s.io/code-generator/examples/MixedCase/applyconfiguration/example/v1"
|
||||
internal "k8s.io/code-generator/examples/MixedCase/applyconfiguration/internal"
|
||||
@@ -45,6 +45,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ package applyconfiguration
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
testing "k8s.io/client-go/testing"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
v1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1"
|
||||
examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1"
|
||||
example2v1 "k8s.io/code-generator/examples/crd/apis/example2/v1"
|
||||
@@ -73,6 +73,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ package applyconfiguration
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
testing "k8s.io/client-go/testing"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
v1 "k8s.io/code-generator/examples/single/api/v1"
|
||||
apiv1 "k8s.io/code-generator/examples/single/applyconfiguration/api/v1"
|
||||
internal "k8s.io/code-generator/examples/single/applyconfiguration/internal"
|
||||
@@ -45,6 +45,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ package applyconfiguration
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
testing "k8s.io/client-go/testing"
|
||||
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
|
||||
v1alpha1 "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
|
||||
v1beta1 "k8s.io/sample-apiserver/pkg/apis/wardle/v1beta1"
|
||||
internal "k8s.io/sample-apiserver/pkg/generated/applyconfiguration/internal"
|
||||
@@ -51,6 +51,6 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter {
|
||||
return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()}
|
||||
func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {
|
||||
return managedfields.NewSchemeTypeConverter(scheme, internal.Parser())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user