Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow runtime.Object to be encoded as runtime.RawExtension #2786

Merged
merged 6 commits into from
Dec 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions pkg/api/latest/latest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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() {
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func init() {
&ContainerManifestList{},
&BoundPod{},
&BoundPods{},
&List{},
)
}

Expand All @@ -68,3 +69,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*BoundPod) IsAnAPIObject() {}
func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
49 changes: 38 additions & 11 deletions pkg/api/serialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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("") {
Expand All @@ -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)
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package api
import (
"time"

"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

Expand Down Expand Up @@ -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"`
}
2 changes: 2 additions & 0 deletions pkg/api/v1beta1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func init() {
&ContainerManifestList{},
&BoundPod{},
&BoundPods{},
&List{},
)
}

Expand All @@ -69,3 +70,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*BoundPod) IsAnAPIObject() {}
func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
7 changes: 7 additions & 0 deletions pkg/api/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package v1beta1
import (
"time"

"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

Expand Down Expand Up @@ -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"`
}
2 changes: 2 additions & 0 deletions pkg/api/v1beta2/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func init() {
&ContainerManifestList{},
&BoundPod{},
&BoundPods{},
&List{},
)
}

Expand All @@ -69,3 +70,4 @@ func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*BoundPod) IsAnAPIObject() {}
func (*BoundPods) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
7 changes: 7 additions & 0 deletions pkg/api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package v1beta2
import (
"time"

"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

Expand Down Expand Up @@ -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"`
}
2 changes: 2 additions & 0 deletions pkg/api/v1beta3/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func init() {
&OperationList{},
&Event{},
&EventList{},
&List{},
)
}

Expand All @@ -69,3 +70,4 @@ func (*Operation) IsAnAPIObject() {}
func (*OperationList) IsAnAPIObject() {}
func (*Event) IsAnAPIObject() {}
func (*EventList) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
18 changes: 16 additions & 2 deletions pkg/api/v1beta3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package v1beta3
import (
"time"

"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the value of Kind for a List containing objects of multiple Kinds? Is it always just List?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - kind "List" means "generic container of things, including potentially other containers". "PodList" is a typed list.

----- Original Message -----

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

What is the value of Kind for a List containing objects of multiple Kinds? Is
it always just List?


Reply to this email directly or view it on GitHub:
https://github.com/GoogleCloudPlatform/kubernetes/pull/2786/files#r21546469

ListMeta `json:"metadata,omitempty"`

Items []runtime.RawExtension `json:"items" description:"list of objects"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the description, clarify that the objects may be of any/multiple kinds.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

On Dec 9, 2014, at 12:54 PM, bgrant0607 notifications@github.com wrote:

In pkg/api/v1beta3/types.go:

@@ -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"
    In the description, clarify that the objects may be of any/multiple kinds.


Reply to this email directly or view it on GitHub.

}
9 changes: 0 additions & 9 deletions pkg/api/validation/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pkg/conversion/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,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.
Expand Down
51 changes: 51 additions & 0 deletions pkg/conversion/error.go
Original file line number Diff line number Diff line change
@@ -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
}
13 changes: 6 additions & 7 deletions pkg/conversion/scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,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, &notRegisteredErr{kind: kind, version: versionName}
}
return nil, fmt.Errorf("no version '%v'", versionName)
return nil, &notRegisteredErr{kind: kind, version: versionName}
}

// AddConversionFuncs adds functions to the list of conversion functions. The given
Expand Down Expand Up @@ -185,8 +185,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
}
}
Expand Down Expand Up @@ -284,7 +283,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 "", "", &notRegisteredErr{t: t}
}
apiVersion = version
kind = kinds[0]
Expand Down