mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-06 07:57:35 +00:00
Split api into api, api/common, api/validation & apitools
This commit is contained in:
19
pkg/api/common/doc.go
Normal file
19
pkg/api/common/doc.go
Normal file
@@ -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
|
||||
@@ -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!")
|
||||
}
|
||||
@@ -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 {
|
||||
61
pkg/api/common/types.go
Normal file
61
pkg/api/common/types.go
Normal file
@@ -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 {
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||
"gopkg.in/v1/yaml"
|
||||
)
|
||||
|
||||
// codec defines methods for serializing and deserializing API
|
||||
// objects.
|
||||
type codec interface {
|
||||
Encode(obj interface{}) (data []byte, err error)
|
||||
Decode(data []byte) (interface{}, error)
|
||||
DecodeInto(data []byte, obj interface{}) error
|
||||
}
|
||||
|
||||
// resourceVersioner provides methods for setting and retrieving
|
||||
// the resource version from an API object.
|
||||
type resourceVersioner interface {
|
||||
SetResourceVersion(obj interface{}, version uint64) error
|
||||
ResourceVersion(obj interface{}) (uint64, error)
|
||||
}
|
||||
|
||||
var Codec codec
|
||||
var ResourceVersioner resourceVersioner
|
||||
|
||||
var conversionScheme = conversion.NewScheme()
|
||||
|
||||
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.
|
||||
// Encode() refuses the object unless its type is registered with AddKnownTypes.
|
||||
func AddKnownTypes(version string, types ...interface{}) {
|
||||
conversionScheme.AddKnownTypes(version, types...)
|
||||
}
|
||||
|
||||
// New returns a new API object of the given version ("" for internal
|
||||
// representation) and name, or an error if it hasn't been registered.
|
||||
func New(versionName, typeName string) (interface{}, error) {
|
||||
return conversionScheme.NewObject(versionName, typeName)
|
||||
}
|
||||
|
||||
// AddConversionFuncs adds a function to the list of conversion functions. The given
|
||||
// function should know how to convert between two API objects. We deduce how to call
|
||||
// it from the types of its two parameters; see the comment for Converter.Register.
|
||||
//
|
||||
// Note that, if you need to copy sub-objects that didn't change, it's safe to call
|
||||
// Convert() inside your conversionFuncs, as long as you don't start a conversion
|
||||
// chain that's infinitely recursive.
|
||||
//
|
||||
// Also note that the default behavior, if you don't add a conversion function, is to
|
||||
// sanely copy fields that have the same names. It's OK if the destination type has
|
||||
// extra fields, but it must not remove any. So you only need to add a conversion
|
||||
// function for things with changed/removed fields.
|
||||
func AddConversionFuncs(conversionFuncs ...interface{}) error {
|
||||
return conversionScheme.AddConversionFuncs(conversionFuncs...)
|
||||
}
|
||||
|
||||
// Convert will attempt to convert in into out. Both must be pointers to API objects.
|
||||
// For easy testing of conversion functions. Returns an error if the conversion isn't
|
||||
// possible.
|
||||
func Convert(in, out interface{}) error {
|
||||
return conversionScheme.Convert(in, out)
|
||||
}
|
||||
|
||||
// FindJSONBase takes an arbitary api type, returns pointer to its JSONBase field.
|
||||
// obj must be a pointer to an api type.
|
||||
func FindJSONBase(obj interface{}) (JSONBaseInterface, error) {
|
||||
v, err := enforcePtr(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := v.Type()
|
||||
name := t.Name()
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), name, v.Interface())
|
||||
}
|
||||
jsonBase := v.FieldByName("JSONBase")
|
||||
if !jsonBase.IsValid() {
|
||||
return nil, fmt.Errorf("struct %v lacks embedded JSON type", name)
|
||||
}
|
||||
g, err := newGenericJSONBase(jsonBase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
// Encode turns the given api object into an appropriate JSON string.
|
||||
// Will return an error if the object doesn't have an embedded JSONBase.
|
||||
// Obj may be a pointer to a struct, or a struct. If a struct, a copy
|
||||
// must be made. If a pointer, the object may be modified before encoding,
|
||||
// but will be put back into its original state before returning.
|
||||
//
|
||||
// Memory/wire format differences:
|
||||
// * Having to keep track of the Kind and APIVersion fields makes tests
|
||||
// very annoying, so the rule is that they are set only in wire format
|
||||
// (json), not when in native (memory) format. This is possible because
|
||||
// both pieces of information are implicit in the go typed object.
|
||||
// * An exception: note that, if there are embedded API objects of known
|
||||
// type, for example, PodList{... Items []Pod ...}, these embedded
|
||||
// objects must be of the same version of the object they are embedded
|
||||
// within, and their APIVersion and Kind must both be empty.
|
||||
// * Note that the exception does not apply to the APIObject type, which
|
||||
// recursively does Encode()/Decode(), and is capable of expressing any
|
||||
// API object.
|
||||
// * Only versioned objects should be encoded. This means that, if you pass
|
||||
// a native object, Encode will convert it to a versioned object. For
|
||||
// example, an api.Pod will get converted to a v1beta1.Pod. However, if
|
||||
// you pass in an object that's already versioned (v1beta1.Pod), Encode
|
||||
// will not modify it.
|
||||
//
|
||||
// The purpose of the above complex conversion behavior is to allow us to
|
||||
// change the memory format yet not break compatibility with any stored
|
||||
// objects, whether they be in our storage layer (e.g., etcd), or in user's
|
||||
// config files.
|
||||
//
|
||||
// TODO/next steps: When we add our second versioned type, this package will
|
||||
// need a version of Encode that lets you choose the wire version. A configurable
|
||||
// default will be needed, to allow operating in clusters that haven't yet
|
||||
// upgraded.
|
||||
//
|
||||
func Encode(obj interface{}) (data []byte, err error) {
|
||||
return conversionScheme.Encode(obj)
|
||||
}
|
||||
|
||||
// enforcePtr ensures that obj is a pointer of some sort. Returns a reflect.Value of the
|
||||
// dereferenced pointer, ensuring that it is settable/addressable.
|
||||
// Returns an error if this is not possible.
|
||||
func enforcePtr(obj interface{}) (reflect.Value, error) {
|
||||
v := reflect.ValueOf(obj)
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return reflect.Value{}, fmt.Errorf("expected pointer, but got %v", v.Type().Name())
|
||||
}
|
||||
return v.Elem(), nil
|
||||
}
|
||||
|
||||
// VersionAndKind will return the APIVersion and Kind of the given wire-format
|
||||
// enconding of an APIObject, or an error.
|
||||
func VersionAndKind(data []byte) (version, kind string, err error) {
|
||||
findKind := struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}{}
|
||||
// yaml is a superset of json, so we use it to decode here. That way,
|
||||
// we understand both.
|
||||
err = yaml.Unmarshal(data, &findKind)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("couldn't get version/kind: %v", err)
|
||||
}
|
||||
return findKind.APIVersion, findKind.Kind, nil
|
||||
}
|
||||
|
||||
// Decode converts a YAML or JSON string back into a pointer to an api object.
|
||||
// Deduces the type based upon the APIVersion and Kind fields, which are set
|
||||
// by Encode. Only versioned objects (APIVersion != "") are accepted. The object
|
||||
// will be converted into the in-memory unversioned type before being returned.
|
||||
func Decode(data []byte) (interface{}, error) {
|
||||
return conversionScheme.Decode(data)
|
||||
}
|
||||
|
||||
// DecodeInto parses a YAML or JSON string and stores it in obj. Returns an error
|
||||
// if data.Kind is set and doesn't match the type of obj. Obj should be a
|
||||
// pointer to an api type.
|
||||
// If obj's APIVersion doesn't match that in data, an attempt will be made to convert
|
||||
// data into obj's version.
|
||||
func DecodeInto(data []byte, obj interface{}) error {
|
||||
return conversionScheme.DecodeInto(data, obj)
|
||||
}
|
||||
|
||||
// metaInsertion implements conversion.MetaInsertionFactory, which lets the conversion
|
||||
// package figure out how to encode our object's types and versions. These fields are
|
||||
// located in our JSONBase.
|
||||
type metaInsertion struct {
|
||||
JSONBase struct {
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
} `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
// Create returns a new metaInsertion with the version and kind fields set.
|
||||
func (metaInsertion) Create(version, kind string) interface{} {
|
||||
m := metaInsertion{}
|
||||
m.JSONBase.APIVersion = version
|
||||
m.JSONBase.Kind = kind
|
||||
return &m
|
||||
}
|
||||
|
||||
// Interpret returns the version and kind information from in, which must be
|
||||
// a metaInsertion pointer object.
|
||||
func (metaInsertion) Interpret(in interface{}) (version, kind string) {
|
||||
m := in.(*metaInsertion)
|
||||
return m.JSONBase.APIVersion, m.JSONBase.Kind
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
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_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
var fuzzIters = flag.Int("fuzz_iters", 50, "How many fuzzing iterations to do.")
|
||||
|
||||
// apiObjectFuzzer can randomly populate api objects.
|
||||
var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
||||
func(j *api.JSONBase, c fuzz.Continue) {
|
||||
// We have to customize the randomization of JSONBases because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
j.ID = c.RandString()
|
||||
// TODO: Fix JSON/YAML packages and/or write custom encoding
|
||||
// for uint64's. Somehow the LS *byte* of this is lost, but
|
||||
// only when all 8 bytes are set.
|
||||
j.ResourceVersion = c.RandUint64() >> 8
|
||||
j.SelfLink = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(intstr *util.IntOrString, c fuzz.Continue) {
|
||||
// util.IntOrString will panic if its kind is set wrong.
|
||||
if c.RandBool() {
|
||||
intstr.Kind = util.IntstrInt
|
||||
intstr.IntVal = int(c.RandUint64())
|
||||
intstr.StrVal = ""
|
||||
} else {
|
||||
intstr.Kind = util.IntstrString
|
||||
intstr.IntVal = 0
|
||||
intstr.StrVal = c.RandString()
|
||||
}
|
||||
},
|
||||
func(u64 *uint64, c fuzz.Continue) {
|
||||
// TODO: uint64's are NOT handled right.
|
||||
*u64 = c.RandUint64() >> 8
|
||||
},
|
||||
func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
|
||||
// This is necessary because keys with nil values get omitted.
|
||||
// TODO: Is this a bug?
|
||||
pb[docker.Port(c.RandString())] = []docker.PortBinding{
|
||||
{c.RandString(), c.RandString()},
|
||||
{c.RandString(), c.RandString()},
|
||||
}
|
||||
},
|
||||
func(pm map[string]docker.PortMapping, c fuzz.Continue) {
|
||||
// This is necessary because keys with nil values get omitted.
|
||||
// TODO: Is this a bug?
|
||||
pm[c.RandString()] = docker.PortMapping{
|
||||
c.RandString(): c.RandString(),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
func objDiff(a, b interface{}) string {
|
||||
ab, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
panic("a")
|
||||
}
|
||||
bb, err := json.Marshal(b)
|
||||
if err != nil {
|
||||
panic("b")
|
||||
}
|
||||
return util.StringDiff(string(ab), string(bb))
|
||||
|
||||
// An alternate diff attempt, in case json isn't showing you
|
||||
// the difference. (reflect.DeepEqual makes a distinction between
|
||||
// nil and empty slices, for example.)
|
||||
return util.StringDiff(
|
||||
fmt.Sprintf("%#v", a),
|
||||
fmt.Sprintf("%#v", b),
|
||||
)
|
||||
}
|
||||
|
||||
func runTest(t *testing.T, source interface{}) {
|
||||
name := reflect.TypeOf(source).Elem().Name()
|
||||
apiObjectFuzzer.Fuzz(source)
|
||||
j, err := api.FindJSONBase(source)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v for %#v", err, source)
|
||||
}
|
||||
j.SetKind("")
|
||||
j.SetAPIVersion("")
|
||||
|
||||
data, err := api.Encode(source)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v (%#v)", name, err, source)
|
||||
return
|
||||
}
|
||||
|
||||
obj2, err := api.Decode(data)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
return
|
||||
} else {
|
||||
if !reflect.DeepEqual(source, obj2) {
|
||||
t.Errorf("1: %v: diff: %v", name, objDiff(source, obj2))
|
||||
return
|
||||
}
|
||||
}
|
||||
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface()
|
||||
err = api.DecodeInto(data, obj3)
|
||||
if err != nil {
|
||||
t.Errorf("2: %v: %v", name, err)
|
||||
return
|
||||
} else {
|
||||
if !reflect.DeepEqual(source, obj3) {
|
||||
t.Errorf("3: %v: diff: %v", name, objDiff(source, obj3))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypes(t *testing.T) {
|
||||
table := []interface{}{
|
||||
&api.PodList{},
|
||||
&api.Pod{},
|
||||
&api.ServiceList{},
|
||||
&api.Service{},
|
||||
&api.ReplicationControllerList{},
|
||||
&api.ReplicationController{},
|
||||
&api.MinionList{},
|
||||
&api.Minion{},
|
||||
&api.Status{},
|
||||
&api.ServerOpList{},
|
||||
&api.ServerOp{},
|
||||
&api.ContainerManifestList{},
|
||||
&api.Endpoints{},
|
||||
&api.Binding{},
|
||||
}
|
||||
for _, item := range table {
|
||||
// Try a few times, since runTest uses random values.
|
||||
for i := 0; i < *fuzzIters; i++ {
|
||||
runTest(t, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_NonPtr(t *testing.T) {
|
||||
pod := api.Pod{
|
||||
Labels: map[string]string{"name": "foo"},
|
||||
}
|
||||
obj := interface{}(pod)
|
||||
data, err := api.Encode(obj)
|
||||
obj2, err2 := api.Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
}
|
||||
if _, ok := obj2.(*api.Pod); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, &pod) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_Ptr(t *testing.T) {
|
||||
pod := &api.Pod{
|
||||
Labels: map[string]string{"name": "foo"},
|
||||
}
|
||||
obj := interface{}(pod)
|
||||
data, err := api.Encode(obj)
|
||||
obj2, err2 := api.Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
}
|
||||
if _, ok := obj2.(*api.Pod); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, pod) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadJSONRejection(t *testing.T) {
|
||||
badJSONMissingKind := []byte(`{ }`)
|
||||
if _, err := api.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 {
|
||||
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
|
||||
}
|
||||
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
|
||||
if err2 := DecodeInto(badJSONKindMismatch, &Minion{}); err2 == nil {
|
||||
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
|
||||
}*/
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// NewJSONBaseResourceVersioner returns a resourceVersioner that can set or
|
||||
// retrieve ResourceVersion on objects derived from JSONBase.
|
||||
func NewJSONBaseResourceVersioner() resourceVersioner {
|
||||
return &jsonBaseResourceVersioner{}
|
||||
}
|
||||
|
||||
type jsonBaseResourceVersioner struct{}
|
||||
|
||||
func (v jsonBaseResourceVersioner) ResourceVersion(obj interface{}) (uint64, error) {
|
||||
json, err := FindJSONBaseRO(obj)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return json.ResourceVersion, nil
|
||||
}
|
||||
|
||||
func (v jsonBaseResourceVersioner) SetResourceVersion(obj interface{}, version uint64) error {
|
||||
json, err := FindJSONBase(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
json.SetResourceVersion(version)
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONBaseInterface lets you work with a JSONBase from any of the versioned or
|
||||
// internal APIObjects.
|
||||
type JSONBaseInterface interface {
|
||||
ID() string
|
||||
SetID(ID string)
|
||||
APIVersion() string
|
||||
SetAPIVersion(version string)
|
||||
Kind() string
|
||||
SetKind(kind string)
|
||||
ResourceVersion() uint64
|
||||
SetResourceVersion(version uint64)
|
||||
}
|
||||
|
||||
type genericJSONBase struct {
|
||||
id *string
|
||||
apiVersion *string
|
||||
kind *string
|
||||
resourceVersion *uint64
|
||||
}
|
||||
|
||||
func (g genericJSONBase) ID() string {
|
||||
return *g.id
|
||||
}
|
||||
|
||||
func (g genericJSONBase) SetID(id string) {
|
||||
*g.id = id
|
||||
}
|
||||
|
||||
func (g genericJSONBase) APIVersion() string {
|
||||
return *g.apiVersion
|
||||
}
|
||||
|
||||
func (g genericJSONBase) SetAPIVersion(version string) {
|
||||
*g.apiVersion = version
|
||||
}
|
||||
|
||||
func (g genericJSONBase) Kind() string {
|
||||
return *g.kind
|
||||
}
|
||||
|
||||
func (g genericJSONBase) SetKind(kind string) {
|
||||
*g.kind = kind
|
||||
}
|
||||
|
||||
func (g genericJSONBase) ResourceVersion() uint64 {
|
||||
return *g.resourceVersion
|
||||
}
|
||||
|
||||
func (g genericJSONBase) SetResourceVersion(version uint64) {
|
||||
*g.resourceVersion = version
|
||||
}
|
||||
|
||||
// fieldPtr puts the address of fieldName, which must be a member of v,
|
||||
// into dest, which must be an address of a variable to which this field's
|
||||
// address can be assigned.
|
||||
func fieldPtr(v reflect.Value, fieldName string, dest interface{}) error {
|
||||
field := v.FieldByName(fieldName)
|
||||
if !field.IsValid() {
|
||||
return fmt.Errorf("Couldn't find %v field in %#v", fieldName, v.Interface())
|
||||
}
|
||||
v = reflect.ValueOf(dest)
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("dest should be ptr")
|
||||
}
|
||||
v = v.Elem()
|
||||
field = field.Addr()
|
||||
if field.Type().AssignableTo(v.Type()) {
|
||||
v.Set(field)
|
||||
return nil
|
||||
}
|
||||
if field.Type().ConvertibleTo(v.Type()) {
|
||||
v.Set(field.Convert(v.Type()))
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Couldn't assign/convert %v to %v", field.Type(), v.Type())
|
||||
}
|
||||
|
||||
// newGenericJSONBase creates a new generic JSONBase from v, which must be an
|
||||
// addressable/setable reflect.Value having the same fields as api.JSONBase.
|
||||
// Returns an error if this isn't the case.
|
||||
func newGenericJSONBase(v reflect.Value) (genericJSONBase, error) {
|
||||
g := genericJSONBase{}
|
||||
if err := fieldPtr(v, "ID", &g.id); err != nil {
|
||||
return g, err
|
||||
}
|
||||
if err := fieldPtr(v, "APIVersion", &g.apiVersion); err != nil {
|
||||
return g, err
|
||||
}
|
||||
if err := fieldPtr(v, "Kind", &g.kind); err != nil {
|
||||
return g, err
|
||||
}
|
||||
if err := fieldPtr(v, "ResourceVersion", &g.resourceVersion); err != nil {
|
||||
return g, err
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
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 (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenericJSONBase(t *testing.T) {
|
||||
j := JSONBase{
|
||||
ID: "foo",
|
||||
APIVersion: "a",
|
||||
Kind: "b",
|
||||
ResourceVersion: 1,
|
||||
}
|
||||
g, err := newGenericJSONBase(reflect.ValueOf(&j).Elem())
|
||||
if err != nil {
|
||||
t.Fatalf("new err: %v", err)
|
||||
}
|
||||
// Prove g supports JSONBaseInterface.
|
||||
jbi := JSONBaseInterface(g)
|
||||
if e, a := "foo", jbi.ID(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "a", jbi.APIVersion(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "b", jbi.Kind(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := uint64(1), jbi.ResourceVersion(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
jbi.SetID("bar")
|
||||
jbi.SetAPIVersion("c")
|
||||
jbi.SetKind("d")
|
||||
jbi.SetResourceVersion(2)
|
||||
|
||||
// Prove that jbi changes the original object.
|
||||
if e, a := "bar", j.ID; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "c", j.APIVersion; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "d", j.Kind; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := uint64(2), j.ResourceVersion; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceVersionerOfAPI(t *testing.T) {
|
||||
testCases := map[string]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},
|
||||
}
|
||||
versioning := NewJSONBaseResourceVersioner()
|
||||
for key, testCase := range testCases {
|
||||
actual, err := versioning.ResourceVersion(testCase.Object)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error %#v", key, err)
|
||||
}
|
||||
if actual != testCase.Expected {
|
||||
t.Errorf("%s: expected %d, got %d", key, testCase.Expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
failingCases := map[string]struct {
|
||||
Object interface{}
|
||||
Expected uint64
|
||||
}{
|
||||
"not a valid object to try": {JSONBase{ResourceVersion: 1}, 1},
|
||||
}
|
||||
for key, testCase := range failingCases {
|
||||
_, err := versioning.ResourceVersion(testCase.Object)
|
||||
if err == nil {
|
||||
t.Errorf("%s: expected error, got nil", key)
|
||||
}
|
||||
}
|
||||
|
||||
setCases := map[string]struct {
|
||||
Object interface{}
|
||||
Expected uint64
|
||||
}{
|
||||
"pointer to api object with version": {&Service{JSONBase: JSONBase{ResourceVersion: 1}}, 1},
|
||||
}
|
||||
for key, testCase := range setCases {
|
||||
if err := versioning.SetResourceVersion(testCase.Object, 5); err != nil {
|
||||
t.Errorf("%s: unexpected error %#v", key, err)
|
||||
}
|
||||
actual, err := versioning.ResourceVersion(testCase.Object)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error %#v", key, err)
|
||||
}
|
||||
if actual != 5 {
|
||||
t.Errorf("%s: expected %d, got %d", key, 5, actual)
|
||||
}
|
||||
}
|
||||
|
||||
failingSetCases := map[string]struct {
|
||||
Object interface{}
|
||||
Expected uint64
|
||||
}{
|
||||
"empty api object": {Service{}, 0},
|
||||
"api object with version": {Service{JSONBase: JSONBase{ResourceVersion: 1}}, 1},
|
||||
}
|
||||
for key, testCase := range failingSetCases {
|
||||
if err := versioning.SetResourceVersion(testCase.Object, 5); err == nil {
|
||||
t.Errorf("%s: unexpected non-error", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
40
pkg/api/register.go
Normal file
40
pkg/api/register.go
Normal file
@@ -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{},
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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{},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
package validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
package validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
Reference in New Issue
Block a user