mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 12:07:47 +00:00
let encoder handle unversioned objects
address lavalamp's comments address lavalamp's comments address lavalamp's comments add a TODO based on lavalamp's comment add a TODO based on lavalamp's comment
This commit is contained in:
parent
9537c43a62
commit
ab5c1f6710
@ -19,6 +19,7 @@ package conversion
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
)
|
||||
|
||||
// EncodeToVersion turns the given api object into an appropriate JSON string.
|
||||
@ -52,6 +53,14 @@ import (
|
||||
func (s *Scheme) EncodeToVersion(obj interface{}, destVersion string) (data []byte, err error) {
|
||||
obj = maybeCopy(obj)
|
||||
v, _ := EnforcePtr(obj) // maybeCopy guarantees a pointer
|
||||
|
||||
// Don't encode an object defined in the unversioned package, unless if the
|
||||
// destVersion is v1, encode it to v1 for backward compatibility.
|
||||
pkg := path.Base(v.Type().PkgPath())
|
||||
if pkg == "unversioned" && destVersion != "v1" {
|
||||
return s.encodeUnversionedObject(obj)
|
||||
}
|
||||
|
||||
if _, registered := s.typeToVersion[v.Type()]; !registered {
|
||||
return nil, fmt.Errorf("type %v is not registered for %q and it will be impossible to Decode it, therefore Encode will refuse to encode it.", v.Type(), destVersion)
|
||||
}
|
||||
@ -102,3 +111,21 @@ func (s *Scheme) EncodeToVersion(obj interface{}, destVersion string) (data []by
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (s *Scheme) encodeUnversionedObject(obj interface{}) (data []byte, err error) {
|
||||
_, objKind, err := s.ObjectVersionAndKind(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = s.SetVersionAndKind("", objKind, obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Version and Kind should be blank in memory. Reset them, since it's
|
||||
// possible that we modified a user object and not a copy above.
|
||||
err = s.SetVersionAndKind("", "", obj)
|
||||
return data, nil
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package conversion
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@ -77,6 +78,7 @@ func UpdateVersionAndKind(baseFields []string, versionField, version, kindField,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkg := path.Base(v.Type().PkgPath())
|
||||
t := v.Type()
|
||||
name := t.Name()
|
||||
if v.Kind() != reflect.Struct {
|
||||
@ -93,6 +95,15 @@ func UpdateVersionAndKind(baseFields []string, versionField, version, kindField,
|
||||
|
||||
field := v.FieldByName(kindField)
|
||||
if !field.IsValid() {
|
||||
// Types defined in the unversioned package are allowed to not have a
|
||||
// kindField. Clients will have to know what they are based on the
|
||||
// context.
|
||||
// TODO: add some type trait here, or some way of indicating whether
|
||||
// this feature is allowed on a per-type basis. Using package name is
|
||||
// overly broad and a bit hacky.
|
||||
if pkg == "unversioned" {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("couldn't find %v field in %#v", kindField, v.Interface())
|
||||
}
|
||||
field.SetString(kind)
|
||||
|
@ -17,8 +17,11 @@ limitations under the License.
|
||||
package conversion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
)
|
||||
|
||||
func TestSimpleMetaFactoryInterpret(t *testing.T) {
|
||||
@ -72,6 +75,25 @@ func TestSimpleMetaFactoryUpdate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test Updating objects that don't have a Kind field.
|
||||
func TestSimpleMetaFactoryUpdateNoKindField(t *testing.T) {
|
||||
factory := SimpleMetaFactory{VersionField: "APIVersion", KindField: "Kind"}
|
||||
// obj does not have a Kind field and is not defined in the unversioned package.
|
||||
obj := struct {
|
||||
SomeField string
|
||||
}{"1"}
|
||||
expectedError := fmt.Errorf("couldn't find %v field in %#v", factory.KindField, obj)
|
||||
if err := factory.Update("test", "other", &obj); err == nil || expectedError.Error() != err.Error() {
|
||||
t.Fatalf("expected error: %v, got: %v", expectedError, err)
|
||||
}
|
||||
|
||||
// ListMeta does not have a Kind field, but is defined in the unversioned package.
|
||||
listMeta := unversioned.ListMeta{}
|
||||
if err := factory.Update("test", "other", &listMeta); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleMetaFactoryUpdateStruct(t *testing.T) {
|
||||
factory := SimpleMetaFactory{BaseFields: []string{"Test"}, VersionField: "V", KindField: "K"}
|
||||
|
||||
|
92
pkg/conversion/unversioned_test.go
Normal file
92
pkg/conversion/unversioned_test.go
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package conversion_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
// TODO: Ideally we should create the necessary package structure in e.g.,
|
||||
// pkg/conversion/test/... instead of importing pkg/api here.
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
var status = &unversioned.Status{
|
||||
Status: unversioned.StatusFailure,
|
||||
Code: 200,
|
||||
Reason: unversioned.StatusReasonUnknown,
|
||||
Message: "",
|
||||
}
|
||||
|
||||
func TestV1EncodeDecodeStatus(t *testing.T) {
|
||||
|
||||
v1Codec := testapi.Default.Codec()
|
||||
|
||||
encoded, err := v1Codec.Encode(status)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
typeMeta := unversioned.TypeMeta{}
|
||||
if err := json.Unmarshal(encoded, &typeMeta); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if typeMeta.Kind != "Status" {
|
||||
t.Errorf("Kind is not set to \"Status\". Got %v", string(encoded))
|
||||
}
|
||||
if typeMeta.APIVersion != "v1" {
|
||||
t.Errorf("APIVersion is not set to \"v1\". Got %v", string(encoded))
|
||||
}
|
||||
decoded, err := v1Codec.Decode(encoded)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(status, decoded) {
|
||||
t.Errorf("expected: %v, got: %v", status, decoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExperimentalEncodeDecodeStatus(t *testing.T) {
|
||||
// TODO: caesarxuchao: use the testapi.Experimental.Codec() once the PR that
|
||||
// moves experimental from v1 to v1alpha1 got merged.
|
||||
// expCodec := testapi.Experimental.Codec()
|
||||
expCodec := runtime.CodecFor(api.Scheme, "experimental/v1alpha1")
|
||||
encoded, err := expCodec.Encode(status)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
typeMeta := unversioned.TypeMeta{}
|
||||
if err := json.Unmarshal(encoded, &typeMeta); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if typeMeta.Kind != "Status" {
|
||||
t.Errorf("Kind is not set to \"Status\". Got %s", encoded)
|
||||
}
|
||||
if typeMeta.APIVersion != "" {
|
||||
t.Errorf("APIVersion is not set to \"\". Got %s", encoded)
|
||||
}
|
||||
decoded, err := expCodec.Decode(encoded)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(status, decoded) {
|
||||
t.Errorf("expected: %v, got: %v", status, decoded)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user