Add a List type that can contain arbitrary objects

Supports objects that the core schema may not recognize and
preserves them unmodified as runtime.Unknown
pull/6/head
Clayton Coleman 2014-12-07 21:19:10 -05:00
parent db2c59ff61
commit 8a833ca701
11 changed files with 109 additions and 4 deletions

View File

@ -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() {

View File

@ -45,6 +45,7 @@ func init() {
&ContainerManifestList{},
&BoundPod{},
&BoundPods{},
&List{},
)
}
@ -68,3 +69,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*BoundPod) IsAnAPIObject() {}
func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}

View File

@ -90,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() {
@ -145,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) {
@ -179,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("") {
@ -197,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)
}
}
}
}

View File

@ -19,6 +19,7 @@ package api
import (
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
@ -999,3 +1000,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"`
}

View File

@ -46,6 +46,7 @@ func init() {
&ContainerManifestList{},
&BoundPod{},
&BoundPods{},
&List{},
)
}
@ -69,3 +70,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*BoundPod) IsAnAPIObject() {}
func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}

View File

@ -19,6 +19,7 @@ package v1beta1
import (
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
@ -780,3 +781,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"`
}

View File

@ -46,6 +46,7 @@ func init() {
&ContainerManifestList{},
&BoundPod{},
&BoundPods{},
&List{},
)
}
@ -69,3 +70,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*BoundPod) IsAnAPIObject() {}
func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}

View File

@ -19,6 +19,7 @@ package v1beta2
import (
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
@ -781,3 +782,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"`
}

View File

@ -46,6 +46,7 @@ func init() {
&OperationList{},
&Event{},
&EventList{},
&List{},
)
}
@ -69,3 +70,4 @@ func (*Operation) IsAnAPIObject() {}
func (*OperationList) IsAnAPIObject() {}
func (*Event) IsAnAPIObject() {}
func (*EventList) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}

View File

@ -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"`
}

View File

@ -366,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 {