mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #26044 from smarterclayton/multiversion_encode
Automatic merge from submit-queue Guarantee that Encode handles nested objects again
This commit is contained in:
		@@ -50,7 +50,7 @@ type ProxyServerConfig struct {
 | 
			
		||||
 | 
			
		||||
func NewProxyConfig() *ProxyServerConfig {
 | 
			
		||||
	config := componentconfig.KubeProxyConfiguration{}
 | 
			
		||||
	api.Scheme.Convert(&v1alpha1.KubeProxyConfiguration{}, &config)
 | 
			
		||||
	api.Scheme.Convert(&v1alpha1.KubeProxyConfiguration{}, &config, nil)
 | 
			
		||||
	return &ProxyServerConfig{
 | 
			
		||||
		KubeProxyConfiguration: config,
 | 
			
		||||
		ContentType:            "application/vnd.kubernetes.protobuf",
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ type KubeletServer struct {
 | 
			
		||||
// NewKubeletServer will create a new KubeletServer with default values.
 | 
			
		||||
func NewKubeletServer() *KubeletServer {
 | 
			
		||||
	config := componentconfig.KubeletConfiguration{}
 | 
			
		||||
	api.Scheme.Convert(&v1alpha1.KubeletConfiguration{}, &config)
 | 
			
		||||
	api.Scheme.Convert(&v1alpha1.KubeletConfiguration{}, &config, nil)
 | 
			
		||||
	return &KubeletServer{
 | 
			
		||||
		AuthPath:             util.NewStringFlag("/var/lib/kubelet/kubernetes_auth"), // deprecated
 | 
			
		||||
		KubeConfig:           util.NewStringFlag("/var/lib/kubelet/kubeconfig"),
 | 
			
		||||
 
 | 
			
		||||
@@ -28,11 +28,11 @@ import (
 | 
			
		||||
 | 
			
		||||
type fakeConvertor struct{}
 | 
			
		||||
 | 
			
		||||
func (fakeConvertor) Convert(in, out interface{}) error {
 | 
			
		||||
func (fakeConvertor) Convert(in, out, context interface{}) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ unversioned.GroupVersion) (runtime.Object, error) {
 | 
			
		||||
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ runtime.GroupVersioner) (runtime.Object, error) {
 | 
			
		||||
	return in, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -106,7 +106,7 @@ func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) {
 | 
			
		||||
	width := len(items)
 | 
			
		||||
	encodable := make([]api.Pod, width)
 | 
			
		||||
	for i := range items {
 | 
			
		||||
		if err := api.Scheme.Convert(&items[i], &encodable[i]); err != nil {
 | 
			
		||||
		if err := api.Scheme.Convert(&items[i], &encodable[i], nil); err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,6 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/conversion"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime/serializer/streaming"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime/serializer/versioning"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/diff"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/sets"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/watch"
 | 
			
		||||
@@ -93,7 +92,11 @@ func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) {
 | 
			
		||||
	name := reflect.TypeOf(item).Elem().Name()
 | 
			
		||||
	data, err := runtime.Encode(codec, item)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", item))
 | 
			
		||||
		if runtime.IsNotRegisteredError(err) {
 | 
			
		||||
			t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", item))
 | 
			
		||||
		} else {
 | 
			
		||||
			t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", item))
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -181,10 +184,14 @@ func TestSetControllerConversion(t *testing.T) {
 | 
			
		||||
		t.Fatalf("unexpected encoding error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	decoder := api.Codecs.UniversalDecoder(*extGroup.GroupVersion(), *defaultGroup.GroupVersion())
 | 
			
		||||
	if err := versioning.EnableCrossGroupDecoding(decoder, extGroup.GroupVersion().Group, defaultGroup.GroupVersion().Group); err != nil {
 | 
			
		||||
		t.Fatalf("unexpected error while enabling cross-group decoding: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	decoder := api.Codecs.DecoderToVersion(
 | 
			
		||||
		api.Codecs.UniversalDeserializer(),
 | 
			
		||||
		runtime.NewMultiGroupVersioner(
 | 
			
		||||
			*defaultGroup.GroupVersion(),
 | 
			
		||||
			unversioned.GroupKind{Group: defaultGroup.GroupVersion().Group},
 | 
			
		||||
			unversioned.GroupKind{Group: extGroup.GroupVersion().Group},
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	t.Logf("rs.v1beta1.extensions -> rc._internal")
 | 
			
		||||
	if err := runtime.DecodeInto(decoder, data, rc); err != nil {
 | 
			
		||||
@@ -475,7 +482,7 @@ func BenchmarkEncodeCodecFromInternal(b *testing.B) {
 | 
			
		||||
	width := len(items)
 | 
			
		||||
	encodable := make([]api.Pod, width)
 | 
			
		||||
	for i := range items {
 | 
			
		||||
		if err := api.Scheme.Convert(&items[i], &encodable[i]); err != nil {
 | 
			
		||||
		if err := api.Scheme.Convert(&items[i], &encodable[i], nil); err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -281,7 +281,7 @@ func (g TestGroup) Codec() runtime.Codec {
 | 
			
		||||
	if serializer.Serializer == nil {
 | 
			
		||||
		return api.Codecs.LegacyCodec(g.externalGroupVersion)
 | 
			
		||||
	}
 | 
			
		||||
	return api.Codecs.CodecForVersions(serializer, api.Codecs.UniversalDeserializer(), []unversioned.GroupVersion{g.externalGroupVersion}, nil)
 | 
			
		||||
	return api.Codecs.CodecForVersions(serializer, api.Codecs.UniversalDeserializer(), unversioned.GroupVersions{g.externalGroupVersion}, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NegotiatedSerializer returns the negotiated serializer for the server.
 | 
			
		||||
@@ -309,7 +309,7 @@ func (g TestGroup) StorageCodec() runtime.Codec {
 | 
			
		||||
	}
 | 
			
		||||
	ds := recognizer.NewDecoder(s, api.Codecs.UniversalDeserializer())
 | 
			
		||||
 | 
			
		||||
	return api.Codecs.CodecForVersions(s, ds, []unversioned.GroupVersion{g.externalGroupVersion}, nil)
 | 
			
		||||
	return api.Codecs.CodecForVersions(s, ds, unversioned.GroupVersions{g.externalGroupVersion}, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Converter returns the api.Scheme for the API version to test against, as set by the
 | 
			
		||||
@@ -393,7 +393,7 @@ func (g TestGroup) RESTMapper() meta.RESTMapper {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExternalGroupVersions returns all external group versions allowed for the server.
 | 
			
		||||
func ExternalGroupVersions() []unversioned.GroupVersion {
 | 
			
		||||
func ExternalGroupVersions() unversioned.GroupVersions {
 | 
			
		||||
	versions := []unversioned.GroupVersion{}
 | 
			
		||||
	for _, g := range Groups {
 | 
			
		||||
		gv := g.GroupVersion()
 | 
			
		||||
 
 | 
			
		||||
@@ -179,6 +179,25 @@ func (gv GroupVersion) String() string {
 | 
			
		||||
	return gv.Version
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false
 | 
			
		||||
// if none of the options match the group. It prefers a match to group and version over just group.
 | 
			
		||||
// TODO: Move GroupVersion to a package under pkg/runtime, since it's used by scheme.
 | 
			
		||||
// TODO: Introduce an adapter type between GroupVersion and runtime.GroupVersioner, and use LegacyCodec(GroupVersion)
 | 
			
		||||
//   in fewer places.
 | 
			
		||||
func (gv GroupVersion) KindForGroupVersionKinds(kinds []GroupVersionKind) (target GroupVersionKind, ok bool) {
 | 
			
		||||
	for _, gvk := range kinds {
 | 
			
		||||
		if gvk.Group == gv.Group && gvk.Version == gv.Version {
 | 
			
		||||
			return gvk, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, gvk := range kinds {
 | 
			
		||||
		if gvk.Group == gv.Group {
 | 
			
		||||
			return gv.WithKind(gvk.Kind), true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return GroupVersionKind{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseGroupVersion turns "group/version" string into a GroupVersion struct. It reports error
 | 
			
		||||
// if it cannot parse the string.
 | 
			
		||||
func ParseGroupVersion(gv string) (GroupVersion, error) {
 | 
			
		||||
@@ -241,6 +260,25 @@ func (gv *GroupVersion) UnmarshalText(value []byte) error {
 | 
			
		||||
	return gv.unmarshal(value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GroupVersions can be used to represent a set of desired group versions.
 | 
			
		||||
// TODO: Move GroupVersions to a package under pkg/runtime, since it's used by scheme.
 | 
			
		||||
// TODO: Introduce an adapter type between GroupVersions and runtime.GroupVersioner, and use LegacyCodec(GroupVersion)
 | 
			
		||||
//   in fewer places.
 | 
			
		||||
type GroupVersions []GroupVersion
 | 
			
		||||
 | 
			
		||||
// KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false
 | 
			
		||||
// if none of the options match the group.
 | 
			
		||||
func (gvs GroupVersions) KindForGroupVersionKinds(kinds []GroupVersionKind) (target GroupVersionKind, ok bool) {
 | 
			
		||||
	for _, gv := range gvs {
 | 
			
		||||
		target, ok := gv.KindForGroupVersionKinds(kinds)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		return target, true
 | 
			
		||||
	}
 | 
			
		||||
	return GroupVersionKind{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToAPIVersionAndKind is a convenience method for satisfying runtime.Object on types that
 | 
			
		||||
// do not use TypeMeta.
 | 
			
		||||
func (gvk *GroupVersionKind) ToAPIVersionAndKind() (string, string) {
 | 
			
		||||
 
 | 
			
		||||
@@ -127,7 +127,7 @@ func TestPodSpecConversion(t *testing.T) {
 | 
			
		||||
		ServiceAccountName: name,
 | 
			
		||||
	}
 | 
			
		||||
	v := versioned.PodSpec{}
 | 
			
		||||
	if err := api.Scheme.Convert(i, &v); err != nil {
 | 
			
		||||
	if err := api.Scheme.Convert(i, &v, nil); err != nil {
 | 
			
		||||
		t.Fatalf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if v.ServiceAccountName != name {
 | 
			
		||||
@@ -152,7 +152,7 @@ func TestPodSpecConversion(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	for k, v := range testCases {
 | 
			
		||||
		got := api.PodSpec{}
 | 
			
		||||
		err := api.Scheme.Convert(v, &got)
 | 
			
		||||
		err := api.Scheme.Convert(v, &got, nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatalf("unexpected error for case %d: %v", k, err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -206,7 +206,7 @@ func TestResourceListConversion(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	for i, test := range tests {
 | 
			
		||||
		output := api.ResourceList{}
 | 
			
		||||
		err := api.Scheme.Convert(&test.input, &output)
 | 
			
		||||
		err := api.Scheme.Convert(&test.input, &output, nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatalf("unexpected error for case %d: %v", i, err)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
 | 
			
		||||
	err = api.Scheme.Convert(obj2, obj3)
 | 
			
		||||
	err = api.Scheme.Convert(obj2, obj3, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("%v\nSource: %#v", err, obj2)
 | 
			
		||||
		return nil
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@ func TestConversion(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	for k, tc := range testcases {
 | 
			
		||||
		internal := &api.Policy{}
 | 
			
		||||
		if err := api.Scheme.Convert(tc.old, internal); err != nil {
 | 
			
		||||
		if err := api.Scheme.Convert(tc.old, internal, nil); err != nil {
 | 
			
		||||
			t.Errorf("%s: unexpected error: %v", k, err)
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(internal, tc.expected) {
 | 
			
		||||
 
 | 
			
		||||
@@ -68,6 +68,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
 | 
			
		||||
		&Ingress{},
 | 
			
		||||
		&IngressList{},
 | 
			
		||||
		&api.ListOptions{},
 | 
			
		||||
		&api.DeleteOptions{},
 | 
			
		||||
		&ReplicaSet{},
 | 
			
		||||
		&ReplicaSetList{},
 | 
			
		||||
		&api.ExportOptions{},
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ func TestJobSpecConversion(t *testing.T) {
 | 
			
		||||
			ManualSelector: test.in,
 | 
			
		||||
		}
 | 
			
		||||
		v := versioned.JobSpec{}
 | 
			
		||||
		if err := api.Scheme.Convert(i, &v); err != nil {
 | 
			
		||||
		if err := api.Scheme.Convert(i, &v, nil); err != nil {
 | 
			
		||||
			t.Fatalf("unexpected error: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(test.expectOut, v.AutoSelector) {
 | 
			
		||||
@@ -73,7 +73,7 @@ func TestJobSpecConversion(t *testing.T) {
 | 
			
		||||
			AutoSelector: test.in,
 | 
			
		||||
		}
 | 
			
		||||
		e := batch.JobSpec{}
 | 
			
		||||
		if err := api.Scheme.Convert(i, &e); err != nil {
 | 
			
		||||
		if err := api.Scheme.Convert(i, &e, nil); err != nil {
 | 
			
		||||
			t.Fatalf("unexpected error: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(test.expectOut, e.ManualSelector) {
 | 
			
		||||
 
 | 
			
		||||
@@ -728,7 +728,7 @@ func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
 | 
			
		||||
	err = api.Scheme.Convert(obj2, obj3)
 | 
			
		||||
	err = api.Scheme.Convert(obj2, obj3, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("%v\nSource: %#v", err, obj2)
 | 
			
		||||
		return nil
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ limitations under the License.
 | 
			
		||||
package policy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
)
 | 
			
		||||
@@ -48,6 +49,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
 | 
			
		||||
	scheme.AddKnownTypes(SchemeGroupVersion,
 | 
			
		||||
		&PodDisruptionBudget{},
 | 
			
		||||
		&PodDisruptionBudgetList{},
 | 
			
		||||
		&api.ListOptions{},
 | 
			
		||||
	)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -320,7 +320,7 @@ type StripVersionNegotiatedSerializer struct {
 | 
			
		||||
	runtime.NegotiatedSerializer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n StripVersionNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
func (n StripVersionNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
 | 
			
		||||
	serializer, ok := encoder.(runtime.Serializer)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		// The stripVersionEncoder needs both an encoder and decoder, but is called from a context that doesn't have access to the
 | 
			
		||||
 
 | 
			
		||||
@@ -64,11 +64,11 @@ func (n *fakeNegotiater) StreamingSerializerForMediaType(mediaType string, optio
 | 
			
		||||
	}, n.streamSerializer != nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *fakeNegotiater) EncoderForVersion(serializer runtime.Encoder, gv unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
func (n *fakeNegotiater) EncoderForVersion(serializer runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
 | 
			
		||||
	return n.serializer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *fakeNegotiater) DecoderToVersion(serializer runtime.Decoder, gv unversioned.GroupVersion) runtime.Decoder {
 | 
			
		||||
func (n *fakeNegotiater) DecoderToVersion(serializer runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
 | 
			
		||||
	return n.serializer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ func NewFromFile(path string) (policyList, error) {
 | 
			
		||||
			if err := runtime.DecodeInto(decoder, b, oldPolicy); err != nil {
 | 
			
		||||
				return nil, policyLoadError{path, i, b, err}
 | 
			
		||||
			}
 | 
			
		||||
			if err := api.Scheme.Convert(oldPolicy, p); err != nil {
 | 
			
		||||
			if err := api.Scheme.Convert(oldPolicy, p, nil); err != nil {
 | 
			
		||||
				return nil, policyLoadError{path, i, b, err}
 | 
			
		||||
			}
 | 
			
		||||
			pl = append(pl, p)
 | 
			
		||||
 
 | 
			
		||||
@@ -562,7 +562,7 @@ func TestSubjectMatches(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	for k, tc := range testCases {
 | 
			
		||||
		policy := &api.Policy{}
 | 
			
		||||
		if err := api.Scheme.Convert(tc.Policy, policy); err != nil {
 | 
			
		||||
		if err := api.Scheme.Convert(tc.Policy, policy, nil); err != nil {
 | 
			
		||||
			t.Errorf("%s: error converting: %v", k, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
@@ -950,7 +950,7 @@ func TestPolicy(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		policy := &api.Policy{}
 | 
			
		||||
		if err := api.Scheme.Convert(test.policy, policy); err != nil {
 | 
			
		||||
		if err := api.Scheme.Convert(test.policy, policy, nil); err != nil {
 | 
			
		||||
			t.Errorf("%s: error converting: %v", test.name, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ func init() {
 | 
			
		||||
		Scheme,
 | 
			
		||||
		yamlSerializer,
 | 
			
		||||
		yamlSerializer,
 | 
			
		||||
		[]unversioned.GroupVersion{{Version: Version}},
 | 
			
		||||
		[]unversioned.GroupVersion{{Version: runtime.APIVersionInternal}},
 | 
			
		||||
		unversioned.GroupVersion{Version: Version},
 | 
			
		||||
		runtime.InternalGroupVersioner,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -458,7 +458,7 @@ func GetPodFromTemplate(template *api.PodTemplateSpec, parentObject runtime.Obje
 | 
			
		||||
	if controllerRef != nil {
 | 
			
		||||
		pod.OwnerReferences = append(pod.OwnerReferences, *controllerRef)
 | 
			
		||||
	}
 | 
			
		||||
	if err := api.Scheme.Convert(&template.Spec, &pod.Spec); err != nil {
 | 
			
		||||
	if err := api.Scheme.Convert(&template.Spec, &pod.Spec, nil); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("unable to convert pod template: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return pod, nil
 | 
			
		||||
 
 | 
			
		||||
@@ -209,7 +209,7 @@ func getJobFromTemplate(sj *batch.ScheduledJob, scheduledTime time.Time) (*batch
 | 
			
		||||
			Name:        name,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	if err := api.Scheme.Convert(&sj.Spec.JobTemplate.Spec, &job.Spec); err != nil {
 | 
			
		||||
	if err := api.Scheme.Convert(&sj.Spec.JobTemplate.Spec, &job.Spec, nil); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("unable to convert job template: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return job, nil
 | 
			
		||||
 
 | 
			
		||||
@@ -213,6 +213,8 @@ type Meta struct {
 | 
			
		||||
	// KeyNameMapping is an optional function which may map the listed key (field name)
 | 
			
		||||
	// into a source and destination value.
 | 
			
		||||
	KeyNameMapping FieldMappingFunc
 | 
			
		||||
	// Context is an optional field that callers may use to pass info to conversion functions.
 | 
			
		||||
	Context interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// scope contains information about an ongoing conversion.
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,6 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime/serializer/recognizer"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime/serializer/versioning"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/storage/storagebackend"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/sets"
 | 
			
		||||
 | 
			
		||||
@@ -262,18 +261,25 @@ func NewStorageCodec(storageMediaType string, ns runtime.StorageSerializer, stor
 | 
			
		||||
		s = runtime.NewBase64Serializer(s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	encoder := ns.EncoderForVersion(
 | 
			
		||||
		s,
 | 
			
		||||
		runtime.NewMultiGroupVersioner(
 | 
			
		||||
			storageVersion,
 | 
			
		||||
			unversioned.GroupKind{Group: storageVersion.Group},
 | 
			
		||||
			unversioned.GroupKind{Group: memoryVersion.Group},
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	ds := recognizer.NewDecoder(s, ns.UniversalDeserializer())
 | 
			
		||||
	encoder := ns.EncoderForVersion(s, storageVersion)
 | 
			
		||||
	decoder := ns.DecoderToVersion(ds, memoryVersion)
 | 
			
		||||
	if memoryVersion.Group != storageVersion.Group {
 | 
			
		||||
		// Allow this codec to translate between groups.
 | 
			
		||||
		if err := versioning.EnableCrossGroupEncoding(encoder, memoryVersion.Group, storageVersion.Group); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("error setting up encoder from %v to %v: %v", memoryVersion, storageVersion, err)
 | 
			
		||||
		}
 | 
			
		||||
		if err := versioning.EnableCrossGroupDecoding(decoder, storageVersion.Group, memoryVersion.Group); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("error setting up decoder from %v to %v: %v", storageVersion, memoryVersion, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	decoder := ns.DecoderToVersion(
 | 
			
		||||
		ds,
 | 
			
		||||
		runtime.NewMultiGroupVersioner(
 | 
			
		||||
			memoryVersion,
 | 
			
		||||
			unversioned.GroupKind{Group: memoryVersion.Group},
 | 
			
		||||
			unversioned.GroupKind{Group: storageVersion.Group},
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return runtime.NewCodec(encoder, decoder), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -197,7 +197,7 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		originalObjJS, err := runtime.Encode(api.Codecs.LegacyCodec(), info.VersionedObject.(runtime.Object))
 | 
			
		||||
		originalObjJS, err := runtime.Encode(api.Codecs.LegacyCodec(mapping.GroupVersionKind.GroupVersion()), info.VersionedObject.(runtime.Object))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -195,20 +195,11 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
 | 
			
		||||
	if len(p.versions) == 0 {
 | 
			
		||||
		return fmt.Errorf("no version specified, object cannot be converted")
 | 
			
		||||
	}
 | 
			
		||||
	for _, version := range p.versions {
 | 
			
		||||
		if version.IsEmpty() {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		converted, err := p.converter.ConvertToVersion(obj, version)
 | 
			
		||||
		if runtime.IsNotRegisteredError(err) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return p.printer.PrintObj(converted, w)
 | 
			
		||||
	converted, err := p.converter.ConvertToVersion(obj, unversioned.GroupVersions(p.versions))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Errorf("the object cannot be converted to any of the versions: %v", p.versions)
 | 
			
		||||
	return p.printer.PrintObj(converted, w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: implement HandledResources()
 | 
			
		||||
 
 | 
			
		||||
@@ -129,7 +129,7 @@ func TestReadPodsFromFile(t *testing.T) {
 | 
			
		||||
	for _, testCase := range testCases {
 | 
			
		||||
		func() {
 | 
			
		||||
			var versionedPod runtime.Object
 | 
			
		||||
			err := testapi.Default.Converter().Convert(&testCase.pod, &versionedPod)
 | 
			
		||||
			err := testapi.Default.Converter().Convert(&testCase.pod, &versionedPod, nil)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatalf("%s: error in versioning the pod: %v", testCase.desc, err)
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -276,7 +276,7 @@ func TestExtractPodsFromHTTP(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	for _, testCase := range testCases {
 | 
			
		||||
		var versionedPods runtime.Object
 | 
			
		||||
		err := testapi.Default.Converter().Convert(&testCase.pods, &versionedPods)
 | 
			
		||||
		err := testapi.Default.Converter().Convert(&testCase.pods, &versionedPods, nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatalf("%s: error in versioning the pods: %s", testCase.desc, err)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ type thirdPartyObjectConverter struct {
 | 
			
		||||
	converter runtime.ObjectConvertor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersion unversioned.GroupVersion) (out runtime.Object, err error) {
 | 
			
		||||
func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersion runtime.GroupVersioner) (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.
 | 
			
		||||
@@ -53,8 +53,8 @@ func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersi
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *thirdPartyObjectConverter) Convert(in, out interface{}) error {
 | 
			
		||||
	return t.converter.Convert(in, out)
 | 
			
		||||
func (t *thirdPartyObjectConverter) Convert(in, out, context interface{}) error {
 | 
			
		||||
	return t.converter.Convert(in, out, context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *thirdPartyObjectConverter) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
 | 
			
		||||
@@ -234,11 +234,11 @@ func (t *thirdPartyResourceDataCodecFactory) StreamingSerializerForMediaType(med
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *thirdPartyResourceDataCodecFactory) EncoderForVersion(s runtime.Encoder, gv unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
	return &thirdPartyResourceDataEncoder{delegate: t.delegate.EncoderForVersion(s, gv), gvk: gv.WithKind(t.kind)}
 | 
			
		||||
func (t *thirdPartyResourceDataCodecFactory) EncoderForVersion(s runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
 | 
			
		||||
	return &thirdPartyResourceDataEncoder{delegate: t.delegate.EncoderForVersion(s, gv), gvk: t.encodeGV.WithKind(t.kind)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *thirdPartyResourceDataCodecFactory) DecoderToVersion(s runtime.Decoder, gv unversioned.GroupVersion) runtime.Decoder {
 | 
			
		||||
func (t *thirdPartyResourceDataCodecFactory) DecoderToVersion(s runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
 | 
			
		||||
	return NewDecoder(t.delegate.DecoderToVersion(s, gv), t.kind)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -517,6 +517,10 @@ func (t *thirdPartyResourceDataEncoder) Encode(obj runtime.Object, stream io.Wri
 | 
			
		||||
			listItems[ix] = json.RawMessage(buff.Bytes())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if t.gvk.IsEmpty() {
 | 
			
		||||
			return fmt.Errorf("thirdPartyResourceDataEncoder was not given a target version")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		encMap := struct {
 | 
			
		||||
			Kind       string               `json:"kind,omitempty"`
 | 
			
		||||
			Items      []json.RawMessage    `json:"items"`
 | 
			
		||||
 
 | 
			
		||||
@@ -145,16 +145,16 @@ func (c *parameterCodec) DecodeParameters(parameters url.Values, from unversione
 | 
			
		||||
	}
 | 
			
		||||
	targetGVK := targetGVKs[0]
 | 
			
		||||
	if targetGVK.GroupVersion() == from {
 | 
			
		||||
		return c.convertor.Convert(¶meters, into)
 | 
			
		||||
		return c.convertor.Convert(¶meters, into, nil)
 | 
			
		||||
	}
 | 
			
		||||
	input, err := c.creator.New(from.WithKind(targetGVK.Kind))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := c.convertor.Convert(¶meters, input); err != nil {
 | 
			
		||||
	if err := c.convertor.Convert(¶meters, input, nil); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return c.convertor.Convert(input, into)
 | 
			
		||||
	return c.convertor.Convert(input, into, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodeParameters converts the provided object into the to version, then converts that object to url.Values.
 | 
			
		||||
@@ -198,3 +198,83 @@ func (s base64Serializer) Decode(data []byte, defaults *unversioned.GroupVersion
 | 
			
		||||
	}
 | 
			
		||||
	return s.Serializer.Decode(out[:n], defaults, into)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// InternalGroupVersioner will always prefer the internal version for a given group version kind.
 | 
			
		||||
	InternalGroupVersioner GroupVersioner = internalGroupVersioner{}
 | 
			
		||||
	// DisabledGroupVersioner will reject all kinds passed to it.
 | 
			
		||||
	DisabledGroupVersioner GroupVersioner = disabledGroupVersioner{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type internalGroupVersioner struct{}
 | 
			
		||||
 | 
			
		||||
// KindForGroupVersionKinds returns an internal Kind if one is found, or converts the first provided kind to the internal version.
 | 
			
		||||
func (internalGroupVersioner) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
 | 
			
		||||
	for _, kind := range kinds {
 | 
			
		||||
		if kind.Version == APIVersionInternal {
 | 
			
		||||
			return kind, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, kind := range kinds {
 | 
			
		||||
		return unversioned.GroupVersionKind{Group: kind.Group, Version: APIVersionInternal, Kind: kind.Kind}, true
 | 
			
		||||
	}
 | 
			
		||||
	return unversioned.GroupVersionKind{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type disabledGroupVersioner struct{}
 | 
			
		||||
 | 
			
		||||
// KindForGroupVersionKinds returns false for any input.
 | 
			
		||||
func (disabledGroupVersioner) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
 | 
			
		||||
	return unversioned.GroupVersionKind{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GroupVersioners implements GroupVersioner and resolves to the first exact match for any kind.
 | 
			
		||||
type GroupVersioners []GroupVersioner
 | 
			
		||||
 | 
			
		||||
// KindForGroupVersionKinds returns the first match of any of the group versioners, or false if no match occured.
 | 
			
		||||
func (gvs GroupVersioners) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
 | 
			
		||||
	for _, gv := range gvs {
 | 
			
		||||
		target, ok := gv.KindForGroupVersionKinds(kinds)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		return target, true
 | 
			
		||||
	}
 | 
			
		||||
	return unversioned.GroupVersionKind{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Assert that unversioned.GroupVersion and GroupVersions implement GroupVersioner
 | 
			
		||||
var _ GroupVersioner = unversioned.GroupVersion{}
 | 
			
		||||
var _ GroupVersioner = unversioned.GroupVersions{}
 | 
			
		||||
var _ GroupVersioner = multiGroupVersioner{}
 | 
			
		||||
 | 
			
		||||
type multiGroupVersioner struct {
 | 
			
		||||
	target             unversioned.GroupVersion
 | 
			
		||||
	acceptedGroupKinds []unversioned.GroupKind
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewMultiGroupVersioner returns the provided group version for any kind that matches one of the provided group kinds.
 | 
			
		||||
// Kind may be empty in the provided group kind, in which case any kind will match.
 | 
			
		||||
func NewMultiGroupVersioner(gv unversioned.GroupVersion, groupKinds ...unversioned.GroupKind) GroupVersioner {
 | 
			
		||||
	if len(groupKinds) == 0 || (len(groupKinds) == 1 && groupKinds[0].Group == gv.Group) {
 | 
			
		||||
		return gv
 | 
			
		||||
	}
 | 
			
		||||
	return multiGroupVersioner{target: gv, acceptedGroupKinds: groupKinds}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KindForGroupVersionKinds returns the target group version if any kind matches any of the original group kinds. It will
 | 
			
		||||
// use the originating kind where possible.
 | 
			
		||||
func (v multiGroupVersioner) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
 | 
			
		||||
	for _, src := range kinds {
 | 
			
		||||
		for _, kind := range v.acceptedGroupKinds {
 | 
			
		||||
			if kind.Group != src.Group {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if len(kind.Kind) > 0 && kind.Kind != src.Kind {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			return v.target.WithKind(src.Kind), true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return unversioned.GroupVersionKind{}, false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@ func TestStringMapConversion(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	for k, tc := range testCases {
 | 
			
		||||
		out := &ExternalComplex{}
 | 
			
		||||
		if err := scheme.Convert(&tc.input, out); (tc.errFn == nil && err != nil) || (tc.errFn != nil && !tc.errFn(err)) {
 | 
			
		||||
		if err := scheme.Convert(&tc.input, out, nil); (tc.errFn == nil && err != nil) || (tc.errFn != nil && !tc.errFn(err)) {
 | 
			
		||||
			t.Errorf("%s: unexpected error: %v", k, err)
 | 
			
		||||
			continue
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ 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) {
 | 
			
		||||
func (c unsafeObjectConvertor) ConvertToVersion(in Object, outVersion GroupVersioner) (Object, error) {
 | 
			
		||||
	return c.Scheme.UnsafeConvertToVersion(in, outVersion)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,12 +30,23 @@ const (
 | 
			
		||||
	APIVersionInternal = "__internal"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GroupVersioner refines a set of possible conversion targets into a single option.
 | 
			
		||||
type GroupVersioner interface {
 | 
			
		||||
	// KindForGroupVersionKinds returns a desired target group version kind for the given input, or returns ok false if no
 | 
			
		||||
	// target is known. In general, if the return target is not in the input list, the caller is expected to invoke
 | 
			
		||||
	// Scheme.New(target) and then perform a conversion between the current Go type and the destination Go type.
 | 
			
		||||
	// Sophisticated implementations may use additional information about the input kinds to pick a destination kind.
 | 
			
		||||
	KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (target unversioned.GroupVersionKind, ok bool)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encoders write objects to a serialized form
 | 
			
		||||
type Encoder interface {
 | 
			
		||||
	// Encode writes an object to a stream. Implementations may return errors if the versions are
 | 
			
		||||
	// incompatible, or if no conversion is defined.
 | 
			
		||||
	Encode(obj Object, w io.Writer) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decoders attempt to load an object from data.
 | 
			
		||||
type Decoder interface {
 | 
			
		||||
	// Decode attempts to deserialize the provided data using either the innate typing of the scheme or the
 | 
			
		||||
	// default kind, group, and version provided. It returns a decoded object as well as the kind, group, and
 | 
			
		||||
@@ -117,12 +128,10 @@ type NegotiatedSerializer interface {
 | 
			
		||||
 | 
			
		||||
	// EncoderForVersion returns an encoder that ensures objects being written to the provided
 | 
			
		||||
	// serializer are in the provided group version.
 | 
			
		||||
	// TODO: take multiple group versions
 | 
			
		||||
	EncoderForVersion(serializer Encoder, gv unversioned.GroupVersion) Encoder
 | 
			
		||||
	EncoderForVersion(serializer Encoder, gv GroupVersioner) Encoder
 | 
			
		||||
	// DecoderForVersion returns a decoder that ensures objects being read by the provided
 | 
			
		||||
	// serializer are in the provided group version by default.
 | 
			
		||||
	// TODO: take multiple group versions
 | 
			
		||||
	DecoderToVersion(serializer Decoder, gv unversioned.GroupVersion) Decoder
 | 
			
		||||
	DecoderToVersion(serializer Decoder, gv GroupVersioner) Decoder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StorageSerializer is an interface used for obtaining encoders, decoders, and serializers
 | 
			
		||||
@@ -139,29 +148,41 @@ type StorageSerializer interface {
 | 
			
		||||
 | 
			
		||||
	// EncoderForVersion returns an encoder that ensures objects being written to the provided
 | 
			
		||||
	// serializer are in the provided group version.
 | 
			
		||||
	// TODO: take multiple group versions
 | 
			
		||||
	EncoderForVersion(serializer Encoder, gv unversioned.GroupVersion) Encoder
 | 
			
		||||
	EncoderForVersion(serializer Encoder, gv GroupVersioner) Encoder
 | 
			
		||||
	// DecoderForVersion returns a decoder that ensures objects being read by the provided
 | 
			
		||||
	// serializer are in the provided group version by default.
 | 
			
		||||
	// TODO: take multiple group versions
 | 
			
		||||
	DecoderToVersion(serializer Decoder, gv unversioned.GroupVersion) Decoder
 | 
			
		||||
	DecoderToVersion(serializer Decoder, gv GroupVersioner) Decoder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NestedObjectEncoder is an optional interface that objects may implement to be given
 | 
			
		||||
// an opportunity to encode any nested Objects / RawExtensions during serialization.
 | 
			
		||||
type NestedObjectEncoder interface {
 | 
			
		||||
	EncodeNestedObjects(e Encoder) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NestedObjectDecoder is an optional interface that objects may implement to be given
 | 
			
		||||
// an opportunity to decode any nested Objects / RawExtensions during serialization.
 | 
			
		||||
type NestedObjectDecoder interface {
 | 
			
		||||
	DecodeNestedObjects(d Decoder) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Non-codec interfaces
 | 
			
		||||
 | 
			
		||||
type ObjectVersioner interface {
 | 
			
		||||
	ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (out Object, err error)
 | 
			
		||||
	ConvertToVersion(in Object, gv GroupVersioner) (out Object, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ObjectConvertor converts an object to a different version.
 | 
			
		||||
type ObjectConvertor interface {
 | 
			
		||||
	// Convert attempts to convert one object into another, or returns an error. This method does
 | 
			
		||||
	// not guarantee the in object is not mutated.
 | 
			
		||||
	Convert(in, out interface{}) error
 | 
			
		||||
	// not guarantee the in object is not mutated. The context argument will be passed to
 | 
			
		||||
	// all nested conversions.
 | 
			
		||||
	Convert(in, out, context 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 unversioned.GroupVersion) (out Object, err error)
 | 
			
		||||
	// method does not guarantee that the in object is not mutated. This method is similar to
 | 
			
		||||
	// Convert() but handles specific details of choosing the correct output version.
 | 
			
		||||
	ConvertToVersion(in Object, gv GroupVersioner) (out Object, err error)
 | 
			
		||||
	ConvertFieldLabel(version, kind, label, value string) (string, string, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -237,7 +237,7 @@ func (s *Scheme) ObjectKinds(obj Object) ([]unversioned.GroupVersionKind, bool,
 | 
			
		||||
 | 
			
		||||
	gvks, ok := s.typeToGVK[t]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, false, ¬RegisteredErr{t: t}
 | 
			
		||||
		return nil, false, NewNotRegisteredErr(unversioned.GroupVersionKind{}, t)
 | 
			
		||||
	}
 | 
			
		||||
	_, unversionedType := s.unversionedTypes[t]
 | 
			
		||||
 | 
			
		||||
@@ -275,7 +275,7 @@ func (s *Scheme) New(kind unversioned.GroupVersionKind) (Object, error) {
 | 
			
		||||
	if t, exists := s.unversionedKinds[kind.Kind]; exists {
 | 
			
		||||
		return reflect.New(t).Interface().(Object), nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, ¬RegisteredErr{gvk: kind}
 | 
			
		||||
	return nil, NewNotRegisteredErr(kind, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern
 | 
			
		||||
@@ -438,23 +438,13 @@ func (s *Scheme) DeepCopy(src interface{}) (interface{}, error) {
 | 
			
		||||
// Convert will attempt to convert in into out. Both must be pointers. For easy
 | 
			
		||||
// testing of conversion functions. Returns an error if the conversion isn't
 | 
			
		||||
// possible. You can call this with types that haven't been registered (for example,
 | 
			
		||||
// a to test conversion of types that are nested within registered types), but in
 | 
			
		||||
// that case, the conversion.Scope object passed to your conversion functions won't
 | 
			
		||||
// have SrcVersion or DestVersion fields set correctly in Meta().
 | 
			
		||||
func (s *Scheme) Convert(in, out interface{}) error {
 | 
			
		||||
	inVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
 | 
			
		||||
	outVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
 | 
			
		||||
	if inObj, ok := in.(Object); ok {
 | 
			
		||||
		if gvks, _, err := s.ObjectKinds(inObj); err == nil {
 | 
			
		||||
			inVersion = gvks[0].GroupVersion()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if outObj, ok := out.(Object); ok {
 | 
			
		||||
		if gvks, _, err := s.ObjectKinds(outObj); err == nil {
 | 
			
		||||
			outVersion = gvks[0].GroupVersion()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
 | 
			
		||||
// a to test conversion of types that are nested within registered types). The
 | 
			
		||||
// context interface is passed to the convertor.
 | 
			
		||||
// TODO: identify whether context should be hidden, or behind a formal context/scope
 | 
			
		||||
//   interface
 | 
			
		||||
func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
 | 
			
		||||
	flags, meta := s.generateConvertMeta(in)
 | 
			
		||||
	meta.Context = context
 | 
			
		||||
	if flags == 0 {
 | 
			
		||||
		flags = conversion.AllowDifferentFieldTypeNames
 | 
			
		||||
	}
 | 
			
		||||
@@ -478,73 +468,20 @@ func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string,
 | 
			
		||||
// version within this scheme. Will return an error if the provided version does not
 | 
			
		||||
// 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 unversioned.GroupVersion) (Object, error) {
 | 
			
		||||
	switch in.(type) {
 | 
			
		||||
	case *Unknown, *Unstructured, *UnstructuredList:
 | 
			
		||||
		old := in.GetObjectKind().GroupVersionKind()
 | 
			
		||||
		defer in.GetObjectKind().SetGroupVersionKind(old)
 | 
			
		||||
		setTargetVersion(in, s, outVersion)
 | 
			
		||||
		return in, nil
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var kind unversioned.GroupVersionKind
 | 
			
		||||
	if unversionedKind, ok := s.unversionedTypes[t]; ok {
 | 
			
		||||
		kind = unversionedKind
 | 
			
		||||
	} else {
 | 
			
		||||
		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)
 | 
			
		||||
		}
 | 
			
		||||
		kind = kinds[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	outKind := outVersion.WithKind(kind.Kind)
 | 
			
		||||
 | 
			
		||||
	inKinds, _, err := s.ObjectKinds(in)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out, err := s.New(outKind)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flags, meta := s.generateConvertMeta(inKinds[0].GroupVersion(), outVersion, in)
 | 
			
		||||
	if err := s.converter.Convert(in, out, flags, meta); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setTargetVersion(out, s, outVersion)
 | 
			
		||||
	return out, nil
 | 
			
		||||
// returned. Passes target down to the conversion methods as the Context on the scope.
 | 
			
		||||
func (s *Scheme) ConvertToVersion(in Object, target GroupVersioner) (Object, error) {
 | 
			
		||||
	return s.convertToVersion(true, in, target)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnsafeConvertToVersion will convert in to the provided outVersion if such a conversion is possible,
 | 
			
		||||
// UnsafeConvertToVersion will convert in to the provided target 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
 | 
			
		||||
	}
 | 
			
		||||
func (s *Scheme) UnsafeConvertToVersion(in Object, target GroupVersioner) (Object, error) {
 | 
			
		||||
	return s.convertToVersion(false, in, target)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// convertToVersion handles conversion with an optional copy.
 | 
			
		||||
func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (Object, error) {
 | 
			
		||||
	// determine the incoming kinds with as few allocations as possible.
 | 
			
		||||
	t := reflect.TypeOf(in)
 | 
			
		||||
	if t.Kind() != reflect.Ptr {
 | 
			
		||||
@@ -556,64 +493,69 @@ func (s *Scheme) UnsafeConvertToVersion(in Object, outVersion unversioned.GroupV
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
		return nil, NewNotRegisteredErr(unversioned.GroupVersionKind{}, t)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
	gvk, ok := target.KindForGroupVersionKinds(kinds)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		// TODO: should this be a typed error?
 | 
			
		||||
		return nil, fmt.Errorf("%v is not suitable for converting to %q", t, target)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// target wants to use the existing type, set kind and return (no conversion necessary)
 | 
			
		||||
	for _, kind := range kinds {
 | 
			
		||||
		if gvk == kind {
 | 
			
		||||
			return copyAndSetTargetKind(copy, s, in, gvk)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
		if gvk, ok := target.KindForGroupVersionKinds([]unversioned.GroupVersionKind{unversionedKind}); ok {
 | 
			
		||||
			return copyAndSetTargetKind(copy, s, in, gvk)
 | 
			
		||||
		}
 | 
			
		||||
		return copyAndSetTargetKind(copy, s, in, unversionedKind)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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)
 | 
			
		||||
	out, err := s.New(gvk)
 | 
			
		||||
	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 copy {
 | 
			
		||||
		copied, err := s.Copy(in)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		in = copied
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flags, meta := s.generateConvertMeta(in)
 | 
			
		||||
	meta.Context = target
 | 
			
		||||
	if err := s.converter.Convert(in, out, flags, meta); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setTargetKind(out, kind)
 | 
			
		||||
	setTargetKind(out, gvk)
 | 
			
		||||
	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) {
 | 
			
		||||
func (s *Scheme) generateConvertMeta(in interface{}) (conversion.FieldMatchingFlags, *conversion.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(unversioned.GroupVersionKind{})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if gvks, _, _ := raw.ObjectKinds(obj); len(gvks) > 0 {
 | 
			
		||||
		obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvks[0].Kind})
 | 
			
		||||
	} else {
 | 
			
		||||
		obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version})
 | 
			
		||||
// copyAndSetTargetKind performs a conditional copy before returning the object, or an error if copy was not successful.
 | 
			
		||||
func copyAndSetTargetKind(copy bool, copier ObjectCopier, obj Object, kind unversioned.GroupVersionKind) (Object, error) {
 | 
			
		||||
	if copy {
 | 
			
		||||
		copied, err := copier.Copy(obj)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		obj = copied
 | 
			
		||||
	}
 | 
			
		||||
	setTargetKind(obj, kind)
 | 
			
		||||
	return obj, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ package runtime_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/gofuzz"
 | 
			
		||||
@@ -128,7 +129,7 @@ func TestScheme(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// Test Convert
 | 
			
		||||
	external := &ExternalSimple{}
 | 
			
		||||
	err = scheme.Convert(simple, external)
 | 
			
		||||
	err = scheme.Convert(simple, external, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -460,6 +461,16 @@ type ExternalInternalSame struct {
 | 
			
		||||
	A                                     TestType2 `json:"A,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UnversionedType struct {
 | 
			
		||||
	MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
 | 
			
		||||
	A                                     string `json:"A,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UnknownType struct {
 | 
			
		||||
	MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
 | 
			
		||||
	A                                     string `json:"A,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() unversioned.ObjectKind { return obj }
 | 
			
		||||
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
 | 
			
		||||
	obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind()
 | 
			
		||||
@@ -500,6 +511,8 @@ var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
 | 
			
		||||
func GetTestScheme() *runtime.Scheme {
 | 
			
		||||
	internalGV := unversioned.GroupVersion{Version: "__internal"}
 | 
			
		||||
	externalGV := unversioned.GroupVersion{Version: "v1"}
 | 
			
		||||
	alternateExternalGV := unversioned.GroupVersion{Group: "custom", Version: "v1"}
 | 
			
		||||
	differentExternalGV := unversioned.GroupVersion{Group: "other", Version: "v2"}
 | 
			
		||||
 | 
			
		||||
	s := runtime.NewScheme()
 | 
			
		||||
	// Ordinarily, we wouldn't add TestType2, but because this is a test and
 | 
			
		||||
@@ -511,6 +524,11 @@ func GetTestScheme() *runtime.Scheme {
 | 
			
		||||
	s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &ExternalTestType2{})
 | 
			
		||||
	s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &TestType1{})
 | 
			
		||||
	s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &ExternalTestType1{})
 | 
			
		||||
	s.AddKnownTypeWithName(externalGV.WithKind("TestType4"), &ExternalTestType1{})
 | 
			
		||||
	s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType3"), &ExternalTestType1{})
 | 
			
		||||
	s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType5"), &ExternalTestType1{})
 | 
			
		||||
	s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &ExternalTestType1{})
 | 
			
		||||
	s.AddUnversionedTypes(externalGV, &UnversionedType{})
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -528,7 +546,7 @@ func TestKnownTypes(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestConvertToVersion(t *testing.T) {
 | 
			
		||||
func TestConvertToVersionBasic(t *testing.T) {
 | 
			
		||||
	s := GetTestScheme()
 | 
			
		||||
	tt := &TestType1{A: "I'm not a pointer object"}
 | 
			
		||||
	other, err := s.ConvertToVersion(tt, unversioned.GroupVersion{Version: "v1"})
 | 
			
		||||
@@ -537,13 +555,258 @@ func TestConvertToVersion(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	converted, ok := other.(*ExternalTestType1)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Got wrong type")
 | 
			
		||||
		t.Fatalf("Got wrong type: %T", other)
 | 
			
		||||
	}
 | 
			
		||||
	if tt.A != converted.A {
 | 
			
		||||
		t.Fatalf("Failed to convert object correctly: %#v", converted)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type testGroupVersioner struct {
 | 
			
		||||
	target unversioned.GroupVersionKind
 | 
			
		||||
	ok     bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m testGroupVersioner) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
 | 
			
		||||
	return m.target, m.ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestConvertToVersion(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		scheme *runtime.Scheme
 | 
			
		||||
		in     runtime.Object
 | 
			
		||||
		gv     runtime.GroupVersioner
 | 
			
		||||
		same   bool
 | 
			
		||||
		out    runtime.Object
 | 
			
		||||
		errFn  func(error) bool
 | 
			
		||||
	}{
 | 
			
		||||
		// errors if the type is not registered in the scheme
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &UnknownType{},
 | 
			
		||||
			errFn:  func(err error) bool { return err != nil && runtime.IsNotRegisteredError(err) },
 | 
			
		||||
		},
 | 
			
		||||
		// errors if the group versioner returns no target
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     testGroupVersioner{},
 | 
			
		||||
			errFn: func(err error) bool {
 | 
			
		||||
				return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// converts to internal
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     unversioned.GroupVersion{Version: "__internal"},
 | 
			
		||||
			out:    &TestType1{A: "test"},
 | 
			
		||||
		},
 | 
			
		||||
		// prefers the first group version in the list
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     unversioned.GroupVersions{{Version: "__internal"}, {Version: "v1"}},
 | 
			
		||||
			out:    &TestType1{A: "test"},
 | 
			
		||||
		},
 | 
			
		||||
		// unversioned type returned as-is
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &UnversionedType{A: "test"},
 | 
			
		||||
			gv:     unversioned.GroupVersions{{Version: "v1"}},
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &UnversionedType{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// detected as already being in the target version
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     unversioned.GroupVersions{{Version: "v1"}},
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// detected as already being in the first target version
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     unversioned.GroupVersions{{Version: "v1"}, {Version: "__internal"}},
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// detected as already being in the first target version
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     unversioned.GroupVersions{{Version: "v1"}, {Version: "__internal"}},
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (1/3): different kind
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     testGroupVersioner{ok: true, target: unversioned.GroupVersionKind{Kind: "TestType3", Version: "v1"}},
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (2/3): different gv
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     testGroupVersioner{ok: true, target: unversioned.GroupVersionKind{Kind: "TestType3", Group: "custom", Version: "v1"}},
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (3/3): different gvk
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     testGroupVersioner{ok: true, target: unversioned.GroupVersionKind{Group: "custom", Version: "v1", Kind: "TestType5"}},
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     runtime.NewMultiGroupVersioner(unversioned.GroupVersion{Group: "other", Version: "v2"}, unversioned.GroupKind{Group: "custom", Kind: "TestType3"}, unversioned.GroupKind{Kind: "TestType1"}),
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     runtime.NewMultiGroupVersioner(unversioned.GroupVersion{Group: "other", Version: "v2"}, unversioned.GroupKind{Kind: "TestType1"}, unversioned.GroupKind{Group: "custom", Kind: "TestType3"}),
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// multi group versioner is unable to find a match when kind AND group don't match (there is no TestType1 kind in group "other", and no kind "TestType5" in the default group)
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &TestType1{A: "test"},
 | 
			
		||||
			gv:     runtime.NewMultiGroupVersioner(unversioned.GroupVersion{Group: "custom", Version: "v1"}, unversioned.GroupKind{Group: "other"}, unversioned.GroupKind{Kind: "TestType5"}),
 | 
			
		||||
			errFn: func(err error) bool {
 | 
			
		||||
				return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     runtime.NewMultiGroupVersioner(unversioned.GroupVersion{Group: "", Version: "v1"}, unversioned.GroupKind{Group: "custom", Kind: "TestType3"}, unversioned.GroupKind{Kind: "TestType1"}),
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &ExternalTestType1{A: "test"},
 | 
			
		||||
			gv:     runtime.NewMultiGroupVersioner(unversioned.GroupVersion{Group: "", Version: "v1"}, unversioned.GroupKind{Kind: "TestType1"}, unversioned.GroupKind{Group: "custom", Kind: "TestType3"}),
 | 
			
		||||
			same:   true,
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// group versioner can choose a particular target kind for a given input when kind is the same across group versions
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &TestType1{A: "test"},
 | 
			
		||||
			gv:     testGroupVersioner{ok: true, target: unversioned.GroupVersionKind{Version: "v1", Kind: "TestType3"}},
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// group versioner can choose a different kind
 | 
			
		||||
		{
 | 
			
		||||
			scheme: GetTestScheme(),
 | 
			
		||||
			in:     &TestType1{A: "test"},
 | 
			
		||||
			gv:     testGroupVersioner{ok: true, target: unversioned.GroupVersionKind{Kind: "TestType5", Group: "custom", Version: "v1"}},
 | 
			
		||||
			out: &ExternalTestType1{
 | 
			
		||||
				MyWeirdCustomEmbeddedVersionKindField: MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
 | 
			
		||||
				A: "test",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for i, test := range testCases {
 | 
			
		||||
		original, _ := test.scheme.DeepCopy(test.in)
 | 
			
		||||
		out, err := test.scheme.ConvertToVersion(test.in, test.gv)
 | 
			
		||||
		switch {
 | 
			
		||||
		case test.errFn != nil:
 | 
			
		||||
			if !test.errFn(err) {
 | 
			
		||||
				t.Errorf("%d: unexpected error: %v", i, err)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		case err != nil:
 | 
			
		||||
			t.Errorf("%d: unexpected error: %v", i, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if out == test.in {
 | 
			
		||||
			t.Errorf("%d: ConvertToVersion should always copy out: %#v", i, out)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.same {
 | 
			
		||||
			if !reflect.DeepEqual(original, test.in) {
 | 
			
		||||
				t.Errorf("%d: unexpected mutation of input: %s", i, diff.ObjectReflectDiff(original, test.in))
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if !reflect.DeepEqual(out, test.out) {
 | 
			
		||||
				t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			unsafe, err := test.scheme.UnsafeConvertToVersion(test.in, test.gv)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Errorf("%d: unexpected error: %v", i, err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if !reflect.DeepEqual(unsafe, test.out) {
 | 
			
		||||
				t.Errorf("%d: unexpected unsafe: %s", i, diff.ObjectReflectDiff(unsafe, test.out))
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if unsafe != test.in {
 | 
			
		||||
				t.Errorf("%d: UnsafeConvertToVersion should return same object: %#v", i, unsafe)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(out, test.out) {
 | 
			
		||||
			t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMetaValues(t *testing.T) {
 | 
			
		||||
	internalGV := unversioned.GroupVersion{Group: "test.group", Version: "__internal"}
 | 
			
		||||
	externalGV := unversioned.GroupVersion{Group: "test.group", Version: "externalVersion"}
 | 
			
		||||
@@ -631,7 +894,7 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	simple := &InternalSimple{TestString: "foo"}
 | 
			
		||||
	external := &ExternalSimple{}
 | 
			
		||||
	err = s.Convert(simple, external)
 | 
			
		||||
	err = s.Convert(simple, external, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,6 @@ limitations under the License.
 | 
			
		||||
package serializer
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime/serializer/json"
 | 
			
		||||
@@ -188,13 +186,17 @@ func (f CodecFactory) SupportedStreamingMediaTypes() []string {
 | 
			
		||||
	return f.streamingAccepts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LegacyCodec encodes output to a given API version, and decodes output into the internal form from
 | 
			
		||||
// any recognized source. The returned codec will always encode output to JSON.
 | 
			
		||||
// LegacyCodec encodes output to a given API versions, and decodes output into the internal form from
 | 
			
		||||
// any recognized source. The returned codec will always encode output to JSON. If a type is not
 | 
			
		||||
// found in the list of versions an error will be returned.
 | 
			
		||||
//
 | 
			
		||||
// This method is deprecated - clients and servers should negotiate a serializer by mime-type and
 | 
			
		||||
// invoke CodecForVersions. Callers that need only to read data should use UniversalDecoder().
 | 
			
		||||
//
 | 
			
		||||
// TODO: make this call exist only in pkg/api, and initialize it with the set of default versions.
 | 
			
		||||
//   All other callers will be forced to request a Codec directly.
 | 
			
		||||
func (f CodecFactory) LegacyCodec(version ...unversioned.GroupVersion) runtime.Codec {
 | 
			
		||||
	return versioning.NewCodecForScheme(f.scheme, f.legacySerializer, f.universal, version, nil)
 | 
			
		||||
	return versioning.NewCodecForScheme(f.scheme, f.legacySerializer, f.universal, unversioned.GroupVersions(version), runtime.InternalGroupVersioner)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UniversalDeserializer can convert any stored data recognized by this factory into a Go object that satisfies
 | 
			
		||||
@@ -211,25 +213,39 @@ func (f CodecFactory) UniversalDeserializer() runtime.Decoder {
 | 
			
		||||
// defaulting.
 | 
			
		||||
//
 | 
			
		||||
// TODO: the decoder will eventually be removed in favor of dealing with objects in their versioned form
 | 
			
		||||
// TODO: only accept a group versioner
 | 
			
		||||
func (f CodecFactory) UniversalDecoder(versions ...unversioned.GroupVersion) runtime.Decoder {
 | 
			
		||||
	return f.CodecForVersions(nil, f.universal, nil, versions)
 | 
			
		||||
	var versioner runtime.GroupVersioner
 | 
			
		||||
	if len(versions) == 0 {
 | 
			
		||||
		versioner = runtime.InternalGroupVersioner
 | 
			
		||||
	} else {
 | 
			
		||||
		versioner = unversioned.GroupVersions(versions)
 | 
			
		||||
	}
 | 
			
		||||
	return f.CodecForVersions(nil, f.universal, nil, versioner)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CodecForVersions creates a codec with the provided serializer. If an object is decoded and its group is not in the list,
 | 
			
		||||
// it will default to runtime.APIVersionInternal. If encode is not specified for an object's group, the object is not
 | 
			
		||||
// converted. If encode or decode are nil, no conversion is performed.
 | 
			
		||||
func (f CodecFactory) CodecForVersions(encoder runtime.Encoder, decoder runtime.Decoder, encode []unversioned.GroupVersion, decode []unversioned.GroupVersion) runtime.Codec {
 | 
			
		||||
func (f CodecFactory) CodecForVersions(encoder runtime.Encoder, decoder runtime.Decoder, encode runtime.GroupVersioner, decode runtime.GroupVersioner) runtime.Codec {
 | 
			
		||||
	// TODO: these are for backcompat, remove them in the future
 | 
			
		||||
	if encode == nil {
 | 
			
		||||
		encode = runtime.DisabledGroupVersioner
 | 
			
		||||
	}
 | 
			
		||||
	if decode == nil {
 | 
			
		||||
		decode = runtime.InternalGroupVersioner
 | 
			
		||||
	}
 | 
			
		||||
	return versioning.NewCodecForScheme(f.scheme, encoder, decoder, encode, decode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecoderToVersion returns a decoder that targets the provided group version.
 | 
			
		||||
func (f CodecFactory) DecoderToVersion(decoder runtime.Decoder, gv unversioned.GroupVersion) runtime.Decoder {
 | 
			
		||||
	return f.CodecForVersions(nil, decoder, nil, []unversioned.GroupVersion{gv})
 | 
			
		||||
func (f CodecFactory) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
 | 
			
		||||
	return f.CodecForVersions(nil, decoder, nil, gv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncoderForVersion returns an encoder that targets the provided group version.
 | 
			
		||||
func (f CodecFactory) EncoderForVersion(encoder runtime.Encoder, gv unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
	return f.CodecForVersions(encoder, nil, []unversioned.GroupVersion{gv}, nil)
 | 
			
		||||
func (f CodecFactory) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
 | 
			
		||||
	return f.CodecForVersions(encoder, nil, gv, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SerializerForMediaType returns a serializer that matches the provided RFC2046 mediaType, or false if no such
 | 
			
		||||
@@ -317,48 +333,16 @@ type DirectCodecFactory struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncoderForVersion returns an encoder that does not do conversion. gv is ignored.
 | 
			
		||||
func (f DirectCodecFactory) EncoderForVersion(serializer runtime.Encoder, gv unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
	return DirectCodec{
 | 
			
		||||
		runtime.NewCodec(serializer, nil),
 | 
			
		||||
		f.CodecFactory.scheme,
 | 
			
		||||
func (f DirectCodecFactory) EncoderForVersion(serializer runtime.Encoder, _ runtime.GroupVersioner) runtime.Encoder {
 | 
			
		||||
	return versioning.DirectEncoder{
 | 
			
		||||
		Encoder:     serializer,
 | 
			
		||||
		ObjectTyper: f.CodecFactory.scheme,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecoderToVersion returns an decoder that does not do conversion. gv is ignored.
 | 
			
		||||
func (f DirectCodecFactory) DecoderToVersion(serializer runtime.Decoder, gv unversioned.GroupVersion) runtime.Decoder {
 | 
			
		||||
	return DirectCodec{
 | 
			
		||||
		runtime.NewCodec(nil, serializer),
 | 
			
		||||
		nil,
 | 
			
		||||
func (f DirectCodecFactory) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder {
 | 
			
		||||
	return versioning.DirectDecoder{
 | 
			
		||||
		Decoder: serializer,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DirectCodec is a codec that does not do conversion. It sets the gvk during serialization, and removes the gvk during deserialization.
 | 
			
		||||
type DirectCodec struct {
 | 
			
		||||
	runtime.Serializer
 | 
			
		||||
	runtime.ObjectTyper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodeToStream does not do conversion. It sets the gvk during serialization. overrides are ignored.
 | 
			
		||||
func (c DirectCodec) Encode(obj runtime.Object, stream io.Writer) error {
 | 
			
		||||
	gvks, _, err := c.ObjectTyper.ObjectKinds(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	kind := obj.GetObjectKind()
 | 
			
		||||
	oldGVK := kind.GroupVersionKind()
 | 
			
		||||
	kind.SetGroupVersionKind(gvks[0])
 | 
			
		||||
	err = c.Serializer.Encode(obj, stream)
 | 
			
		||||
	kind.SetGroupVersionKind(oldGVK)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decode does not do conversion. It removes the gvk during deserialization.
 | 
			
		||||
func (c DirectCodec) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
 | 
			
		||||
	obj, gvk, err := c.Serializer.Decode(data, defaults, into)
 | 
			
		||||
	if obj != nil {
 | 
			
		||||
		kind := obj.GetObjectKind()
 | 
			
		||||
		// clearing the gvk is just a convention of a codec
 | 
			
		||||
		kind.SetGroupVersionKind(unversioned.GroupVersionKind{})
 | 
			
		||||
	}
 | 
			
		||||
	return obj, gvk, err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -254,7 +254,7 @@ func TestVersionedEncoding(t *testing.T) {
 | 
			
		||||
	cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{}))
 | 
			
		||||
	encoder, _ := cf.SerializerForFileExtension("json")
 | 
			
		||||
 | 
			
		||||
	codec := cf.CodecForVersions(encoder, nil, []unversioned.GroupVersion{{Version: "v2"}}, nil)
 | 
			
		||||
	codec := cf.CodecForVersions(encoder, nil, unversioned.GroupVersion{Version: "v2"}, nil)
 | 
			
		||||
	out, err := runtime.Encode(codec, &TestType1{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
@@ -263,19 +263,19 @@ func TestVersionedEncoding(t *testing.T) {
 | 
			
		||||
		t.Fatal(string(out))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	codec = cf.CodecForVersions(encoder, nil, []unversioned.GroupVersion{{Version: "v3"}}, nil)
 | 
			
		||||
	codec = cf.CodecForVersions(encoder, nil, unversioned.GroupVersion{Version: "v3"}, nil)
 | 
			
		||||
	_, err = runtime.Encode(codec, &TestType1{})
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// unversioned encode with no versions is written directly to wire
 | 
			
		||||
	codec = cf.CodecForVersions(encoder, nil, nil, nil)
 | 
			
		||||
	codec = cf.CodecForVersions(encoder, nil, runtime.InternalGroupVersioner, nil)
 | 
			
		||||
	out, err = runtime.Encode(codec, &TestType1{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if string(out) != `{"myVersionKey":"__internal","myKindKey":"TestType1"}`+"\n" {
 | 
			
		||||
	if string(out) != `{}`+"\n" {
 | 
			
		||||
		t.Fatal(string(out))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ limitations under the License.
 | 
			
		||||
package serializer
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -48,10 +47,10 @@ func (n *negotiatedSerializerWrapper) StreamingSerializerForMediaType(mediaType
 | 
			
		||||
	return n.streamInfo, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *negotiatedSerializerWrapper) EncoderForVersion(e runtime.Encoder, _ unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
func (n *negotiatedSerializerWrapper) EncoderForVersion(e runtime.Encoder, _ runtime.GroupVersioner) runtime.Encoder {
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *negotiatedSerializerWrapper) DecoderToVersion(d runtime.Decoder, _gv unversioned.GroupVersion) runtime.Decoder {
 | 
			
		||||
func (n *negotiatedSerializerWrapper) DecoderToVersion(d runtime.Decoder, _gv runtime.GroupVersioner) runtime.Decoder {
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,59 +17,20 @@ limitations under the License.
 | 
			
		||||
package versioning
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// EnableCrossGroupDecoding modifies the given decoder in place, if it is a codec
 | 
			
		||||
// from this package. It allows objects from one group to be auto-decoded into
 | 
			
		||||
// another group. 'destGroup' must already exist in the codec.
 | 
			
		||||
// TODO: this is an encapsulation violation and should be refactored
 | 
			
		||||
func EnableCrossGroupDecoding(d runtime.Decoder, sourceGroup, destGroup string) error {
 | 
			
		||||
	internal, ok := d.(*codec)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("unsupported decoder type")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dest, ok := internal.decodeVersion[destGroup]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("group %q is not a possible destination group in the given codec", destGroup)
 | 
			
		||||
	}
 | 
			
		||||
	internal.decodeVersion[sourceGroup] = dest
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnableCrossGroupEncoding modifies the given encoder in place, if it is a codec
 | 
			
		||||
// from this package. It allows objects from one group to be auto-decoded into
 | 
			
		||||
// another group. 'destGroup' must already exist in the codec.
 | 
			
		||||
// TODO: this is an encapsulation violation and should be refactored
 | 
			
		||||
func EnableCrossGroupEncoding(e runtime.Encoder, sourceGroup, destGroup string) error {
 | 
			
		||||
	internal, ok := e.(*codec)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("unsupported encoder type")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dest, ok := internal.encodeVersion[destGroup]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("group %q is not a possible destination group in the given codec", destGroup)
 | 
			
		||||
	}
 | 
			
		||||
	internal.encodeVersion[sourceGroup] = dest
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewCodecForScheme is a convenience method for callers that are using a scheme.
 | 
			
		||||
func NewCodecForScheme(
 | 
			
		||||
	// TODO: I should be a scheme interface?
 | 
			
		||||
	scheme *runtime.Scheme,
 | 
			
		||||
	encoder runtime.Encoder,
 | 
			
		||||
	decoder runtime.Decoder,
 | 
			
		||||
	encodeVersion []unversioned.GroupVersion,
 | 
			
		||||
	decodeVersion []unversioned.GroupVersion,
 | 
			
		||||
	encodeVersion runtime.GroupVersioner,
 | 
			
		||||
	decodeVersion runtime.GroupVersioner,
 | 
			
		||||
) runtime.Codec {
 | 
			
		||||
	return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, scheme, encodeVersion, decodeVersion)
 | 
			
		||||
}
 | 
			
		||||
@@ -84,8 +45,8 @@ func NewCodec(
 | 
			
		||||
	creater runtime.ObjectCreater,
 | 
			
		||||
	copier runtime.ObjectCopier,
 | 
			
		||||
	typer runtime.ObjectTyper,
 | 
			
		||||
	encodeVersion []unversioned.GroupVersion,
 | 
			
		||||
	decodeVersion []unversioned.GroupVersion,
 | 
			
		||||
	encodeVersion runtime.GroupVersioner,
 | 
			
		||||
	decodeVersion runtime.GroupVersioner,
 | 
			
		||||
) runtime.Codec {
 | 
			
		||||
	internal := &codec{
 | 
			
		||||
		encoder:   encoder,
 | 
			
		||||
@@ -94,33 +55,10 @@ func NewCodec(
 | 
			
		||||
		creater:   creater,
 | 
			
		||||
		copier:    copier,
 | 
			
		||||
		typer:     typer,
 | 
			
		||||
	}
 | 
			
		||||
	if encodeVersion != nil {
 | 
			
		||||
		internal.encodeVersion = make(map[string]unversioned.GroupVersion)
 | 
			
		||||
		for _, v := range encodeVersion {
 | 
			
		||||
			// first one for a group wins.  This is consistent with best to worst order throughout the codebase
 | 
			
		||||
			if _, ok := internal.encodeVersion[v.Group]; ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			internal.encodeVersion[v.Group] = v
 | 
			
		||||
		}
 | 
			
		||||
		if len(internal.encodeVersion) == 1 {
 | 
			
		||||
			for _, v := range internal.encodeVersion {
 | 
			
		||||
				internal.preferredEncodeVersion = []unversioned.GroupVersion{v}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if decodeVersion != nil {
 | 
			
		||||
		internal.decodeVersion = make(map[string]unversioned.GroupVersion)
 | 
			
		||||
		for _, v := range decodeVersion {
 | 
			
		||||
			// first one for a group wins.  This is consistent with best to worst order throughout the codebase
 | 
			
		||||
			if _, ok := internal.decodeVersion[v.Group]; ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			internal.decodeVersion[v.Group] = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		encodeVersion: encodeVersion,
 | 
			
		||||
		decodeVersion: decodeVersion,
 | 
			
		||||
	}
 | 
			
		||||
	return internal
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -132,10 +70,8 @@ type codec struct {
 | 
			
		||||
	copier    runtime.ObjectCopier
 | 
			
		||||
	typer     runtime.ObjectTyper
 | 
			
		||||
 | 
			
		||||
	encodeVersion map[string]unversioned.GroupVersion
 | 
			
		||||
	decodeVersion map[string]unversioned.GroupVersion
 | 
			
		||||
 | 
			
		||||
	preferredEncodeVersion []unversioned.GroupVersion
 | 
			
		||||
	encodeVersion runtime.GroupVersioner
 | 
			
		||||
	decodeVersion runtime.GroupVersioner
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decode attempts a decode of the object, then tries to convert it to the internal version. If into is provided and the decoding is
 | 
			
		||||
@@ -152,6 +88,12 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
 | 
			
		||||
		return nil, gvk, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if d, ok := obj.(runtime.NestedObjectDecoder); ok {
 | 
			
		||||
		if err := d.DecodeNestedObjects(DirectDecoder{c.decoder}); err != nil {
 | 
			
		||||
			return nil, gvk, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if we specify a target, use generic conversion.
 | 
			
		||||
	if into != nil {
 | 
			
		||||
		if into == obj {
 | 
			
		||||
@@ -160,7 +102,7 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
 | 
			
		||||
			}
 | 
			
		||||
			return into, gvk, nil
 | 
			
		||||
		}
 | 
			
		||||
		if err := c.convertor.Convert(obj, into); err != nil {
 | 
			
		||||
		if err := c.convertor.Convert(obj, into, c.decodeVersion); err != nil {
 | 
			
		||||
			return nil, gvk, err
 | 
			
		||||
		}
 | 
			
		||||
		if isVersioned {
 | 
			
		||||
@@ -170,37 +112,7 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
 | 
			
		||||
		return into, gvk, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// invoke a version conversion
 | 
			
		||||
	group := gvk.Group
 | 
			
		||||
	if defaultGVK != nil {
 | 
			
		||||
		group = defaultGVK.Group
 | 
			
		||||
	}
 | 
			
		||||
	var targetGV unversioned.GroupVersion
 | 
			
		||||
	if c.decodeVersion == nil {
 | 
			
		||||
		// convert to internal by default
 | 
			
		||||
		targetGV.Group = group
 | 
			
		||||
		targetGV.Version = runtime.APIVersionInternal
 | 
			
		||||
	} else {
 | 
			
		||||
		gv, ok := c.decodeVersion[group]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			// unknown objects are left in their original version
 | 
			
		||||
			if isVersioned {
 | 
			
		||||
				versioned.Objects = []runtime.Object{obj}
 | 
			
		||||
				return versioned, gvk, nil
 | 
			
		||||
			}
 | 
			
		||||
			return obj, gvk, nil
 | 
			
		||||
		}
 | 
			
		||||
		targetGV = gv
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if gvk.GroupVersion() == targetGV {
 | 
			
		||||
		if isVersioned {
 | 
			
		||||
			versioned.Objects = []runtime.Object{obj}
 | 
			
		||||
			return versioned, gvk, nil
 | 
			
		||||
		}
 | 
			
		||||
		return obj, gvk, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Convert if needed.
 | 
			
		||||
	if isVersioned {
 | 
			
		||||
		// create a copy, because ConvertToVersion does not guarantee non-mutation of objects
 | 
			
		||||
		copied, err := c.copier.Copy(obj)
 | 
			
		||||
@@ -209,14 +121,14 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
 | 
			
		||||
		}
 | 
			
		||||
		versioned.Objects = []runtime.Object{copied}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Convert if needed.
 | 
			
		||||
	out, err := c.convertor.ConvertToVersion(obj, targetGV)
 | 
			
		||||
	out, err := c.convertor.ConvertToVersion(obj, c.decodeVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, gvk, err
 | 
			
		||||
	}
 | 
			
		||||
	if isVersioned {
 | 
			
		||||
		versioned.Objects = append(versioned.Objects, out)
 | 
			
		||||
		if versioned.Last() != out {
 | 
			
		||||
			versioned.Objects = append(versioned.Objects, out)
 | 
			
		||||
		}
 | 
			
		||||
		return versioned, gvk, nil
 | 
			
		||||
	}
 | 
			
		||||
	return out, gvk, nil
 | 
			
		||||
@@ -225,51 +137,86 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
 | 
			
		||||
// Encode ensures the provided object is output in the appropriate group and version, invoking
 | 
			
		||||
// conversion if necessary. Unversioned objects (according to the ObjectTyper) are output as is.
 | 
			
		||||
func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
 | 
			
		||||
	if _, ok := obj.(*runtime.Unknown); ok {
 | 
			
		||||
	switch obj.(type) {
 | 
			
		||||
	case *runtime.Unknown, *runtime.Unstructured, *runtime.UnstructuredList:
 | 
			
		||||
		return c.encoder.Encode(obj, w)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gvks, isUnversioned, err := c.typer.ObjectKinds(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	gvk := gvks[0]
 | 
			
		||||
 | 
			
		||||
	if c.encodeVersion == nil || isUnversioned {
 | 
			
		||||
		if e, ok := obj.(runtime.NestedObjectEncoder); ok {
 | 
			
		||||
			if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		objectKind := obj.GetObjectKind()
 | 
			
		||||
		old := objectKind.GroupVersionKind()
 | 
			
		||||
		objectKind.SetGroupVersionKind(gvk)
 | 
			
		||||
		objectKind.SetGroupVersionKind(gvks[0])
 | 
			
		||||
		err = c.encoder.Encode(obj, w)
 | 
			
		||||
		objectKind.SetGroupVersionKind(old)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	targetGV, ok := c.encodeVersion[gvk.Group]
 | 
			
		||||
 | 
			
		||||
	// attempt a conversion to the sole encode version
 | 
			
		||||
	if !ok && c.preferredEncodeVersion != nil {
 | 
			
		||||
		ok = true
 | 
			
		||||
		targetGV = c.preferredEncodeVersion[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if no fallback is available, error
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("the codec does not recognize group %q for kind %q and cannot encode it", gvk.Group, gvk.Kind)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Perform a conversion if necessary
 | 
			
		||||
	objectKind := obj.GetObjectKind()
 | 
			
		||||
	old := objectKind.GroupVersionKind()
 | 
			
		||||
	out, err := c.convertor.ConvertToVersion(obj, targetGV)
 | 
			
		||||
	out, err := c.convertor.ConvertToVersion(obj, c.encodeVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if ok {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if e, ok := out.(runtime.NestedObjectEncoder); ok {
 | 
			
		||||
		if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		obj = out
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Conversion is responsible for setting the proper group, version, and kind onto the outgoing object
 | 
			
		||||
	err = c.encoder.Encode(obj, w)
 | 
			
		||||
	err = c.encoder.Encode(out, w)
 | 
			
		||||
	// restore the old GVK, in case conversion returned the same object
 | 
			
		||||
	objectKind.SetGroupVersionKind(old)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DirectEncoder serializes an object and ensures the GVK is set.
 | 
			
		||||
type DirectEncoder struct {
 | 
			
		||||
	runtime.Encoder
 | 
			
		||||
	runtime.ObjectTyper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encode does not do conversion. It sets the gvk during serialization.
 | 
			
		||||
func (e DirectEncoder) Encode(obj runtime.Object, stream io.Writer) error {
 | 
			
		||||
	gvks, _, err := e.ObjectTyper.ObjectKinds(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if runtime.IsNotRegisteredError(err) {
 | 
			
		||||
			return e.Encoder.Encode(obj, stream)
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	kind := obj.GetObjectKind()
 | 
			
		||||
	oldGVK := kind.GroupVersionKind()
 | 
			
		||||
	kind.SetGroupVersionKind(gvks[0])
 | 
			
		||||
	err = e.Encoder.Encode(obj, stream)
 | 
			
		||||
	kind.SetGroupVersionKind(oldGVK)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DirectDecoder clears the group version kind of a deserialized object.
 | 
			
		||||
type DirectDecoder struct {
 | 
			
		||||
	runtime.Decoder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decode does not do conversion. It removes the gvk during deserialization.
 | 
			
		||||
func (d DirectDecoder) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
 | 
			
		||||
	obj, gvk, err := d.Decoder.Decode(data, defaults, into)
 | 
			
		||||
	if obj != nil {
 | 
			
		||||
		kind := obj.GetObjectKind()
 | 
			
		||||
		// clearing the gvk is just a convention of a codec
 | 
			
		||||
		kind.SetGroupVersionKind(unversioned.GroupVersionKind{})
 | 
			
		||||
	}
 | 
			
		||||
	return obj, gvk, err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ package versioning
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +38,60 @@ func (d *testDecodable) GetObjectKind() unversioned.ObjectKind                {
 | 
			
		||||
func (d *testDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
 | 
			
		||||
func (d *testDecodable) GroupVersionKind() unversioned.GroupVersionKind       { return d.gvk }
 | 
			
		||||
 | 
			
		||||
type testNestedDecodable struct {
 | 
			
		||||
	Other string
 | 
			
		||||
	Value int `json:"value"`
 | 
			
		||||
 | 
			
		||||
	gvk          unversioned.GroupVersionKind
 | 
			
		||||
	nestedCalled bool
 | 
			
		||||
	nestedErr    error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *testNestedDecodable) GetObjectKind() unversioned.ObjectKind                { return d }
 | 
			
		||||
func (d *testNestedDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
 | 
			
		||||
func (d *testNestedDecodable) GroupVersionKind() unversioned.GroupVersionKind       { return d.gvk }
 | 
			
		||||
 | 
			
		||||
func (d *testNestedDecodable) EncodeNestedObjects(e runtime.Encoder) error {
 | 
			
		||||
	d.nestedCalled = true
 | 
			
		||||
	return d.nestedErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error {
 | 
			
		||||
	d.nestedCalled = true
 | 
			
		||||
	return d.nestedErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNestedDecode(t *testing.T) {
 | 
			
		||||
	n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
 | 
			
		||||
	decoder := &mockSerializer{obj: n}
 | 
			
		||||
	codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil)
 | 
			
		||||
	if _, _, err := codec.Decode([]byte(`{}`), nil, n); err != n.nestedErr {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if !n.nestedCalled {
 | 
			
		||||
		t.Errorf("did not invoke nested decoder")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNestedEncode(t *testing.T) {
 | 
			
		||||
	n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")}
 | 
			
		||||
	n2 := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode 2")}
 | 
			
		||||
	encoder := &mockSerializer{obj: n}
 | 
			
		||||
	codec := NewCodec(
 | 
			
		||||
		encoder, nil,
 | 
			
		||||
		&checkConvertor{obj: n2, groupVersion: unversioned.GroupVersion{Group: "other"}},
 | 
			
		||||
		nil, nil,
 | 
			
		||||
		&mockTyper{gvks: []unversioned.GroupVersionKind{{Kind: "test"}}},
 | 
			
		||||
		unversioned.GroupVersion{Group: "other"}, nil,
 | 
			
		||||
	)
 | 
			
		||||
	if err := codec.Encode(n, ioutil.Discard); err != n2.nestedErr {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if n.nestedCalled || !n2.nestedCalled {
 | 
			
		||||
		t.Errorf("did not invoke correct nested decoder")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDecode(t *testing.T) {
 | 
			
		||||
	gvk1 := &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}
 | 
			
		||||
	decodable1 := &testDecodable{}
 | 
			
		||||
@@ -53,7 +108,7 @@ func TestDecode(t *testing.T) {
 | 
			
		||||
		yaml       bool
 | 
			
		||||
		pretty     bool
 | 
			
		||||
 | 
			
		||||
		encodes, decodes []unversioned.GroupVersion
 | 
			
		||||
		encodes, decodes runtime.GroupVersioner
 | 
			
		||||
 | 
			
		||||
		defaultGVK *unversioned.GroupVersionKind
 | 
			
		||||
		into       runtime.Object
 | 
			
		||||
@@ -67,12 +122,14 @@ func TestDecode(t *testing.T) {
 | 
			
		||||
			serializer:  &mockSerializer{actual: gvk1},
 | 
			
		||||
			convertor:   &checkConvertor{groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
 | 
			
		||||
			expectedGVK: gvk1,
 | 
			
		||||
			decodes:     unversioned.GroupVersion{Group: "other", Version: "__internal"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			serializer:  &mockSerializer{actual: gvk1, obj: decodable1},
 | 
			
		||||
			convertor:   &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
 | 
			
		||||
			expectedGVK: gvk1,
 | 
			
		||||
			sameObject:  decodable2,
 | 
			
		||||
			decodes:     unversioned.GroupVersion{Group: "other", Version: "__internal"},
 | 
			
		||||
		},
 | 
			
		||||
		// defaultGVK.Group is allowed to force a conversion to the destination group
 | 
			
		||||
		{
 | 
			
		||||
@@ -81,6 +138,7 @@ func TestDecode(t *testing.T) {
 | 
			
		||||
			convertor:   &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "force", Version: "__internal"}},
 | 
			
		||||
			expectedGVK: gvk1,
 | 
			
		||||
			sameObject:  decodable2,
 | 
			
		||||
			decodes:     unversioned.GroupVersion{Group: "force", Version: "__internal"},
 | 
			
		||||
		},
 | 
			
		||||
		// uses direct conversion for into when objects differ
 | 
			
		||||
		{
 | 
			
		||||
@@ -121,6 +179,7 @@ func TestDecode(t *testing.T) {
 | 
			
		||||
			convertor:      &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
 | 
			
		||||
			expectedGVK:    gvk1,
 | 
			
		||||
			expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
 | 
			
		||||
			decodes:        unversioned.GroupVersion{Group: "other", Version: "__internal"},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
 | 
			
		||||
@@ -130,38 +189,45 @@ func TestDecode(t *testing.T) {
 | 
			
		||||
			convertor:      &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
 | 
			
		||||
			expectedGVK:    gvk1,
 | 
			
		||||
			expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
 | 
			
		||||
			decodes:        unversioned.GroupVersion{Group: "other", Version: "__internal"},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// decode into the same version as the serialized object
 | 
			
		||||
		{
 | 
			
		||||
			decodes: []unversioned.GroupVersion{gvk1.GroupVersion()},
 | 
			
		||||
			decodes: unversioned.GroupVersions{gvk1.GroupVersion()},
 | 
			
		||||
 | 
			
		||||
			serializer:     &mockSerializer{actual: gvk1, obj: decodable1},
 | 
			
		||||
			convertor:      &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "other", Version: "blah"}}},
 | 
			
		||||
			expectedGVK:    gvk1,
 | 
			
		||||
			expectedObject: decodable1,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			into:    &runtime.VersionedObjects{Objects: []runtime.Object{}},
 | 
			
		||||
			decodes: []unversioned.GroupVersion{gvk1.GroupVersion()},
 | 
			
		||||
			decodes: unversioned.GroupVersions{gvk1.GroupVersion()},
 | 
			
		||||
 | 
			
		||||
			serializer:     &mockSerializer{actual: gvk1, obj: decodable1},
 | 
			
		||||
			convertor:      &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "other", Version: "blah"}}},
 | 
			
		||||
			copier:         &checkCopy{in: decodable1, obj: decodable1, err: nil},
 | 
			
		||||
			expectedGVK:    gvk1,
 | 
			
		||||
			expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// codec with non matching version skips conversion altogether
 | 
			
		||||
		{
 | 
			
		||||
			decodes: []unversioned.GroupVersion{{Group: "something", Version: "else"}},
 | 
			
		||||
			decodes: unversioned.GroupVersions{{Group: "something", Version: "else"}},
 | 
			
		||||
 | 
			
		||||
			serializer:     &mockSerializer{actual: gvk1, obj: decodable1},
 | 
			
		||||
			convertor:      &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "something", Version: "else"}}},
 | 
			
		||||
			expectedGVK:    gvk1,
 | 
			
		||||
			expectedObject: decodable1,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			into:    &runtime.VersionedObjects{Objects: []runtime.Object{}},
 | 
			
		||||
			decodes: []unversioned.GroupVersion{{Group: "something", Version: "else"}},
 | 
			
		||||
			decodes: unversioned.GroupVersions{{Group: "something", Version: "else"}},
 | 
			
		||||
 | 
			
		||||
			serializer:     &mockSerializer{actual: gvk1, obj: decodable1},
 | 
			
		||||
			convertor:      &checkConvertor{in: decodable1, obj: decodable1, groupVersion: unversioned.GroupVersions{{Group: "something", Version: "else"}}},
 | 
			
		||||
			copier:         &checkCopy{in: decodable1, obj: decodable1, err: nil},
 | 
			
		||||
			expectedGVK:    gvk1,
 | 
			
		||||
			expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}},
 | 
			
		||||
		},
 | 
			
		||||
@@ -228,11 +294,11 @@ func (c *checkCopy) Copy(obj runtime.Object) (runtime.Object, error) {
 | 
			
		||||
type checkConvertor struct {
 | 
			
		||||
	err           error
 | 
			
		||||
	in, obj       runtime.Object
 | 
			
		||||
	groupVersion  unversioned.GroupVersion
 | 
			
		||||
	groupVersion  runtime.GroupVersioner
 | 
			
		||||
	directConvert bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *checkConvertor) Convert(in, out interface{}) error {
 | 
			
		||||
func (c *checkConvertor) Convert(in, out, context interface{}) error {
 | 
			
		||||
	if !c.directConvert {
 | 
			
		||||
		return fmt.Errorf("unexpected call to Convert")
 | 
			
		||||
	}
 | 
			
		||||
@@ -244,15 +310,15 @@ func (c *checkConvertor) Convert(in, out interface{}) error {
 | 
			
		||||
	}
 | 
			
		||||
	return c.err
 | 
			
		||||
}
 | 
			
		||||
func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion unversioned.GroupVersion) (out runtime.Object, err error) {
 | 
			
		||||
func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion runtime.GroupVersioner) (out runtime.Object, err error) {
 | 
			
		||||
	if c.directConvert {
 | 
			
		||||
		return nil, fmt.Errorf("unexpected call to ConvertToVersion")
 | 
			
		||||
	}
 | 
			
		||||
	if c.in != nil && c.in != in {
 | 
			
		||||
		return nil, fmt.Errorf("unexpected in: %s", in)
 | 
			
		||||
	}
 | 
			
		||||
	if c.groupVersion != outVersion {
 | 
			
		||||
		return nil, fmt.Errorf("unexpected outversion: %s", outVersion)
 | 
			
		||||
	if !reflect.DeepEqual(c.groupVersion, outVersion) {
 | 
			
		||||
		return nil, fmt.Errorf("unexpected outversion: %s (%s)", outVersion, c.groupVersion)
 | 
			
		||||
	}
 | 
			
		||||
	return c.obj, c.err
 | 
			
		||||
}
 | 
			
		||||
@@ -289,10 +355,15 @@ func (c *mockCreater) New(kind unversioned.GroupVersionKind) (runtime.Object, er
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mockTyper struct {
 | 
			
		||||
	gvk *unversioned.GroupVersionKind
 | 
			
		||||
	err error
 | 
			
		||||
	gvks        []unversioned.GroupVersionKind
 | 
			
		||||
	unversioned bool
 | 
			
		||||
	err         error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *mockTyper) ObjectKind(obj runtime.Object) (*unversioned.GroupVersionKind, bool, error) {
 | 
			
		||||
	return t.gvk, false, t.err
 | 
			
		||||
func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersionKind, bool, error) {
 | 
			
		||||
	return t.gvks, t.unversioned, t.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *mockTyper) Recognizes(_ unversioned.GroupVersionKind) bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -168,7 +168,7 @@ func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList
 | 
			
		||||
// sane implementation for APIs that require an object converter.
 | 
			
		||||
type UnstructuredObjectConverter struct{}
 | 
			
		||||
 | 
			
		||||
func (UnstructuredObjectConverter) Convert(in, out interface{}) error {
 | 
			
		||||
func (UnstructuredObjectConverter) Convert(in, out, context interface{}) error {
 | 
			
		||||
	unstructIn, ok := in.(*Unstructured)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("input type %T in not valid for unstructured conversion", in)
 | 
			
		||||
@@ -187,9 +187,14 @@ func (UnstructuredObjectConverter) Convert(in, out interface{}) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (UnstructuredObjectConverter) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
 | 
			
		||||
	if gvk := in.GetObjectKind().GroupVersionKind(); gvk.GroupVersion() != outVersion {
 | 
			
		||||
		return nil, errors.New("unstructured converter cannot convert versions")
 | 
			
		||||
func (UnstructuredObjectConverter) ConvertToVersion(in Object, target GroupVersioner) (Object, error) {
 | 
			
		||||
	if kind := in.GetObjectKind().GroupVersionKind(); !kind.IsEmpty() {
 | 
			
		||||
		gvk, ok := target.KindForGroupVersionKinds([]unversioned.GroupVersionKind{kind})
 | 
			
		||||
		if !ok {
 | 
			
		||||
			// TODO: should this be a typed error?
 | 
			
		||||
			return nil, fmt.Errorf("%v is unstructured and is not suitable for converting to %q", kind, target)
 | 
			
		||||
		}
 | 
			
		||||
		in.GetObjectKind().SetGroupVersionKind(gvk)
 | 
			
		||||
	}
 | 
			
		||||
	return in, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,14 +30,13 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var status = &unversioned.Status{
 | 
			
		||||
	Status:  unversioned.StatusFailure,
 | 
			
		||||
	Code:    200,
 | 
			
		||||
	Reason:  unversioned.StatusReasonUnknown,
 | 
			
		||||
	Message: "",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestV1EncodeDecodeStatus(t *testing.T) {
 | 
			
		||||
	status := &unversioned.Status{
 | 
			
		||||
		Status:  unversioned.StatusFailure,
 | 
			
		||||
		Code:    200,
 | 
			
		||||
		Reason:  unversioned.StatusReasonUnknown,
 | 
			
		||||
		Message: "",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v1Codec := testapi.Default.Codec()
 | 
			
		||||
 | 
			
		||||
@@ -65,6 +64,12 @@ func TestV1EncodeDecodeStatus(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestExperimentalEncodeDecodeStatus(t *testing.T) {
 | 
			
		||||
	status := &unversioned.Status{
 | 
			
		||||
		Status:  unversioned.StatusFailure,
 | 
			
		||||
		Code:    200,
 | 
			
		||||
		Reason:  unversioned.StatusReasonUnknown,
 | 
			
		||||
		Message: "",
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: caesarxuchao: use the testapi.Extensions.Codec() once the PR that
 | 
			
		||||
	// moves experimental from v1 to v1beta1 got merged.
 | 
			
		||||
	expCodec := api.Codecs.LegacyCodec(extensions.SchemeGroupVersion)
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ type SchedulerServer struct {
 | 
			
		||||
// NewSchedulerServer creates a new SchedulerServer with default parameters
 | 
			
		||||
func NewSchedulerServer() *SchedulerServer {
 | 
			
		||||
	config := componentconfig.KubeSchedulerConfiguration{}
 | 
			
		||||
	api.Scheme.Convert(&v1alpha1.KubeSchedulerConfiguration{}, &config)
 | 
			
		||||
	api.Scheme.Convert(&v1alpha1.KubeSchedulerConfiguration{}, &config, nil)
 | 
			
		||||
	config.LeaderElection.LeaderElect = true
 | 
			
		||||
	s := SchedulerServer{
 | 
			
		||||
		KubeSchedulerConfiguration: config,
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ func init() {
 | 
			
		||||
		api.Scheme,
 | 
			
		||||
		jsonSerializer,
 | 
			
		||||
		jsonSerializer,
 | 
			
		||||
		[]unversioned.GroupVersion{{Version: Version}},
 | 
			
		||||
		[]unversioned.GroupVersion{{Version: runtime.APIVersionInternal}},
 | 
			
		||||
		unversioned.GroupVersion{Version: Version},
 | 
			
		||||
		runtime.InternalGroupVersioner,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ limitations under the License.
 | 
			
		||||
package framework
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime/serializer/versioning"
 | 
			
		||||
)
 | 
			
		||||
@@ -58,10 +57,10 @@ func (s *wrappedSerializer) UniversalDeserializer() runtime.Decoder {
 | 
			
		||||
	return s.serializer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *wrappedSerializer) EncoderForVersion(encoder runtime.Encoder, gv unversioned.GroupVersion) runtime.Encoder {
 | 
			
		||||
	return versioning.NewCodec(encoder, nil, s.scheme, s.scheme, s.scheme, s.scheme, []unversioned.GroupVersion{gv}, nil)
 | 
			
		||||
func (s *wrappedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
 | 
			
		||||
	return versioning.NewCodec(encoder, nil, s.scheme, s.scheme, s.scheme, s.scheme, gv, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *wrappedSerializer) DecoderToVersion(decoder runtime.Decoder, gv unversioned.GroupVersion) runtime.Decoder {
 | 
			
		||||
	return versioning.NewCodec(nil, decoder, s.scheme, s.scheme, s.scheme, s.scheme, nil, []unversioned.GroupVersion{gv})
 | 
			
		||||
func (s *wrappedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
 | 
			
		||||
	return versioning.NewCodec(nil, decoder, s.scheme, s.scheme, s.scheme, s.scheme, nil, gv)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user