mirror of https://github.com/k3s-io/k3s
Merge pull request #2786 from smarterclayton/load_opaque_objects
Allow runtime.Object to be encoded as runtime.RawExtensionpull/6/head
commit
f81ec248d0
|
@ -25,7 +25,9 @@ import (
|
|||
internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
fuzz "github.com/google/gofuzz"
|
||||
)
|
||||
|
@ -83,6 +85,26 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
|||
// only replicas round trips
|
||||
j.Replicas = int(c.RandUint64())
|
||||
},
|
||||
func(j *internal.List, c fuzz.Continue) {
|
||||
c.Fuzz(&j.ListMeta)
|
||||
c.Fuzz(&j.Items)
|
||||
if j.Items == nil {
|
||||
j.Items = []runtime.Object{}
|
||||
}
|
||||
},
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"},
|
||||
RawJSON: []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`),
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&internal.Pod{}, &internal.ReplicationController{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(intstr *util.IntOrString, c fuzz.Continue) {
|
||||
// util.IntOrString will panic if its kind is set wrong.
|
||||
if c.RandBool() {
|
||||
|
|
|
@ -45,6 +45,7 @@ func init() {
|
|||
&ContainerManifestList{},
|
||||
&BoundPod{},
|
||||
&BoundPods{},
|
||||
&List{},
|
||||
)
|
||||
// Legacy names are supported
|
||||
Scheme.AddKnownTypeWithName("", "Minion", &Node{})
|
||||
|
@ -71,3 +72,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
|
|||
func (*ContainerManifestList) IsAnAPIObject() {}
|
||||
func (*BoundPod) IsAnAPIObject() {}
|
||||
func (*BoundPods) IsAnAPIObject() {}
|
||||
func (*List) IsAnAPIObject() {}
|
||||
|
|
|
@ -48,15 +48,6 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
|||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
|
||||
j.Name = c.RandString()
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(j *api.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
|
@ -99,6 +90,26 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
|||
// only replicas round trips
|
||||
j.Replicas = int(c.RandUint64())
|
||||
},
|
||||
func(j *api.List, c fuzz.Continue) {
|
||||
c.Fuzz(&j.ListMeta)
|
||||
c.Fuzz(&j.Items)
|
||||
if j.Items == nil {
|
||||
j.Items = []runtime.Object{}
|
||||
}
|
||||
},
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"},
|
||||
RawJSON: []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`),
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(intstr *util.IntOrString, c fuzz.Continue) {
|
||||
// util.IntOrString will panic if its kind is set wrong.
|
||||
if c.RandBool() {
|
||||
|
@ -154,7 +165,7 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
|||
|
||||
obj2, err := codec.Decode(data)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
t.Errorf("0: %v: %v\nCodec: %v\nData: %s\nSource: %#v", name, err, codec, string(data), source)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(source, obj2) {
|
||||
|
@ -188,7 +199,21 @@ func TestSpecificKind(t *testing.T) {
|
|||
api.Scheme.Log(nil)
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
api.Scheme.Log(t)
|
||||
kind := "List"
|
||||
item, err := api.Scheme.New("", kind)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't make a %v? %v", kind, err)
|
||||
return
|
||||
}
|
||||
runTest(t, v1beta1.Codec, item)
|
||||
runTest(t, v1beta2.Codec, item)
|
||||
api.Scheme.Log(nil)
|
||||
}
|
||||
|
||||
var nonRoundTrippableTypes = util.NewStringSet("ContainerManifest")
|
||||
var nonInternalRoundTrippableTypes = util.NewStringSet("List")
|
||||
|
||||
func TestRoundTripTypes(t *testing.T) {
|
||||
for kind := range api.Scheme.KnownTypes("") {
|
||||
|
@ -206,7 +231,9 @@ func TestRoundTripTypes(t *testing.T) {
|
|||
}
|
||||
runTest(t, v1beta1.Codec, item)
|
||||
runTest(t, v1beta2.Codec, item)
|
||||
runTest(t, api.Codec, item)
|
||||
if !nonInternalRoundTrippableTypes.Has(kind) {
|
||||
runTest(t, api.Codec, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package api
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -1000,3 +1001,11 @@ type BoundPods struct {
|
|||
// Items is the list of all pods bound to a given host.
|
||||
Items []BoundPod `json:"items"`
|
||||
}
|
||||
|
||||
// List holds a list of objects, which may not be known by the server.
|
||||
type List struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []runtime.Object `json:"items"`
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ func init() {
|
|||
&ContainerManifestList{},
|
||||
&BoundPod{},
|
||||
&BoundPods{},
|
||||
&List{},
|
||||
)
|
||||
// Future names are supported
|
||||
api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
|
||||
|
@ -76,3 +77,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
|
|||
func (*ContainerManifestList) IsAnAPIObject() {}
|
||||
func (*BoundPod) IsAnAPIObject() {}
|
||||
func (*BoundPods) IsAnAPIObject() {}
|
||||
func (*List) IsAnAPIObject() {}
|
||||
|
|
|
@ -19,6 +19,7 @@ package v1beta1
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -782,3 +783,9 @@ type BoundPods struct {
|
|||
// Items is the list of all pods bound to a given host.
|
||||
Items []BoundPod `json:"items" description:"list of all pods bound to a given host"`
|
||||
}
|
||||
|
||||
// List holds a list of objects, which may not be known by the server.
|
||||
type List struct {
|
||||
TypeMeta `json:",inline"`
|
||||
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ func init() {
|
|||
&ContainerManifestList{},
|
||||
&BoundPod{},
|
||||
&BoundPods{},
|
||||
&List{},
|
||||
)
|
||||
// Future names are supported
|
||||
api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
|
||||
|
@ -76,3 +77,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
|
|||
func (*ContainerManifestList) IsAnAPIObject() {}
|
||||
func (*BoundPod) IsAnAPIObject() {}
|
||||
func (*BoundPods) IsAnAPIObject() {}
|
||||
func (*List) IsAnAPIObject() {}
|
||||
|
|
|
@ -19,6 +19,7 @@ package v1beta2
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -783,3 +784,9 @@ type BoundPods struct {
|
|||
// Items is the list of all pods bound to a given host.
|
||||
Items []BoundPod `json:"items" description:"list of all pods bound to a given host"`
|
||||
}
|
||||
|
||||
// List holds a list of objects, which may not be known by the server.
|
||||
type List struct {
|
||||
TypeMeta `json:",inline"`
|
||||
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ func init() {
|
|||
&OperationList{},
|
||||
&Event{},
|
||||
&EventList{},
|
||||
&List{},
|
||||
)
|
||||
// Legacy names are supported
|
||||
api.Scheme.AddKnownTypeWithName("v1beta3", "Minion", &Node{})
|
||||
|
@ -72,3 +73,4 @@ func (*Operation) IsAnAPIObject() {}
|
|||
func (*OperationList) IsAnAPIObject() {}
|
||||
func (*Event) IsAnAPIObject() {}
|
||||
func (*EventList) IsAnAPIObject() {}
|
||||
func (*List) IsAnAPIObject() {}
|
||||
|
|
|
@ -19,6 +19,7 @@ package v1beta3
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -556,9 +557,14 @@ type ReplicationControllerSpec struct {
|
|||
// Selector is a label query over pods that should match the Replicas count.
|
||||
Selector map[string]string `json:"selector,omitempty"`
|
||||
|
||||
// Template is a reference to an object that describes the pod that will be created if
|
||||
// TemplateRef is a reference to an object that describes the pod that will be created if
|
||||
// insufficient replicas are detected.
|
||||
Template ObjectReference `json:"template,omitempty"`
|
||||
TemplateRef *ObjectReference `json:"templateRef,omitempty"`
|
||||
|
||||
// Template is the object that describes the pod that will be created if
|
||||
// insufficient replicas are detected. This takes precedence over a
|
||||
// TemplateRef.
|
||||
Template *PodTemplateSpec `json:"template,omitempty"`
|
||||
}
|
||||
|
||||
// ReplicationControllerStatus represents the current status of a replication
|
||||
|
@ -944,3 +950,11 @@ type EventList struct {
|
|||
|
||||
Items []Event `json:"items"`
|
||||
}
|
||||
|
||||
// List holds a list of objects, which may not be known by the server.
|
||||
type List struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []runtime.RawExtension `json:"items" description:"list of objects"`
|
||||
}
|
||||
|
|
|
@ -49,15 +49,6 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
|||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
|
||||
j.Name = c.RandString()
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(j *api.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
|
|
|
@ -112,7 +112,7 @@ func (s *Scheme) DecodeInto(data []byte, obj interface{}) error {
|
|||
} else {
|
||||
external, err := s.NewObject(dataVersion, dataKind)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create new object of type ('%s', '%s')", dataVersion, dataKind)
|
||||
return err
|
||||
}
|
||||
// yaml is a superset of json, so we use it to decode here. That way,
|
||||
// we understand both.
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. 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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type notRegisteredErr struct {
|
||||
kind string
|
||||
version string
|
||||
t reflect.Type
|
||||
}
|
||||
|
||||
func (k *notRegisteredErr) Error() string {
|
||||
if k.t != nil {
|
||||
return fmt.Sprintf("no kind is registered for the type %v", k.t)
|
||||
}
|
||||
if len(k.kind) == 0 {
|
||||
return fmt.Sprintf("no version %q has been registered", k.version)
|
||||
}
|
||||
if len(k.version) == 0 {
|
||||
return fmt.Sprintf("no kind %q is registered for the default version", k.kind)
|
||||
}
|
||||
return fmt.Sprintf("no kind %q is registered for version %q", k.kind, k.version)
|
||||
}
|
||||
|
||||
// IsNotRegisteredError returns true if the error indicates the provided
|
||||
// object or input data is not registered.
|
||||
func IsNotRegisteredError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := err.(*notRegisteredErr)
|
||||
return ok
|
||||
}
|
|
@ -145,14 +145,14 @@ func (s *Scheme) KnownTypes(version string) map[string]reflect.Type {
|
|||
|
||||
// NewObject returns a new object of the given version and name,
|
||||
// or an error if it hasn't been registered.
|
||||
func (s *Scheme) NewObject(versionName, typeName string) (interface{}, error) {
|
||||
func (s *Scheme) NewObject(versionName, kind string) (interface{}, error) {
|
||||
if types, ok := s.versionMap[versionName]; ok {
|
||||
if t, ok := types[typeName]; ok {
|
||||
if t, ok := types[kind]; ok {
|
||||
return reflect.New(t).Interface(), nil
|
||||
}
|
||||
return nil, fmt.Errorf("no type '%v' for version '%v'", typeName, versionName)
|
||||
return nil, ¬RegisteredErr{kind: kind, version: versionName}
|
||||
}
|
||||
return nil, fmt.Errorf("no version '%v'", versionName)
|
||||
return nil, ¬RegisteredErr{kind: kind, version: versionName}
|
||||
}
|
||||
|
||||
// AddConversionFuncs adds functions to the list of conversion functions. The given
|
||||
|
@ -187,8 +187,7 @@ func (s *Scheme) NewObject(versionName, typeName string) (interface{}, error) {
|
|||
// add conversion functions for things with changed/removed fields.
|
||||
func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
|
||||
for _, f := range conversionFuncs {
|
||||
err := s.converter.Register(f)
|
||||
if err != nil {
|
||||
if err := s.converter.Register(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -286,7 +285,7 @@ func (s *Scheme) ObjectVersionAndKind(obj interface{}) (apiVersion, kind string,
|
|||
version, vOK := s.typeToVersion[t]
|
||||
kinds, kOK := s.typeToKind[t]
|
||||
if !vOK || !kOK {
|
||||
return "", "", fmt.Errorf("unregistered type: %v", t)
|
||||
return "", "", ¬RegisteredErr{t: t}
|
||||
}
|
||||
apiVersion = version
|
||||
kind = kinds[0]
|
||||
|
|
|
@ -22,16 +22,14 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var Codec = runtime.CodecFor(scheme, "v1test")
|
||||
|
||||
type EmbeddedTest struct {
|
||||
runtime.TypeMeta `json:",inline"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Object runtime.EmbeddedObject `json:"object,omitempty"`
|
||||
EmptyObject runtime.EmbeddedObject `json:"emptyObject,omitempty"`
|
||||
runtime.TypeMeta
|
||||
ID string
|
||||
Object runtime.EmbeddedObject
|
||||
EmptyObject runtime.EmbeddedObject
|
||||
}
|
||||
|
||||
type EmbeddedTestExternal struct {
|
||||
|
@ -41,21 +39,91 @@ type EmbeddedTestExternal struct {
|
|||
EmptyObject runtime.RawExtension `json:"emptyObject,omitempty"`
|
||||
}
|
||||
|
||||
type ObjectTest struct {
|
||||
runtime.TypeMeta
|
||||
|
||||
ID string
|
||||
Items []runtime.Object
|
||||
}
|
||||
|
||||
type ObjectTestExternal struct {
|
||||
runtime.TypeMeta `yaml:",inline" json:",inline"`
|
||||
|
||||
ID string `json:"id,omitempty"`
|
||||
Items []runtime.RawExtension `json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*ObjectTest) IsAnAPIObject() {}
|
||||
func (*ObjectTestExternal) IsAnAPIObject() {}
|
||||
func (*EmbeddedTest) IsAnAPIObject() {}
|
||||
func (*EmbeddedTestExternal) IsAnAPIObject() {}
|
||||
|
||||
func TestDecodeEmptyRawExtensionAsObject(t *testing.T) {
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypes("", &ObjectTest{})
|
||||
s.AddKnownTypeWithName("v1test", "ObjectTest", &ObjectTestExternal{})
|
||||
|
||||
_, err := s.Decode([]byte(`{"kind":"ObjectTest","apiVersion":"v1test","items":[{}]}`))
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non-error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestArrayOfRuntimeObject(t *testing.T) {
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypes("", &EmbeddedTest{})
|
||||
s.AddKnownTypeWithName("v1test", "EmbeddedTest", &EmbeddedTestExternal{})
|
||||
s.AddKnownTypes("", &ObjectTest{})
|
||||
s.AddKnownTypeWithName("v1test", "ObjectTest", &ObjectTestExternal{})
|
||||
|
||||
internal := &ObjectTest{
|
||||
Items: []runtime.Object{
|
||||
&EmbeddedTest{ID: "foo"},
|
||||
&EmbeddedTest{ID: "bar"},
|
||||
// TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization
|
||||
&runtime.Unknown{RawJSON: []byte(`{"apiVersion":"unknown","foo":"bar","kind":"OtherTest"}`)},
|
||||
&ObjectTest{
|
||||
Items: []runtime.Object{
|
||||
&EmbeddedTest{ID: "baz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
wire, err := s.EncodeToVersion(internal, "v1test")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("Wire format is:\n%s\n", string(wire))
|
||||
|
||||
obj := &ObjectTestExternal{}
|
||||
if err := json.Unmarshal(wire, obj); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("exact wire is: %#v", string(obj.Items[0].RawJSON))
|
||||
|
||||
decoded, err := s.Decode(wire)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
internal.Items[2].(*runtime.Unknown).Kind = "OtherTest"
|
||||
internal.Items[2].(*runtime.Unknown).APIVersion = "unknown"
|
||||
if e, a := internal, decoded; !reflect.DeepEqual(e, a) {
|
||||
t.Log(string(decoded.(*ObjectTest).Items[2].(*runtime.Unknown).RawJSON))
|
||||
t.Errorf("mismatched decoded: %s", util.ObjectDiff(e, a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbeddedObject(t *testing.T) {
|
||||
s := scheme
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypes("", &EmbeddedTest{})
|
||||
s.AddKnownTypeWithName("v1test", "EmbeddedTest", &EmbeddedTestExternal{})
|
||||
|
||||
outer := &EmbeddedTest{
|
||||
TypeMeta: runtime.TypeMeta{Name: "outer"},
|
||||
ID: "outer",
|
||||
ID: "outer",
|
||||
Object: runtime.EmbeddedObject{
|
||||
&EmbeddedTest{
|
||||
TypeMeta: runtime.TypeMeta{Name: "inner"},
|
||||
ID: "inner",
|
||||
ID: "inner",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -83,7 +151,7 @@ func TestEmbeddedObject(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Unexpected decode error %v", err)
|
||||
}
|
||||
if externalViaJSON.Kind == "" || externalViaJSON.APIVersion == "" || externalViaJSON.Name != "outer" {
|
||||
if externalViaJSON.Kind == "" || externalViaJSON.APIVersion == "" || externalViaJSON.ID != "outer" {
|
||||
t.Errorf("Expected objects to have type info set, got %#v", externalViaJSON)
|
||||
}
|
||||
if !reflect.DeepEqual(externalViaJSON.EmptyObject.RawJSON, []byte("null")) || len(externalViaJSON.Object.RawJSON) == 0 {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. 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 runtime
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||
)
|
||||
|
||||
// IsNotRegisteredError returns true if the error indicates the provided
|
||||
// object or input data is not registered.
|
||||
func IsNotRegisteredError(err error) bool {
|
||||
return conversion.IsNotRegisteredError(err)
|
||||
}
|
|
@ -26,6 +26,8 @@ func (re *RawExtension) UnmarshalJSON(in []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (re *RawExtension) MarshalJSON() ([]byte, error) {
|
||||
// Marshal may get called on pointers or values, so implement MarshalJSON on value.
|
||||
// http://stackoverflow.com/questions/21390979/custom-marshaljson-never-gets-called-in-go
|
||||
func (re RawExtension) MarshalJSON() ([]byte, error) {
|
||||
return re.RawJSON, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. 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 runtime_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestEmbeddedRawExtensionMarshal(t *testing.T) {
|
||||
type test struct {
|
||||
Ext runtime.RawExtension
|
||||
}
|
||||
|
||||
extension := test{Ext: runtime.RawExtension{RawJSON: []byte(`{"foo":"bar"}`)}}
|
||||
data, err := json.Marshal(extension)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if string(data) != `{"Ext":{"foo":"bar"}}` {
|
||||
t.Errorf("unexpected data: %s", string(data))
|
||||
}
|
||||
}
|
|
@ -140,15 +140,77 @@ func (self *Scheme) rawExtensionToEmbeddedObject(in *RawExtension, out *Embedded
|
|||
return nil
|
||||
}
|
||||
|
||||
// runtimeObjectToRawExtensionArray takes a list of objects and encodes them as RawExtension in the output version
|
||||
// defined by the conversion.Scope. If objects must be encoded to different schema versions you should set them as
|
||||
// runtime.Unknown in the internal version instead.
|
||||
func (self *Scheme) runtimeObjectToRawExtensionArray(in *[]Object, out *[]RawExtension, s conversion.Scope) error {
|
||||
src := *in
|
||||
dest := make([]RawExtension, len(src))
|
||||
|
||||
_, outVersion, scheme := self.fromScope(s)
|
||||
|
||||
for i := range src {
|
||||
switch t := src[i].(type) {
|
||||
case *Unknown:
|
||||
dest[i].RawJSON = t.RawJSON
|
||||
default:
|
||||
data, err := scheme.EncodeToVersion(src[i], outVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dest[i].RawJSON = data
|
||||
}
|
||||
}
|
||||
*out = dest
|
||||
return nil
|
||||
}
|
||||
|
||||
// rawExtensionToRuntimeObjectArray attempts to decode objects from the array - if they are unrecognized objects,
|
||||
// they are added as Unknown.
|
||||
func (self *Scheme) rawExtensionToRuntimeObjectArray(in *[]RawExtension, out *[]Object, s conversion.Scope) error {
|
||||
src := *in
|
||||
dest := make([]Object, len(src))
|
||||
|
||||
_, _, scheme := self.fromScope(s)
|
||||
|
||||
for i := range src {
|
||||
data := src[i].RawJSON
|
||||
obj, err := scheme.Decode(data)
|
||||
if err != nil {
|
||||
if !IsNotRegisteredError(err) {
|
||||
return err
|
||||
}
|
||||
version, kind, err := scheme.raw.DataVersionAndKind(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj = &Unknown{
|
||||
TypeMeta: TypeMeta{
|
||||
APIVersion: version,
|
||||
Kind: kind,
|
||||
},
|
||||
RawJSON: data,
|
||||
}
|
||||
}
|
||||
dest[i] = obj
|
||||
}
|
||||
*out = dest
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewScheme creates a new Scheme. This scheme is pluggable by default.
|
||||
func NewScheme() *Scheme {
|
||||
s := &Scheme{conversion.NewScheme()}
|
||||
s.raw.InternalVersion = ""
|
||||
s.raw.MetaFactory = conversion.SimpleMetaFactory{BaseFields: []string{"TypeMeta"}, VersionField: "APIVersion", KindField: "Kind"}
|
||||
s.raw.AddConversionFuncs(
|
||||
if err := s.raw.AddConversionFuncs(
|
||||
s.embeddedObjectToRawExtension,
|
||||
s.rawExtensionToEmbeddedObject,
|
||||
)
|
||||
s.runtimeObjectToRawExtensionArray,
|
||||
s.rawExtensionToRuntimeObjectArray,
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -304,6 +366,8 @@ func (s *Scheme) DecodeInto(data []byte, obj Object) error {
|
|||
|
||||
// Copy does a deep copy of an API object. Useful mostly for tests.
|
||||
// TODO(dbsmith): implement directly instead of via Encode/Decode
|
||||
// TODO(claytonc): Copy cannot be used for objects which do not encode type information, such
|
||||
// as lists of runtime.Objects
|
||||
func (s *Scheme) Copy(obj Object) (Object, error) {
|
||||
data, err := s.EncodeToVersion(obj, "")
|
||||
if err != nil {
|
||||
|
|
|
@ -16,9 +16,7 @@ limitations under the License.
|
|||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
import ()
|
||||
|
||||
// Note that the types provided in this file are not versioned and are intended to be
|
||||
// safe to use from within all versions of every API object.
|
||||
|
@ -35,15 +33,8 @@ import (
|
|||
// your own with the same fields.
|
||||
//
|
||||
type TypeMeta struct {
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
UID string `json:"uid,omitempty"`
|
||||
CreationTimestamp util.Time `json:"creationTimestamp,omitempty"`
|
||||
SelfLink string `json:"selfLink,omitempty"`
|
||||
ResourceVersion string `json:"resourceVersion,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
}
|
||||
|
||||
// PluginBase is like TypeMeta, but it's intended for plugin objects that won't ever be encoded
|
||||
|
|
Loading…
Reference in New Issue