mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-30 15:02:23 +00:00
Merge pull request #25018 from smarterclayton/fast_conversion
Automatic merge from submit-queue Reduce allocations during conversion, enable new UnsafeConvertToVersion path Cleans up the conversion path to avoid a few unnecessary allocations, then creates a new UnsafeConvertToVersion path that will allow encode/decode to bypass copying the object for performance. In that subsequent PR, ConvertToVersion will start to call Copy() and we will refactor conversions to reuse as much of the existing object as possible. Also changes the unversioned.ObjectKind signature to not require allocations - speeds up a few common paths.
This commit is contained in:
commit
5c30f983d9
@ -50,11 +50,11 @@ func BenchmarkPodConversion(b *testing.B) {
|
||||
var result *api.Pod
|
||||
for i := 0; i < b.N; i++ {
|
||||
pod := &items[i%width]
|
||||
versionedObj, err := scheme.ConvertToVersion(pod, testapi.Default.GroupVersion().String())
|
||||
versionedObj, err := scheme.UnsafeConvertToVersion(pod, *testapi.Default.GroupVersion())
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String())
|
||||
obj, err := scheme.UnsafeConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion())
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
@ -76,11 +76,11 @@ func BenchmarkNodeConversion(b *testing.B) {
|
||||
scheme := api.Scheme
|
||||
var result *api.Node
|
||||
for i := 0; i < b.N; i++ {
|
||||
versionedObj, err := scheme.ConvertToVersion(&node, testapi.Default.GroupVersion().String())
|
||||
versionedObj, err := scheme.UnsafeConvertToVersion(&node, *testapi.Default.GroupVersion())
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String())
|
||||
obj, err := scheme.UnsafeConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion())
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
@ -104,11 +104,11 @@ func BenchmarkReplicationControllerConversion(b *testing.B) {
|
||||
scheme := api.Scheme
|
||||
var result *api.ReplicationController
|
||||
for i := 0; i < b.N; i++ {
|
||||
versionedObj, err := scheme.ConvertToVersion(&replicationController, testapi.Default.GroupVersion().String())
|
||||
versionedObj, err := scheme.UnsafeConvertToVersion(&replicationController, *testapi.Default.GroupVersion())
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String())
|
||||
obj, err := scheme.UnsafeConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion())
|
||||
if err != nil {
|
||||
b.Fatalf("Conversion error: %v", err)
|
||||
}
|
||||
|
@ -123,33 +123,21 @@ type objectAccessor struct {
|
||||
}
|
||||
|
||||
func (obj objectAccessor) GetKind() string {
|
||||
if gvk := obj.GetObjectKind().GroupVersionKind(); gvk != nil {
|
||||
return gvk.Kind
|
||||
}
|
||||
return ""
|
||||
return obj.GetObjectKind().GroupVersionKind().Kind
|
||||
}
|
||||
|
||||
func (obj objectAccessor) SetKind(kind string) {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
if gvk == nil {
|
||||
gvk = &unversioned.GroupVersionKind{}
|
||||
}
|
||||
gvk.Kind = kind
|
||||
obj.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
}
|
||||
|
||||
func (obj objectAccessor) GetAPIVersion() string {
|
||||
if gvk := obj.GetObjectKind().GroupVersionKind(); gvk != nil {
|
||||
return gvk.GroupVersion().String()
|
||||
}
|
||||
return ""
|
||||
return obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
|
||||
}
|
||||
|
||||
func (obj objectAccessor) SetAPIVersion(version string) {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
if gvk == nil {
|
||||
gvk = &unversioned.GroupVersionKind{}
|
||||
}
|
||||
gv, err := unversioned.ParseGroupVersion(version)
|
||||
if err != nil {
|
||||
gv = unversioned.GroupVersion{Version: version}
|
||||
|
@ -253,10 +253,10 @@ type InternalObject struct {
|
||||
}
|
||||
|
||||
func (obj *InternalObject) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *InternalObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *InternalObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *InternalObject) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *InternalObject) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
|
||||
}
|
||||
|
||||
@ -610,10 +610,10 @@ type MyAPIObject struct {
|
||||
}
|
||||
|
||||
func (obj *MyAPIObject) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *MyAPIObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *MyAPIObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *MyAPIObject) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *MyAPIObject) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ func (fakeConvertor) Convert(in, out interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ string) (runtime.Object, error) {
|
||||
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ unversioned.GroupVersion) (runtime.Object, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
|
@ -54,10 +54,7 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) {
|
||||
|
||||
// if the object referenced is actually persisted, we can just get kind from meta
|
||||
// if we are building an object reference to something not yet persisted, we should fallback to scheme
|
||||
var kind string
|
||||
if gvk != nil {
|
||||
kind = gvk.Kind
|
||||
}
|
||||
kind := gvk.Kind
|
||||
if len(kind) == 0 {
|
||||
// TODO: this is wrong
|
||||
gvk, err := Scheme.ObjectKind(obj)
|
||||
@ -68,10 +65,7 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) {
|
||||
}
|
||||
|
||||
// if the object referenced is actually persisted, we can also get version from meta
|
||||
var version string
|
||||
if gvk != nil {
|
||||
version = gvk.GroupVersion().String()
|
||||
}
|
||||
version := gvk.GroupVersion().String()
|
||||
if len(version) == 0 {
|
||||
selfLink := meta.GetSelfLink()
|
||||
if len(selfLink) == 0 {
|
||||
@ -111,9 +105,9 @@ func GetPartialReference(obj runtime.Object, fieldPath string) (*ObjectReference
|
||||
|
||||
// IsAnAPIObject allows clients to preemptively get a reference to an API object and pass it to places that
|
||||
// intend only to get a reference to that object. This simplifies the event recording interface.
|
||||
func (obj *ObjectReference) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *ObjectReference) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *ObjectReference) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *ObjectReference) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ func TestObjectWatchFraming(t *testing.T) {
|
||||
secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00}
|
||||
secret.Data["utf8"] = []byte("a string with \u0345 characters")
|
||||
secret.Data["long"] = bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x00}, 1000)
|
||||
converted, _ := api.Scheme.ConvertToVersion(secret, "v1")
|
||||
converted, _ := api.Scheme.ConvertToVersion(secret, v1.SchemeGroupVersion)
|
||||
v1secret := converted.(*v1.Secret)
|
||||
for _, streamingMediaType := range api.Codecs.SupportedStreamingMediaTypes() {
|
||||
s, _ := api.Codecs.StreamingSerializerForMediaType(streamingMediaType, nil)
|
||||
@ -358,7 +358,7 @@ func benchmarkItems() []v1.Pod {
|
||||
for i := range items {
|
||||
var pod api.Pod
|
||||
apiObjectFuzzer.Fuzz(&pod)
|
||||
out, err := api.Scheme.ConvertToVersion(&pod, "v1")
|
||||
out, err := api.Scheme.ConvertToVersion(&pod, v1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -259,11 +259,11 @@ func (gvk *GroupVersionKind) ToAPIVersionAndKind() (string, string) {
|
||||
// do not use TypeMeta. This method exists to support test types and legacy serializations
|
||||
// that have a distinct group and kind.
|
||||
// TODO: further reduce usage of this method.
|
||||
func FromAPIVersionAndKind(apiVersion, kind string) *GroupVersionKind {
|
||||
func FromAPIVersionAndKind(apiVersion, kind string) GroupVersionKind {
|
||||
if gv, err := ParseGroupVersion(apiVersion); err == nil {
|
||||
return &GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
|
||||
return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
|
||||
}
|
||||
return &GroupVersionKind{Kind: kind}
|
||||
return GroupVersionKind{Kind: kind}
|
||||
}
|
||||
|
||||
// All objects that are serialized from a Scheme encode their type information. This interface is used
|
||||
@ -273,10 +273,10 @@ func FromAPIVersionAndKind(apiVersion, kind string) *GroupVersionKind {
|
||||
type ObjectKind interface {
|
||||
// SetGroupVersionKind sets or clears the intended serialized kind of an object. Passing kind nil
|
||||
// should clear the current setting.
|
||||
SetGroupVersionKind(kind *GroupVersionKind)
|
||||
SetGroupVersionKind(kind GroupVersionKind)
|
||||
// GroupVersionKind returns the stored group, version, and kind of an object, or nil if the object does
|
||||
// not expose or provide these fields.
|
||||
GroupVersionKind() *GroupVersionKind
|
||||
GroupVersionKind() GroupVersionKind
|
||||
}
|
||||
|
||||
// EmptyObjectKind implements the ObjectKind interface as a noop
|
||||
@ -286,7 +286,7 @@ var EmptyObjectKind = emptyObjectKind{}
|
||||
type emptyObjectKind struct{}
|
||||
|
||||
// SetGroupVersionKind implements the ObjectKind interface
|
||||
func (emptyObjectKind) SetGroupVersionKind(gvk *GroupVersionKind) {}
|
||||
func (emptyObjectKind) SetGroupVersionKind(gvk GroupVersionKind) {}
|
||||
|
||||
// GroupVersionKind implements the ObjectKind interface
|
||||
func (emptyObjectKind) GroupVersionKind() *GroupVersionKind { return nil }
|
||||
func (emptyObjectKind) GroupVersionKind() GroupVersionKind { return GroupVersionKind{} }
|
||||
|
@ -25,12 +25,12 @@ func Kind(kind string) GroupKind {
|
||||
}
|
||||
|
||||
// SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
|
||||
func (obj *TypeMeta) SetGroupVersionKind(gvk *GroupVersionKind) {
|
||||
func (obj *TypeMeta) SetGroupVersionKind(gvk GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
|
||||
// GroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
|
||||
func (obj *TypeMeta) GroupVersionKind() *GroupVersionKind {
|
||||
func (obj *TypeMeta) GroupVersionKind() GroupVersionKind {
|
||||
return FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ func validateOwnerReference(ownerReference api.OwnerReference, fldPath *field.Pa
|
||||
if len(ownerReference.UID) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), ownerReference.UID, "uid must not be empty"))
|
||||
}
|
||||
if _, ok := BannedOwners[*gvk]; ok {
|
||||
if _, ok := BannedOwners[gvk]; ok {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, ownerReference, fmt.Sprintf("%s is disallowed from being an owner", gvk)))
|
||||
}
|
||||
return allErrs
|
||||
|
@ -264,7 +264,7 @@ func (c stripVersionEncoder) EncodeToStream(obj runtime.Object, w io.Writer, ove
|
||||
}
|
||||
gvk.Group = ""
|
||||
gvk.Version = ""
|
||||
roundTrippedObj.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
roundTrippedObj.GetObjectKind().SetGroupVersionKind(*gvk)
|
||||
return c.serializer.EncodeToStream(roundTrippedObj, w)
|
||||
}
|
||||
|
||||
|
@ -459,7 +459,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, typer runtime.ObjectTyper
|
||||
ctx := scope.ContextFunc(req)
|
||||
ctx = api.WithNamespace(ctx, namespace)
|
||||
|
||||
versionedObj, err := converter.ConvertToVersion(r.New(), scope.Kind.GroupVersion().String())
|
||||
versionedObj, err := converter.ConvertToVersion(r.New(), scope.Kind.GroupVersion())
|
||||
if err != nil {
|
||||
scope.err(err, res.ResponseWriter, req.Request)
|
||||
return
|
||||
|
@ -174,7 +174,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
||||
|
||||
namer := &testNamer{namespace, name}
|
||||
|
||||
versionedObj, err := api.Scheme.ConvertToVersion(&api.Pod{}, "v1")
|
||||
versionedObj, err := api.Scheme.ConvertToVersion(&api.Pod{}, unversioned.GroupVersion{Version: "v1"})
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||
return
|
||||
|
@ -35,9 +35,9 @@ func init() {
|
||||
}
|
||||
|
||||
func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *Config) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *Config) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *Config) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *Config) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ func init() {
|
||||
}
|
||||
|
||||
func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *Config) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *Config) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *Config) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *Config) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
|
@ -210,9 +210,6 @@ func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
|
||||
|
||||
// Meta is supplied by Scheme, when it calls Convert.
|
||||
type Meta struct {
|
||||
SrcVersion string
|
||||
DestVersion string
|
||||
|
||||
// KeyNameMapping is an optional function which may map the listed key (field name)
|
||||
// into a source and destination value.
|
||||
KeyNameMapping FieldMappingFunc
|
||||
|
@ -611,7 +611,7 @@ func TestConverter_meta(t *testing.T) {
|
||||
checks := 0
|
||||
err := c.RegisterConversionFunc(
|
||||
func(in *Foo, out *Bar, s Scope) error {
|
||||
if s.Meta() == nil || s.Meta().SrcVersion != "test" || s.Meta().DestVersion != "passes" {
|
||||
if s.Meta() == nil {
|
||||
t.Errorf("Meta did not get passed!")
|
||||
}
|
||||
checks++
|
||||
@ -624,7 +624,7 @@ func TestConverter_meta(t *testing.T) {
|
||||
}
|
||||
err = c.RegisterConversionFunc(
|
||||
func(in *string, out *string, s Scope) error {
|
||||
if s.Meta() == nil || s.Meta().SrcVersion != "test" || s.Meta().DestVersion != "passes" {
|
||||
if s.Meta() == nil {
|
||||
t.Errorf("Meta did not get passed a second time!")
|
||||
}
|
||||
checks++
|
||||
@ -634,7 +634,7 @@ func TestConverter_meta(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{SrcVersion: "test", DestVersion: "passes"})
|
||||
err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
@ -174,8 +174,6 @@ func DeepCopy_conversion_Equalities(in Equalities, out *Equalities, c *Cloner) e
|
||||
}
|
||||
|
||||
func DeepCopy_conversion_Meta(in Meta, out *Meta, c *Cloner) error {
|
||||
out.SrcVersion = in.SrcVersion
|
||||
out.DestVersion = in.DestVersion
|
||||
if in.KeyNameMapping == nil {
|
||||
out.KeyNameMapping = nil
|
||||
} else if newVal, err := c.DeepCopy(in.KeyNameMapping); err != nil {
|
||||
|
@ -221,7 +221,7 @@ func (o AnnotateOptions) RunAnnotate() error {
|
||||
return err
|
||||
}
|
||||
|
||||
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion().String())
|
||||
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -87,24 +87,24 @@ type ExternalType2 struct {
|
||||
}
|
||||
|
||||
func (obj *internalType) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *internalType) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *internalType) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *internalType) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *internalType) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
func (obj *externalType) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *externalType) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *externalType) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *externalType) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *externalType) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
func (obj *ExternalType2) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *ExternalType2) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *ExternalType2) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *ExternalType2) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *ExternalType2) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ func (o *ConvertOptions) RunConvert() error {
|
||||
}
|
||||
|
||||
infos := []*resource.Info{info}
|
||||
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String(), o.encoder)
|
||||
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion, o.encoder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ func RunEdit(f *cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objs, err := resource.AsVersionedObjects(infos, defaultVersion.String(), encoder)
|
||||
objs, err := resource.AsVersionedObjects(infos, defaultVersion, encoder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj, err := resource.AsVersionedObject(infos, !singular, version.String(), f.JSONEncoder())
|
||||
obj, err := resource.AsVersionedObject(infos, !singular, version, f.JSONEncoder())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -273,7 +273,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
|
||||
}
|
||||
|
||||
for ix := range infos {
|
||||
objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version.String())
|
||||
objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
continue
|
||||
|
@ -246,7 +246,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
||||
}
|
||||
outputObj = info.Object
|
||||
} else {
|
||||
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion().String())
|
||||
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ func (r *Result) Watch(resourceVersion string) (watch.Interface, error) {
|
||||
// the objects as children, or if only a single Object is present, as that object. The provided
|
||||
// version will be preferred as the conversion target, but the Object's mapping version will be
|
||||
// used if that version is not present.
|
||||
func AsVersionedObject(infos []*Info, forceList bool, version string, encoder runtime.Encoder) (runtime.Object, error) {
|
||||
func AsVersionedObject(infos []*Info, forceList bool, version unversioned.GroupVersion, encoder runtime.Encoder) (runtime.Object, error) {
|
||||
objects, err := AsVersionedObjects(infos, version, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -222,7 +222,7 @@ func AsVersionedObject(infos []*Info, forceList bool, version string, encoder ru
|
||||
object = objects[0]
|
||||
} else {
|
||||
object = &api.List{Items: objects}
|
||||
converted, err := tryConvert(api.Scheme, object, version, registered.GroupOrDie(api.GroupName).GroupVersion.Version)
|
||||
converted, err := tryConvert(api.Scheme, object, version, registered.GroupOrDie(api.GroupName).GroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -234,7 +234,7 @@ func AsVersionedObject(infos []*Info, forceList bool, version string, encoder ru
|
||||
// AsVersionedObjects converts a list of infos into versioned objects. The provided
|
||||
// version will be preferred as the conversion target, but the Object's mapping version will be
|
||||
// used if that version is not present.
|
||||
func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder) ([]runtime.Object, error) {
|
||||
func AsVersionedObjects(infos []*Info, version unversioned.GroupVersion, encoder runtime.Encoder) ([]runtime.Object, error) {
|
||||
objects := []runtime.Object{}
|
||||
for _, info := range infos {
|
||||
if info.Object == nil {
|
||||
@ -250,7 +250,7 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder)
|
||||
|
||||
// objects that are not part of api.Scheme must be converted to JSON
|
||||
// TODO: convert to map[string]interface{}, attach to runtime.Unknown?
|
||||
if len(version) > 0 {
|
||||
if !version.IsEmpty() {
|
||||
if _, err := api.Scheme.ObjectKind(info.Object); runtime.IsNotRegisteredError(err) {
|
||||
// TODO: ideally this would encode to version, but we don't expose multiple codecs here.
|
||||
data, err := runtime.Encode(encoder, info.Object)
|
||||
@ -263,7 +263,7 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder)
|
||||
}
|
||||
}
|
||||
|
||||
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.GroupVersionKind.GroupVersion().String())
|
||||
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -274,10 +274,10 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder)
|
||||
|
||||
// tryConvert attempts to convert the given object to the provided versions in order. This function assumes
|
||||
// the object is in internal version.
|
||||
func tryConvert(convertor runtime.ObjectConvertor, object runtime.Object, versions ...string) (runtime.Object, error) {
|
||||
func tryConvert(convertor runtime.ObjectConvertor, object runtime.Object, versions ...unversioned.GroupVersion) (runtime.Object, error) {
|
||||
var last error
|
||||
for _, version := range versions {
|
||||
if len(version) == 0 {
|
||||
if version.IsEmpty() {
|
||||
return object, nil
|
||||
}
|
||||
obj, err := convertor.ConvertToVersion(object, version)
|
||||
|
@ -182,7 +182,7 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
|
||||
if version.IsEmpty() {
|
||||
continue
|
||||
}
|
||||
converted, err := p.convertor.ConvertToVersion(obj, version.String())
|
||||
converted, err := p.convertor.ConvertToVersion(obj, version)
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
continue
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func TestPrinter(t *testing.T) {
|
||||
},
|
||||
}
|
||||
emptyListTest := &api.PodList{}
|
||||
testapi, err := api.Scheme.ConvertToVersion(podTest, testapi.Default.GroupVersion().String())
|
||||
testapi, err := api.Scheme.ConvertToVersion(podTest, *testapi.Default.GroupVersion())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ type thirdPartyObjectConverter struct {
|
||||
converter runtime.ObjectConvertor
|
||||
}
|
||||
|
||||
func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersion string) (out runtime.Object, err error) {
|
||||
func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersion unversioned.GroupVersion) (out runtime.Object, err error) {
|
||||
switch in.(type) {
|
||||
// This seems weird, but in this case the ThirdPartyResourceData is really just a wrapper on the raw 3rd party data.
|
||||
// The actual thing printed/sent to server is the actual raw third party resource data, which only has one version.
|
||||
|
@ -162,7 +162,7 @@ func (c *parameterCodec) EncodeParameters(obj Object, to unversioned.GroupVersio
|
||||
return nil, err
|
||||
}
|
||||
if to != gvk.GroupVersion() {
|
||||
out, err := c.convertor.ConvertToVersion(obj, to.String())
|
||||
out, err := c.convertor.ConvertToVersion(obj, to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -43,10 +43,31 @@ func (t objectTyperToTyper) ObjectKind(obj Object) (*unversioned.GroupVersionKin
|
||||
return &gvk, unversionedType, nil
|
||||
}
|
||||
|
||||
// ObjectTyperToTyper casts the old typer interface to the new typer interface
|
||||
func ObjectTyperToTyper(typer ObjectTyper) Typer {
|
||||
return objectTyperToTyper{typer: typer}
|
||||
}
|
||||
|
||||
// unsafeObjectConvertor implements ObjectConvertor using the unsafe conversion path.
|
||||
type unsafeObjectConvertor struct {
|
||||
*Scheme
|
||||
}
|
||||
|
||||
var _ ObjectConvertor = unsafeObjectConvertor{}
|
||||
|
||||
// ConvertToVersion converts in to the provided outVersion without copying the input first, which
|
||||
// is only safe if the output object is not mutated or reused.
|
||||
func (c unsafeObjectConvertor) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
|
||||
return c.Scheme.UnsafeConvertToVersion(in, outVersion)
|
||||
}
|
||||
|
||||
// UnsafeObjectConvertor performs object conversion without copying the object structure,
|
||||
// for use when the converted object will not be reused or mutated. Primarily for use within
|
||||
// versioned codecs, which use the external object for serialization but do not return it.
|
||||
func UnsafeObjectConvertor(scheme *Scheme) ObjectConvertor {
|
||||
return unsafeObjectConvertor{scheme}
|
||||
}
|
||||
|
||||
// fieldPtr puts the address of fieldName, which must be a member of v,
|
||||
// into dest, which must be an address of a variable to which this field's
|
||||
// address can be assigned.
|
||||
|
@ -161,7 +161,7 @@ type StorageSerializer interface {
|
||||
// Non-codec interfaces
|
||||
|
||||
type ObjectVersioner interface {
|
||||
ConvertToVersion(in Object, outVersion string) (out Object, err error)
|
||||
ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (out Object, err error)
|
||||
}
|
||||
|
||||
// ObjectConvertor converts an object to a different version.
|
||||
@ -171,7 +171,7 @@ type ObjectConvertor interface {
|
||||
Convert(in, out interface{}) error
|
||||
// ConvertToVersion takes the provided object and converts it the provided version. This
|
||||
// method does not guarantee that the in object is not mutated.
|
||||
ConvertToVersion(in Object, outVersion string) (out Object, err error)
|
||||
ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (out Object, err error)
|
||||
ConvertFieldLabel(version, kind, label, value string) (string, string, error)
|
||||
}
|
||||
|
||||
|
@ -21,12 +21,12 @@ import (
|
||||
)
|
||||
|
||||
// SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
|
||||
func (obj *TypeMeta) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *TypeMeta) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
|
||||
// GroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
|
||||
func (obj *TypeMeta) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *TypeMeta) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
|
||||
|
@ -124,11 +124,8 @@ func (s *Scheme) nameFunc(t reflect.Type) string {
|
||||
|
||||
// fromScope gets the input version, desired output version, and desired Scheme
|
||||
// from a conversion.Scope.
|
||||
func (s *Scheme) fromScope(scope conversion.Scope) (inVersion, outVersion string, scheme *Scheme) {
|
||||
scheme = s
|
||||
inVersion = scope.Meta().SrcVersion
|
||||
outVersion = scope.Meta().DestVersion
|
||||
return inVersion, outVersion, scheme
|
||||
func (s *Scheme) fromScope(scope conversion.Scope) *Scheme {
|
||||
return s
|
||||
}
|
||||
|
||||
// Converter allows access to the converter for the scheme
|
||||
@ -476,16 +473,12 @@ func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string,
|
||||
// contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
|
||||
// return an error if the conversion does not result in a valid Object being
|
||||
// returned. The serializer handles loading/serializing nested objects.
|
||||
func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error) {
|
||||
gv, err := unversioned.ParseGroupVersion(outVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (s *Scheme) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
|
||||
switch in.(type) {
|
||||
case *Unknown, *Unstructured, *UnstructuredList:
|
||||
old := in.GetObjectKind().GroupVersionKind()
|
||||
defer in.GetObjectKind().SetGroupVersionKind(old)
|
||||
setTargetVersion(in, s, gv)
|
||||
setTargetVersion(in, s, outVersion)
|
||||
return in, nil
|
||||
}
|
||||
t := reflect.TypeOf(in)
|
||||
@ -509,7 +502,7 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error)
|
||||
kind = kinds[0]
|
||||
}
|
||||
|
||||
outKind := gv.WithKind(kind.Kind)
|
||||
outKind := outVersion.WithKind(kind.Kind)
|
||||
|
||||
inKind, err := s.ObjectKind(in)
|
||||
if err != nil {
|
||||
@ -521,29 +514,106 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flags, meta := s.generateConvertMeta(inKind.GroupVersion(), gv, in)
|
||||
flags, meta := s.generateConvertMeta(inKind.GroupVersion(), outVersion, in)
|
||||
if err := s.converter.Convert(in, out, flags, meta); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setTargetVersion(out, s, gv)
|
||||
setTargetVersion(out, s, outVersion)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// UnsafeConvertToVersion will convert in to the provided outVersion if such a conversion is possible,
|
||||
// but does not guarantee the output object does not share fields with the input object. It attempts to be as
|
||||
// efficient as possible when doing conversion.
|
||||
func (s *Scheme) UnsafeConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
|
||||
switch t := in.(type) {
|
||||
case *Unknown:
|
||||
t.APIVersion = outVersion.String()
|
||||
return t, nil
|
||||
case *Unstructured:
|
||||
t.SetAPIVersion(outVersion.String())
|
||||
return t, nil
|
||||
case *UnstructuredList:
|
||||
t.SetAPIVersion(outVersion.String())
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// determine the incoming kinds with as few allocations as possible.
|
||||
t := reflect.TypeOf(in)
|
||||
if t.Kind() != reflect.Ptr {
|
||||
return nil, fmt.Errorf("only pointer types may be converted: %v", t)
|
||||
}
|
||||
t = t.Elem()
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
|
||||
}
|
||||
kinds, ok := s.typeToGVK[t]
|
||||
if !ok || len(kinds) == 0 {
|
||||
return nil, fmt.Errorf("%v is not a registered type and cannot be converted into version %q", t, outVersion)
|
||||
}
|
||||
|
||||
// if the Go type is also registered to the destination kind, no conversion is necessary
|
||||
for i := range kinds {
|
||||
if kinds[i].Version == outVersion.Version && kinds[i].Group == outVersion.Group {
|
||||
setTargetKind(in, kinds[i])
|
||||
return in, nil
|
||||
}
|
||||
}
|
||||
|
||||
// type is unversioned, no conversion necessary
|
||||
// it should be possible to avoid this allocation
|
||||
if unversionedKind, ok := s.unversionedTypes[t]; ok {
|
||||
kind := unversionedKind
|
||||
outKind := outVersion.WithKind(kind.Kind)
|
||||
setTargetKind(in, outKind)
|
||||
return in, nil
|
||||
}
|
||||
|
||||
// allocate a new object as the target using the target kind
|
||||
// TODO: this should look in the target group version and find the first kind that matches, rather than the
|
||||
// first kind registered in typeToGVK
|
||||
kind := kinds[0]
|
||||
kind.Version = outVersion.Version
|
||||
kind.Group = outVersion.Group
|
||||
out, err := s.New(kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: try to avoid the allocations here - in fast paths we are not likely to need these flags or meta
|
||||
flags, meta := s.converter.DefaultMeta(t)
|
||||
if err := s.converter.Convert(in, out, flags, meta); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setTargetKind(out, kind)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// generateConvertMeta constructs the meta value we pass to Convert.
|
||||
func (s *Scheme) generateConvertMeta(srcGroupVersion, destGroupVersion unversioned.GroupVersion, in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) {
|
||||
flags, meta := s.converter.DefaultMeta(reflect.TypeOf(in))
|
||||
meta.SrcVersion = srcGroupVersion.String()
|
||||
meta.DestVersion = destGroupVersion.String()
|
||||
return flags, meta
|
||||
return s.converter.DefaultMeta(reflect.TypeOf(in))
|
||||
}
|
||||
|
||||
// setTargetVersion is deprecated and should be replaced by use of setTargetKind
|
||||
func setTargetVersion(obj Object, raw *Scheme, gv unversioned.GroupVersion) {
|
||||
if gv.Version == APIVersionInternal {
|
||||
// internal is a special case
|
||||
obj.GetObjectKind().SetGroupVersionKind(nil)
|
||||
} else {
|
||||
gvk, _ := raw.ObjectKind(obj)
|
||||
obj.GetObjectKind().SetGroupVersionKind(&unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvk.Kind})
|
||||
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{})
|
||||
return
|
||||
}
|
||||
gvk, _ := raw.ObjectKind(obj)
|
||||
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvk.Kind})
|
||||
}
|
||||
|
||||
// setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.
|
||||
func setTargetKind(obj Object, kind unversioned.GroupVersionKind) {
|
||||
if kind.Version == APIVersionInternal {
|
||||
// internal is a special case
|
||||
// TODO: look at removing the need to special case this
|
||||
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{})
|
||||
return
|
||||
}
|
||||
obj.GetObjectKind().SetGroupVersionKind(kind)
|
||||
}
|
||||
|
@ -65,24 +65,12 @@ func TestScheme(t *testing.T) {
|
||||
// Register functions to verify that scope.Meta() gets set correctly.
|
||||
err := scheme.AddConversionFuncs(
|
||||
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
|
||||
if e, a := internalGV.String(), scope.Meta().SrcVersion; e != a {
|
||||
t.Errorf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
if e, a := externalGV.String(), scope.Meta().DestVersion; e != a {
|
||||
t.Errorf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
internalToExternalCalls++
|
||||
return nil
|
||||
},
|
||||
func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error {
|
||||
if e, a := externalGV.String(), scope.Meta().SrcVersion; e != a {
|
||||
t.Errorf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
if e, a := internalGV.String(), scope.Meta().DestVersion; e != a {
|
||||
t.Errorf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
externalToInternalCalls++
|
||||
@ -472,10 +460,10 @@ type ExternalInternalSame struct {
|
||||
}
|
||||
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind)
|
||||
}
|
||||
|
||||
@ -542,7 +530,7 @@ func TestKnownTypes(t *testing.T) {
|
||||
func TestConvertToVersion(t *testing.T) {
|
||||
s := GetTestScheme()
|
||||
tt := &TestType1{A: "I'm not a pointer object"}
|
||||
other, err := s.ConvertToVersion(tt, "v1")
|
||||
other, err := s.ConvertToVersion(tt, unversioned.GroupVersion{Version: "v1"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failure: %v", err)
|
||||
}
|
||||
@ -570,24 +558,12 @@ func TestMetaValues(t *testing.T) {
|
||||
err := s.AddConversionFuncs(
|
||||
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
|
||||
t.Logf("internal -> external")
|
||||
if e, a := internalGV.String(), scope.Meta().SrcVersion; e != a {
|
||||
t.Fatalf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
if e, a := externalGV.String(), scope.Meta().DestVersion; e != a {
|
||||
t.Fatalf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
internalToExternalCalls++
|
||||
return nil
|
||||
},
|
||||
func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error {
|
||||
t.Logf("external -> internal")
|
||||
if e, a := externalGV.String(), scope.Meta().SrcVersion; e != a {
|
||||
t.Errorf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
if e, a := internalGV.String(), scope.Meta().DestVersion; e != a {
|
||||
t.Fatalf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
externalToInternalCalls++
|
||||
return nil
|
||||
@ -602,12 +578,12 @@ func TestMetaValues(t *testing.T) {
|
||||
|
||||
s.Log(t)
|
||||
|
||||
out, err := s.ConvertToVersion(simple, externalGV.String())
|
||||
out, err := s.ConvertToVersion(simple, externalGV)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
internal, err := s.ConvertToVersion(out, internalGV.String())
|
||||
internal, err := s.ConvertToVersion(out, internalGV)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@ -643,12 +619,6 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
|
||||
// Register functions to verify that scope.Meta() gets set correctly.
|
||||
err := s.AddConversionFuncs(
|
||||
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
|
||||
if e, a := "unknown/unknown", scope.Meta().SrcVersion; e != a {
|
||||
t.Fatalf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
if e, a := "unknown/unknown", scope.Meta().DestVersion; e != a {
|
||||
t.Fatalf("Expected '%v', got '%v'", e, a)
|
||||
}
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
internalToExternalCalls++
|
||||
return nil
|
||||
|
@ -129,10 +129,10 @@ var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
|
||||
)
|
||||
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind)
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
|
||||
if unk, ok := into.(*runtime.Unknown); ok && unk != nil {
|
||||
unk.Raw = originalData
|
||||
unk.ContentType = runtime.ContentTypeJSON
|
||||
unk.GetObjectKind().SetGroupVersionKind(actual)
|
||||
unk.GetObjectKind().SetGroupVersionKind(*actual)
|
||||
return unk, actual, nil
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,12 @@ import (
|
||||
type testDecodable struct {
|
||||
Other string
|
||||
Value int `json:"value"`
|
||||
gvk *unversioned.GroupVersionKind
|
||||
gvk unversioned.GroupVersionKind
|
||||
}
|
||||
|
||||
func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
|
||||
func (d *testDecodable) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { d.gvk = gvk }
|
||||
func (d *testDecodable) GroupVersionKind() *unversioned.GroupVersionKind { return d.gvk }
|
||||
func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
|
||||
func (d *testDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
|
||||
func (d *testDecodable) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
testCases := []struct {
|
||||
@ -76,34 +76,28 @@ func TestDecode(t *testing.T) {
|
||||
errFn: func(err error) bool { return err.Error() == "fake error" },
|
||||
},
|
||||
{
|
||||
data: []byte("{}"),
|
||||
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{
|
||||
gvk: nil, // json serializer does NOT set GVK
|
||||
},
|
||||
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
data: []byte("{}"),
|
||||
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{},
|
||||
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
},
|
||||
|
||||
// version without group is not defaulted
|
||||
{
|
||||
data: []byte(`{"apiVersion":"blah"}`),
|
||||
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{
|
||||
gvk: nil, // json serializer does NOT set GVK
|
||||
},
|
||||
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
|
||||
data: []byte(`{"apiVersion":"blah"}`),
|
||||
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{},
|
||||
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
|
||||
},
|
||||
// group without version is defaulted
|
||||
{
|
||||
data: []byte(`{"apiVersion":"other/"}`),
|
||||
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{
|
||||
gvk: nil, // json serializer does NOT set GVK
|
||||
},
|
||||
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
data: []byte(`{"apiVersion":"other/"}`),
|
||||
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{},
|
||||
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
},
|
||||
|
||||
// accept runtime.Unknown as into and bypass creator
|
||||
|
@ -120,14 +120,14 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
|
||||
}
|
||||
|
||||
actual := unk.GroupVersionKind()
|
||||
copyKindDefaults(actual, gvk)
|
||||
copyKindDefaults(&actual, gvk)
|
||||
|
||||
if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil {
|
||||
*intoUnknown = unk
|
||||
if len(intoUnknown.ContentType) == 0 {
|
||||
intoUnknown.ContentType = s.contentType
|
||||
}
|
||||
return intoUnknown, actual, nil
|
||||
return intoUnknown, &actual, nil
|
||||
}
|
||||
|
||||
if into != nil {
|
||||
@ -136,16 +136,16 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
|
||||
case runtime.IsNotRegisteredError(err):
|
||||
pb, ok := into.(proto.Message)
|
||||
if !ok {
|
||||
return nil, actual, errNotMarshalable{reflect.TypeOf(into)}
|
||||
return nil, &actual, errNotMarshalable{reflect.TypeOf(into)}
|
||||
}
|
||||
if err := proto.Unmarshal(unk.Raw, pb); err != nil {
|
||||
return nil, actual, err
|
||||
return nil, &actual, err
|
||||
}
|
||||
return into, actual, nil
|
||||
return into, &actual, nil
|
||||
case err != nil:
|
||||
return nil, actual, err
|
||||
return nil, &actual, err
|
||||
default:
|
||||
copyKindDefaults(actual, typed)
|
||||
copyKindDefaults(&actual, typed)
|
||||
// if the result of defaulting did not set a version or group, ensure that at least group is set
|
||||
// (copyKindDefaults will not assign Group if version is already set). This guarantees that the group
|
||||
// of into is set if there is no better information from the caller or object.
|
||||
@ -156,25 +156,24 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
|
||||
}
|
||||
|
||||
if len(actual.Kind) == 0 {
|
||||
return nil, actual, runtime.NewMissingKindErr(fmt.Sprintf("%#v", unk.TypeMeta))
|
||||
return nil, &actual, runtime.NewMissingKindErr(fmt.Sprintf("%#v", unk.TypeMeta))
|
||||
}
|
||||
if len(actual.Version) == 0 {
|
||||
return nil, actual, runtime.NewMissingVersionErr(fmt.Sprintf("%#v", unk.TypeMeta))
|
||||
return nil, &actual, runtime.NewMissingVersionErr(fmt.Sprintf("%#v", unk.TypeMeta))
|
||||
}
|
||||
|
||||
return unmarshalToObject(s.typer, s.creater, actual, into, unk.Raw)
|
||||
return unmarshalToObject(s.typer, s.creater, &actual, into, unk.Raw)
|
||||
}
|
||||
|
||||
// EncodeToStream serializes the provided object to the given writer. Overrides is ignored.
|
||||
func (s *Serializer) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unversioned.GroupVersion) error {
|
||||
var unk runtime.Unknown
|
||||
if kind := obj.GetObjectKind().GroupVersionKind(); kind != nil {
|
||||
unk = runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{
|
||||
Kind: kind.Kind,
|
||||
APIVersion: kind.GroupVersion().String(),
|
||||
},
|
||||
}
|
||||
kind := obj.GetObjectKind().GroupVersionKind()
|
||||
unk = runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{
|
||||
Kind: kind.Kind,
|
||||
APIVersion: kind.GroupVersion().String(),
|
||||
},
|
||||
}
|
||||
|
||||
prefixSize := uint64(len(s.prefix))
|
||||
@ -334,7 +333,7 @@ func (s *RawSerializer) Decode(originalData []byte, gvk *unversioned.GroupVersio
|
||||
intoUnknown.Raw = data
|
||||
intoUnknown.ContentEncoding = ""
|
||||
intoUnknown.ContentType = s.contentType
|
||||
intoUnknown.SetGroupVersionKind(actual)
|
||||
intoUnknown.SetGroupVersionKind(*actual)
|
||||
return intoUnknown, actual, nil
|
||||
}
|
||||
|
||||
|
@ -34,12 +34,12 @@ import (
|
||||
)
|
||||
|
||||
type testObject struct {
|
||||
gvk *unversioned.GroupVersionKind
|
||||
gvk unversioned.GroupVersionKind
|
||||
}
|
||||
|
||||
func (d *testObject) GetObjectKind() unversioned.ObjectKind { return d }
|
||||
func (d *testObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { d.gvk = gvk }
|
||||
func (d *testObject) GroupVersionKind() *unversioned.GroupVersionKind { return d.gvk }
|
||||
func (d *testObject) GetObjectKind() unversioned.ObjectKind { return d }
|
||||
func (d *testObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
|
||||
func (d *testObject) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
|
||||
|
||||
type testMarshalable struct {
|
||||
testObject
|
||||
@ -106,7 +106,7 @@ func TestEncode(t *testing.T) {
|
||||
0x22, 0x00, // content-encoding
|
||||
}
|
||||
obj2 := &testMarshalable{
|
||||
testObject: testObject{gvk: &unversioned.GroupVersionKind{Kind: "test", Group: "other", Version: "version"}},
|
||||
testObject: testObject{gvk: unversioned.GroupVersionKind{Kind: "test", Group: "other", Version: "version"}},
|
||||
data: []byte{0x01, 0x02, 0x03},
|
||||
}
|
||||
wire2 := []byte{
|
||||
|
@ -71,7 +71,7 @@ func NewCodecForScheme(
|
||||
encodeVersion []unversioned.GroupVersion,
|
||||
decodeVersion []unversioned.GroupVersion,
|
||||
) runtime.Codec {
|
||||
return NewCodec(encoder, decoder, scheme, scheme, scheme, runtime.ObjectTyperToTyper(scheme), encodeVersion, decodeVersion)
|
||||
return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, runtime.ObjectTyperToTyper(scheme), encodeVersion, decodeVersion)
|
||||
}
|
||||
|
||||
// NewCodec takes objects in their internal versions and converts them to external versions before
|
||||
@ -204,7 +204,7 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
|
||||
}
|
||||
|
||||
// Convert if needed.
|
||||
out, err := c.convertor.ConvertToVersion(obj, targetGV.String())
|
||||
out, err := c.convertor.ConvertToVersion(obj, targetGV)
|
||||
if err != nil {
|
||||
return nil, gvk, err
|
||||
}
|
||||
@ -227,10 +227,12 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv
|
||||
}
|
||||
|
||||
if (c.encodeVersion == nil && len(overrides) == 0) || isUnversioned {
|
||||
old := obj.GetObjectKind().GroupVersionKind()
|
||||
obj.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
defer obj.GetObjectKind().SetGroupVersionKind(old)
|
||||
return c.encoder.EncodeToStream(obj, w, overrides...)
|
||||
objectKind := obj.GetObjectKind()
|
||||
old := objectKind.GroupVersionKind()
|
||||
objectKind.SetGroupVersionKind(*gvk)
|
||||
err = c.encoder.EncodeToStream(obj, w, overrides...)
|
||||
objectKind.SetGroupVersionKind(old)
|
||||
return err
|
||||
}
|
||||
|
||||
targetGV, ok := c.encodeVersion[gvk.Group]
|
||||
@ -261,22 +263,21 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv
|
||||
}
|
||||
|
||||
// Perform a conversion if necessary
|
||||
if gvk.GroupVersion() != targetGV {
|
||||
out, err := c.convertor.ConvertToVersion(obj, targetGV.String())
|
||||
if err != nil {
|
||||
if ok {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
obj = out
|
||||
objectKind := obj.GetObjectKind()
|
||||
old := objectKind.GroupVersionKind()
|
||||
out, err := c.convertor.ConvertToVersion(obj, targetGV)
|
||||
if err != nil {
|
||||
if ok {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
old := obj.GetObjectKind().GroupVersionKind()
|
||||
defer obj.GetObjectKind().SetGroupVersionKind(old)
|
||||
obj.GetObjectKind().SetGroupVersionKind(&unversioned.GroupVersionKind{Group: targetGV.Group, Version: targetGV.Version, Kind: gvk.Kind})
|
||||
obj = out
|
||||
}
|
||||
|
||||
return c.encoder.EncodeToStream(obj, w, overrides...)
|
||||
// Conversion is responsible for setting the proper group, version, and kind onto the outgoing object
|
||||
err = c.encoder.EncodeToStream(obj, w, overrides...)
|
||||
// restore the old GVK, in case conversion returned the same object
|
||||
objectKind.SetGroupVersionKind(old)
|
||||
return err
|
||||
}
|
||||
|
||||
// promoteOrPrependGroupVersion finds the group version in the provided group versions that has the same group as target.
|
||||
|
@ -30,12 +30,12 @@ import (
|
||||
type testDecodable struct {
|
||||
Other string
|
||||
Value int `json:"value"`
|
||||
gvk *unversioned.GroupVersionKind
|
||||
gvk unversioned.GroupVersionKind
|
||||
}
|
||||
|
||||
func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
|
||||
func (d *testDecodable) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { d.gvk = gvk }
|
||||
func (d *testDecodable) GroupVersionKind() *unversioned.GroupVersionKind { return d.gvk }
|
||||
func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
|
||||
func (d *testDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
|
||||
func (d *testDecodable) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
gvk1 := &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}
|
||||
@ -65,12 +65,12 @@ func TestDecode(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
serializer: &mockSerializer{actual: gvk1},
|
||||
convertor: &checkConvertor{groupVersion: "other/__internal"},
|
||||
convertor: &checkConvertor{groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
|
||||
expectedGVK: gvk1,
|
||||
},
|
||||
{
|
||||
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
|
||||
expectedGVK: gvk1,
|
||||
sameObject: decodable2,
|
||||
},
|
||||
@ -78,7 +78,7 @@ func TestDecode(t *testing.T) {
|
||||
{
|
||||
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
|
||||
defaultGVK: &unversioned.GroupVersionKind{Group: "force"},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "force/__internal"},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "force", Version: "__internal"}},
|
||||
expectedGVK: gvk1,
|
||||
sameObject: decodable2,
|
||||
},
|
||||
@ -118,7 +118,7 @@ func TestDecode(t *testing.T) {
|
||||
|
||||
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
|
||||
copier: &checkCopy{in: decodable1, obj: decodable1},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
|
||||
expectedGVK: gvk1,
|
||||
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
|
||||
},
|
||||
@ -127,7 +127,7 @@ func TestDecode(t *testing.T) {
|
||||
|
||||
serializer: &mockSerializer{actual: gvk1, obj: decodable1},
|
||||
copier: &checkCopy{in: decodable1, obj: nil, err: fmt.Errorf("error on copy")},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"},
|
||||
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
|
||||
expectedGVK: gvk1,
|
||||
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
|
||||
},
|
||||
@ -228,7 +228,7 @@ func (c *checkCopy) Copy(obj runtime.Object) (runtime.Object, error) {
|
||||
type checkConvertor struct {
|
||||
err error
|
||||
in, obj runtime.Object
|
||||
groupVersion string
|
||||
groupVersion unversioned.GroupVersion
|
||||
directConvert bool
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ func (c *checkConvertor) Convert(in, out interface{}) error {
|
||||
}
|
||||
return c.err
|
||||
}
|
||||
func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion string) (out runtime.Object, err error) {
|
||||
func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion unversioned.GroupVersion) (out runtime.Object, err error) {
|
||||
if c.directConvert {
|
||||
return nil, fmt.Errorf("unexpected call to ConvertToVersion")
|
||||
}
|
||||
|
@ -301,18 +301,18 @@ func (u *Unstructured) SetAnnotations(annotations map[string]string) {
|
||||
u.setNestedMap(annotations, "metadata", "annotations")
|
||||
}
|
||||
|
||||
func (u *Unstructured) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (u *Unstructured) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
u.SetAPIVersion(gvk.GroupVersion().String())
|
||||
u.SetKind(gvk.Kind)
|
||||
}
|
||||
|
||||
func (u *Unstructured) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (u *Unstructured) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion())
|
||||
if err != nil {
|
||||
return nil
|
||||
return unversioned.GroupVersionKind{}
|
||||
}
|
||||
gvk := gv.WithKind(u.GetKind())
|
||||
return &gvk
|
||||
return gvk
|
||||
}
|
||||
|
||||
// UnstructuredList allows lists that do not have Golang structs
|
||||
@ -364,18 +364,18 @@ func (u *UnstructuredList) SetSelfLink(selfLink string) {
|
||||
u.setNestedField(selfLink, "metadata", "selfLink")
|
||||
}
|
||||
|
||||
func (u *UnstructuredList) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||
func (u *UnstructuredList) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
|
||||
u.SetAPIVersion(gvk.GroupVersion().String())
|
||||
u.SetKind(gvk.Kind)
|
||||
}
|
||||
|
||||
func (u *UnstructuredList) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||
func (u *UnstructuredList) GroupVersionKind() unversioned.GroupVersionKind {
|
||||
gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion())
|
||||
if err != nil {
|
||||
return nil
|
||||
return unversioned.GroupVersionKind{}
|
||||
}
|
||||
gvk := gv.WithKind(u.GetKind())
|
||||
return &gvk
|
||||
return gvk
|
||||
}
|
||||
|
||||
// VersionedObjects is used by Decoders to give callers a way to access all versions
|
||||
|
@ -45,10 +45,10 @@ func (s unstructuredJSONScheme) Decode(data []byte, _ *unversioned.GroupVersionK
|
||||
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
if len(gvk.Kind) == 0 {
|
||||
return nil, gvk, NewMissingKindErr(string(data))
|
||||
return nil, &gvk, NewMissingKindErr(string(data))
|
||||
}
|
||||
|
||||
return obj, gvk, nil
|
||||
return obj, &gvk, nil
|
||||
}
|
||||
|
||||
func (unstructuredJSONScheme) EncodeToStream(obj Object, w io.Writer, overrides ...unversioned.GroupVersion) error {
|
||||
|
Loading…
Reference in New Issue
Block a user