From 6121e61f99be5a17b2f389883a18eff70b20e8fe Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 29 Aug 2014 15:48:41 -0700 Subject: [PATCH] Split api into api, api/common, api/validation & apitools --- pkg/api/common/doc.go | 19 ++++++ pkg/api/{apiobj.go => common/object.go} | 20 +++--- .../{apiobj_test.go => common/object_test.go} | 22 ++++--- pkg/api/common/types.go | 61 +++++++++++++++++++ pkg/api/doc.go | 7 ++- pkg/api/register.go | 40 ++++++++++++ pkg/api/types.go | 12 +--- pkg/api/v1beta1/conversion.go | 7 +-- pkg/api/v1beta1/conversion_test.go | 3 +- pkg/api/v1beta1/register.go | 4 +- pkg/api/v1beta1/types.go | 12 +--- pkg/api/{ => validation}/validation.go | 2 +- pkg/api/{ => validation}/validation_test.go | 2 +- pkg/apitools/doc.go | 42 +++++++++++++ pkg/{api => apitools}/helper.go | 43 +------------ pkg/{api => apitools}/helper_test.go | 23 +++---- pkg/{api => apitools}/jsonbase.go | 6 +- pkg/{api => apitools}/jsonbase_test.go | 34 +++++++++-- 18 files changed, 249 insertions(+), 110 deletions(-) create mode 100644 pkg/api/common/doc.go rename pkg/api/{apiobj.go => common/object.go} (83%) rename pkg/api/{apiobj_test.go => common/object_test.go} (74%) create mode 100644 pkg/api/common/types.go create mode 100644 pkg/api/register.go rename pkg/api/{ => validation}/validation.go (99%) rename pkg/api/{ => validation}/validation_test.go (99%) create mode 100644 pkg/apitools/doc.go rename pkg/{api => apitools}/helper.go (89%) rename pkg/{api => apitools}/helper_test.go (91%) rename pkg/{api => apitools}/jsonbase.go (97%) rename pkg/{api => apitools}/jsonbase_test.go (69%) diff --git a/pkg/api/common/doc.go b/pkg/api/common/doc.go new file mode 100644 index 00000000000..9464773ada8 --- /dev/null +++ b/pkg/api/common/doc.go @@ -0,0 +1,19 @@ +/* +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 common provides types useful for all versions of any object +// that conforms to the kubernetes API object expectations. +package common diff --git a/pkg/api/apiobj.go b/pkg/api/common/object.go similarity index 83% rename from pkg/api/apiobj.go rename to pkg/api/common/object.go index ce5a4cfe40f..32ad2ed7345 100644 --- a/pkg/api/apiobj.go +++ b/pkg/api/common/object.go @@ -14,10 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api +package common import ( "gopkg.in/v1/yaml" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/apitools" ) // Encode()/Decode() are the canonical way of converting an API object to/from @@ -26,14 +28,14 @@ import ( // embedded within other API types. // UnmarshalJSON implements the json.Unmarshaler interface. -func (a *APIObject) UnmarshalJSON(b []byte) error { +func (a *Object) UnmarshalJSON(b []byte) error { // Handle JSON's "null": Decode() doesn't expect it. if len(b) == 4 && string(b) == "null" { a.Object = nil return nil } - obj, err := Decode(b) + obj, err := apitools.Decode(b) if err != nil { return err } @@ -42,17 +44,17 @@ func (a *APIObject) UnmarshalJSON(b []byte) error { } // MarshalJSON implements the json.Marshaler interface. -func (a APIObject) MarshalJSON() ([]byte, error) { +func (a Object) MarshalJSON() ([]byte, error) { if a.Object == nil { // Encode unset/nil objects as JSON's "null". return []byte("null"), nil } - return Encode(a.Object) + return apitools.Encode(a.Object) } // SetYAML implements the yaml.Setter interface. -func (a *APIObject) SetYAML(tag string, value interface{}) bool { +func (a *Object) SetYAML(tag string, value interface{}) bool { if value == nil { a.Object = nil return true @@ -67,7 +69,7 @@ func (a *APIObject) SetYAML(tag string, value interface{}) bool { if err != nil { panic("yaml can't reverse its own object") } - obj, err := Decode(b) + obj, err := apitools.Decode(b) if err != nil { return false } @@ -76,13 +78,13 @@ func (a *APIObject) SetYAML(tag string, value interface{}) bool { } // GetYAML implements the yaml.Getter interface. -func (a APIObject) GetYAML() (tag string, value interface{}) { +func (a Object) GetYAML() (tag string, value interface{}) { if a.Object == nil { value = "null" return } // Encode returns JSON, which is conveniently a subset of YAML. - v, err := Encode(a.Object) + v, err := apitools.Encode(a.Object) if err != nil { panic("impossible to encode API object!") } diff --git a/pkg/api/apiobj_test.go b/pkg/api/common/object_test.go similarity index 74% rename from pkg/api/apiobj_test.go rename to pkg/api/common/object_test.go index 620c7d9cb14..a9316c18712 100644 --- a/pkg/api/apiobj_test.go +++ b/pkg/api/common/object_test.go @@ -14,40 +14,42 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api +package common import ( "encoding/json" "reflect" "testing" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/apitools" ) -func TestAPIObject(t *testing.T) { +func TestObject(t *testing.T) { type EmbeddedTest struct { JSONBase `yaml:",inline" json:",inline"` - Object APIObject `yaml:"object,omitempty" json:"object,omitempty"` - EmptyObject APIObject `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"` + Object Object `yaml:"object,omitempty" json:"object,omitempty"` + EmptyObject Object `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"` } - AddKnownTypes("", EmbeddedTest{}) - AddKnownTypes("v1beta1", EmbeddedTest{}) + apitools.AddKnownTypes("", EmbeddedTest{}) + apitools.AddKnownTypes("v1beta1", EmbeddedTest{}) outer := &EmbeddedTest{ JSONBase: JSONBase{ID: "outer"}, - Object: APIObject{ + Object: Object{ &EmbeddedTest{ JSONBase: JSONBase{ID: "inner"}, }, }, } - wire, err := Encode(outer) + wire, err := apitools.Encode(outer) if err != nil { t.Fatalf("Unexpected encode error '%v'", err) } t.Logf("Wire format is:\n%v\n", string(wire)) - decoded, err := Decode(wire) + decoded, err := apitools.Decode(wire) if err != nil { t.Fatalf("Unexpected decode error %v", err) } @@ -56,7 +58,7 @@ func TestAPIObject(t *testing.T) { t.Errorf("Expected: %#v but got %#v", e, a) } - // test JSON decoding, too, since api.Decode uses yaml unmarshalling. + // test JSON decoding, too, since apitools.Decode uses yaml unmarshalling. var decodedViaJSON EmbeddedTest err = json.Unmarshal(wire, &decodedViaJSON) if err != nil { diff --git a/pkg/api/common/types.go b/pkg/api/common/types.go new file mode 100644 index 00000000000..e76e29db270 --- /dev/null +++ b/pkg/api/common/types.go @@ -0,0 +1,61 @@ +/* +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 common + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" +) + +// JSONBase is shared by all top level objects. The proper way to use it is to inline it in your type, +// like this: +// type MyAwesomeAPIObject struct { +// common.JSONBase `yaml:",inline" json:",inline"` +// ... // other fields +// } +// +// JSONBase is provided here for convenience. You may use it directlly from this package or define +// your own with the same fields. +// +type JSONBase struct { + Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + ID string `json:"id,omitempty" yaml:"id,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` +} + +// Object has appropriate encoder and decoder functions, such that on the wire, it's +// stored as a []byte, but in memory, the contained object is accessable as an interface{} +// via the Get() function. Only objects having a JSONBase may be stored via Object. +// The purpose of this is to allow an API object of type known only at runtime to be +// embedded within other API objects. +// +// Note that object assumes that you've registered all of your api types with the api package. +// +// Note that objects will be serialized into the api package's default external versioned type; +// this should be fixed in the future to use the version of the current Codec instead. +type Object struct { + Object interface{} +} + +// Extension allows api objects with unknown types to be passed-through. This can be used +// to deal with the API objects from a plug-in. Extension objects still have functioning +// JSONBase features-- kind, version, resourceVersion, etc. +// TODO: Not implemented yet +type Extension struct { +} diff --git a/pkg/api/doc.go b/pkg/api/doc.go index f77c9e72bdd..da8ea3d15a1 100644 --- a/pkg/api/doc.go +++ b/pkg/api/doc.go @@ -14,6 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package api includes all types used to communicate between the various -// parts of the Kubernetes system. +// Package api contains the latest (or "internal") version of the +// Kubernetes API objects. This is the API objects as represented in memory. +// The contract presented to clients is located in the versioned packages, +// which are sub-directories. The first one is "v1beta1". Those packages +// describe how a particular version is serialized to storage/network. package api diff --git a/pkg/api/register.go b/pkg/api/register.go new file mode 100644 index 00000000000..42e3a8c63eb --- /dev/null +++ b/pkg/api/register.go @@ -0,0 +1,40 @@ +/* +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 api + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/apitools" +) + +func init() { + apitools.AddKnownTypes("", + PodList{}, + Pod{}, + ReplicationControllerList{}, + ReplicationController{}, + ServiceList{}, + Service{}, + MinionList{}, + Minion{}, + Status{}, + ServerOpList{}, + ServerOp{}, + ContainerManifestList{}, + Endpoints{}, + Binding{}, + ) +} diff --git a/pkg/api/types.go b/pkg/api/types.go index 9f3b76a3f46..a85aaac5e0a 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -17,6 +17,7 @@ limitations under the License. package api import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/common" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/fsouza/go-dockerclient" @@ -521,14 +522,5 @@ type WatchEvent struct { // For added or modified objects, this is the new object; for deleted objects, // it's the state of the object immediately prior to its deletion. - Object APIObject -} - -// APIObject has appropriate encoder and decoder functions, such that on the wire, it's -// stored as a []byte, but in memory, the contained object is accessable as an interface{} -// via the Get() function. Only objects having a JSONBase may be stored via APIObject. -// The purpose of this is to allow an API object of type known only at runtime to be -// embedded within other API objects. -type APIObject struct { - Object interface{} + Object common.Object } diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index 1f5d699362c..8b9ba560c3a 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -19,15 +19,14 @@ package v1beta1 import ( // Alias this so it can be easily changed when we cut the next version. newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - // Also import under original name for Convert and AddConversionFuncs. - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/apitools" ) func init() { // Shortcut for sub-conversions. TODO: This should possibly be refactored // such that this convert function is passed to each conversion func. - Convert := api.Convert - api.AddConversionFuncs( + Convert := apitools.Convert + apitools.AddConversionFuncs( // EnvVar's Key is deprecated in favor of Name. func(in *newer.EnvVar, out *EnvVar) error { out.Value = in.Value diff --git a/pkg/api/v1beta1/conversion_test.go b/pkg/api/v1beta1/conversion_test.go index a0f1b80b94e..f202735c195 100644 --- a/pkg/api/v1beta1/conversion_test.go +++ b/pkg/api/v1beta1/conversion_test.go @@ -22,9 +22,10 @@ import ( newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" + "github.com/GoogleCloudPlatform/kubernetes/pkg/apitools" ) -var Convert = newer.Convert +var Convert = apitools.Convert func TestEnvConversion(t *testing.T) { nonCanonical := []v1beta1.EnvVar{ diff --git a/pkg/api/v1beta1/register.go b/pkg/api/v1beta1/register.go index cd4cb5a2d94..1d4dae99de5 100644 --- a/pkg/api/v1beta1/register.go +++ b/pkg/api/v1beta1/register.go @@ -17,11 +17,11 @@ limitations under the License. package v1beta1 import ( - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/apitools" ) func init() { - api.AddKnownTypes("v1beta1", + apitools.AddKnownTypes("v1beta1", PodList{}, Pod{}, ReplicationControllerList{}, diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index 5c81d79c729..0812acefae6 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -17,6 +17,7 @@ limitations under the License. package v1beta1 import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/common" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/GoogleCloudPlatform/kubernetes/third_party/docker-api-structs" @@ -521,14 +522,5 @@ type WatchEvent struct { // For added or modified objects, this is the new object; for deleted objects, // it's the state of the object immediately prior to its deletion. - Object APIObject -} - -// APIObject has appropriate encoder and decoder functions, such that on the wire, it's -// stored as a []byte, but in memory, the contained object is accessable as an interface{} -// via the Get() function. Only objects having a JSONBase may be stored via APIObject. -// The purpose of this is to allow an API object of type known only at runtime to be -// embedded within other API objects. -type APIObject struct { - Object interface{} + Object common.Object } diff --git a/pkg/api/validation.go b/pkg/api/validation/validation.go similarity index 99% rename from pkg/api/validation.go rename to pkg/api/validation/validation.go index 79a97e49e39..c744ea32047 100644 --- a/pkg/api/validation.go +++ b/pkg/api/validation/validation.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api +package validation import ( "strings" diff --git a/pkg/api/validation_test.go b/pkg/api/validation/validation_test.go similarity index 99% rename from pkg/api/validation_test.go rename to pkg/api/validation/validation_test.go index 5e599b85017..99862f59ce0 100644 --- a/pkg/api/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api +package validation import ( "strings" diff --git a/pkg/apitools/doc.go b/pkg/apitools/doc.go new file mode 100644 index 00000000000..a0550549ef0 --- /dev/null +++ b/pkg/apitools/doc.go @@ -0,0 +1,42 @@ +/* +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 apitools includes helper functions for working with API objects +// that follow the kubernetes API object conventions, which are: +// +// 0. Your API objects have a common metadata struct member, JSONBase. +// 1. Your code refers to an internal set of API objects. +// 2. In a separate package, you have an external set of API objects. +// 3. The external set is considered to be versioned, and no breaking +// changes are ever made to it (fields may be added but not changed +// or removed). +// 4. As your api evolves, you'll make an additional versioned package +// with every major change. +// 5. Versioned packages have conversion functions which convert to +// and from the internal version. +// 6. You'll continue to support older versions according to your +// deprecation policy, and you can easily provide a program/library +// to update old versions into new versions because of 5. +// 7. All of your serializations and deserializations are handled in a +// centralized place. +// +// Package apitools provides a conversion helper to make 5 easy, and the +// Encode/Decode/DecodeInto trio to accomplish 7. You can also register +// additional "codecs" which use a version of your choice. It's +// recommended that you register your types with apitools in your +// package's init function. +// +package apitools diff --git a/pkg/api/helper.go b/pkg/apitools/helper.go similarity index 89% rename from pkg/api/helper.go rename to pkg/apitools/helper.go index 6c7d94e54e3..ddd6a58d6b9 100644 --- a/pkg/api/helper.go +++ b/pkg/apitools/helper.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api +package apitools import ( "fmt" @@ -39,34 +39,14 @@ type resourceVersioner interface { ResourceVersion(obj interface{}) (uint64, error) } -var Codec codec -var ResourceVersioner resourceVersioner - +var ResourceVersioner resourceVersioner = NewJSONBaseResourceVersioner() var conversionScheme = conversion.NewScheme() +var Codec codec = conversionScheme func init() { conversionScheme.InternalVersion = "" conversionScheme.ExternalVersion = "v1beta1" conversionScheme.MetaInsertionFactory = metaInsertion{} - AddKnownTypes("", - PodList{}, - Pod{}, - ReplicationControllerList{}, - ReplicationController{}, - ServiceList{}, - Service{}, - MinionList{}, - Minion{}, - Status{}, - ServerOpList{}, - ServerOp{}, - ContainerManifestList{}, - Endpoints{}, - Binding{}, - ) - - Codec = conversionScheme - ResourceVersioner = NewJSONBaseResourceVersioner() } // AddKnownTypes registers the types of the arguments to the marshaller of the package api. @@ -127,23 +107,6 @@ func FindJSONBase(obj interface{}) (JSONBaseInterface, error) { return g, nil } -// FindJSONBaseRO takes an arbitary api type, return a copy of its JSONBase field. -// obj may be a pointer to an api type, or a non-pointer struct api type. -func FindJSONBaseRO(obj interface{}) (JSONBase, error) { - v := reflect.ValueOf(obj) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() != reflect.Struct { - return JSONBase{}, fmt.Errorf("expected struct, but got %v (%#v)", v.Type().Name(), v.Interface()) - } - jsonBase := v.FieldByName("JSONBase") - if !jsonBase.IsValid() { - return JSONBase{}, fmt.Errorf("struct %v lacks embedded JSON type", v.Type().Name()) - } - return jsonBase.Interface().(JSONBase), nil -} - // EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests. func EncodeOrDie(obj interface{}) string { return conversionScheme.EncodeOrDie(obj) diff --git a/pkg/api/helper_test.go b/pkg/apitools/helper_test.go similarity index 91% rename from pkg/api/helper_test.go rename to pkg/apitools/helper_test.go index 87883670b54..e8df4d109da 100644 --- a/pkg/api/helper_test.go +++ b/pkg/apitools/helper_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api_test +package apitools_test import ( "encoding/json" @@ -25,6 +25,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" _ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" + "github.com/GoogleCloudPlatform/kubernetes/pkg/apitools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/fsouza/go-dockerclient" "github.com/google/gofuzz" @@ -107,20 +108,20 @@ func objDiff(a, b interface{}) string { func runTest(t *testing.T, source interface{}) { name := reflect.TypeOf(source).Elem().Name() apiObjectFuzzer.Fuzz(source) - j, err := api.FindJSONBase(source) + j, err := apitools.FindJSONBase(source) if err != nil { t.Fatalf("Unexpected error %v for %#v", err, source) } j.SetKind("") j.SetAPIVersion("") - data, err := api.Encode(source) + data, err := apitools.Encode(source) if err != nil { t.Errorf("%v: %v (%#v)", name, err, source) return } - obj2, err := api.Decode(data) + obj2, err := apitools.Decode(data) if err != nil { t.Errorf("%v: %v", name, err) return @@ -131,7 +132,7 @@ func runTest(t *testing.T, source interface{}) { } } obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface() - err = api.DecodeInto(data, obj3) + err = apitools.DecodeInto(data, obj3) if err != nil { t.Errorf("2: %v: %v", name, err) return @@ -173,8 +174,8 @@ func TestEncode_NonPtr(t *testing.T) { Labels: map[string]string{"name": "foo"}, } obj := interface{}(pod) - data, err := api.Encode(obj) - obj2, err2 := api.Decode(data) + data, err := apitools.Encode(obj) + obj2, err2 := apitools.Decode(data) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } @@ -191,8 +192,8 @@ func TestEncode_Ptr(t *testing.T) { Labels: map[string]string{"name": "foo"}, } obj := interface{}(pod) - data, err := api.Encode(obj) - obj2, err2 := api.Decode(data) + data, err := apitools.Encode(obj) + obj2, err2 := apitools.Decode(data) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } @@ -206,11 +207,11 @@ func TestEncode_Ptr(t *testing.T) { func TestBadJSONRejection(t *testing.T) { badJSONMissingKind := []byte(`{ }`) - if _, err := api.Decode(badJSONMissingKind); err == nil { + if _, err := apitools.Decode(badJSONMissingKind); err == nil { t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind) } badJSONUnknownType := []byte(`{"kind": "bar"}`) - if _, err1 := api.Decode(badJSONUnknownType); err1 == nil { + if _, err1 := apitools.Decode(badJSONUnknownType); err1 == nil { t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType) } /*badJSONKindMismatch := []byte(`{"kind": "Pod"}`) diff --git a/pkg/api/jsonbase.go b/pkg/apitools/jsonbase.go similarity index 97% rename from pkg/api/jsonbase.go rename to pkg/apitools/jsonbase.go index 4c211381a87..1577cea360c 100644 --- a/pkg/api/jsonbase.go +++ b/pkg/apitools/jsonbase.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api +package apitools import ( "fmt" @@ -30,11 +30,11 @@ func NewJSONBaseResourceVersioner() resourceVersioner { type jsonBaseResourceVersioner struct{} func (v jsonBaseResourceVersioner) ResourceVersion(obj interface{}) (uint64, error) { - json, err := FindJSONBaseRO(obj) + json, err := FindJSONBase(obj) if err != nil { return 0, err } - return json.ResourceVersion, nil + return json.ResourceVersion(), nil } func (v jsonBaseResourceVersioner) SetResourceVersion(obj interface{}, version uint64) error { diff --git a/pkg/api/jsonbase_test.go b/pkg/apitools/jsonbase_test.go similarity index 69% rename from pkg/api/jsonbase_test.go rename to pkg/apitools/jsonbase_test.go index 73bbe634a62..e1843a3e10a 100644 --- a/pkg/api/jsonbase_test.go +++ b/pkg/apitools/jsonbase_test.go @@ -14,14 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -package api +package apitools import ( "reflect" "testing" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) func TestGenericJSONBase(t *testing.T) { + type JSONBase struct { + Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + ID string `json:"id,omitempty" yaml:"id,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + } j := JSONBase{ ID: "foo", APIVersion: "a", @@ -68,13 +78,25 @@ func TestGenericJSONBase(t *testing.T) { } func TestResourceVersionerOfAPI(t *testing.T) { - testCases := map[string]struct { + type JSONBase struct { + Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + ID string `json:"id,omitempty" yaml:"id,omitempty"` + CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` + SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + } + type MyAPIObject struct { + JSONBase `yaml:",inline" json:",inline"` + } + type T struct { Object interface{} Expected uint64 - }{ - "empty api object": {Service{}, 0}, - "api object with version": {Service{JSONBase: JSONBase{ResourceVersion: 1}}, 1}, - "pointer to api object with version": {&Service{JSONBase: JSONBase{ResourceVersion: 1}}, 1}, + } + testCases := map[string]T{ + "empty api object": {&MyAPIObject{}, 0}, + "api object with version": {&MyAPIObject{JSONBase: JSONBase{ResourceVersion: 1}}, 1}, + "pointer to api object with version": {&MyAPIObject{JSONBase: JSONBase{ResourceVersion: 1}}, 1}, } versioning := NewJSONBaseResourceVersioner() for key, testCase := range testCases {