Merge pull request #1275 from smarterclayton/v1beta2
Create v1beta2 and allow multiple Codec encodings to exist
This commit is contained in:
@@ -14,7 +14,7 @@ install:
|
||||
- ./hack/build-go.sh
|
||||
|
||||
script:
|
||||
- ./hack/test-go.sh
|
||||
- KUBE_TIMEOUT='-timeout 60s' ./hack/test-go.sh
|
||||
- PATH=$HOME/gopath/bin:./third_party/etcd/bin:$PATH ./hack/test-cmd.sh
|
||||
- PATH=$HOME/gopath/bin:./third_party/etcd/bin:$PATH ./hack/test-integration.sh
|
||||
|
||||
|
@@ -29,6 +29,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
||||
@@ -206,7 +207,7 @@ func runAtomicPutTest(c *client.Client) {
|
||||
var svc api.Service
|
||||
err := c.Post().Path("services").Body(
|
||||
&api.Service{
|
||||
JSONBase: api.JSONBase{ID: "atomicservice", APIVersion: "v1beta1"},
|
||||
JSONBase: api.JSONBase{ID: "atomicservice", APIVersion: latest.Version},
|
||||
Port: 12345,
|
||||
Labels: map[string]string{
|
||||
"name": "atomicService",
|
||||
|
@@ -30,6 +30,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubecfg"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@@ -129,7 +130,7 @@ func readConfig(storage string) []byte {
|
||||
glog.Fatal("Need config file (-c)")
|
||||
}
|
||||
|
||||
data, err := parser.ToWireFormat(readConfigData(), storage, runtime.DefaultCodec)
|
||||
data, err := parser.ToWireFormat(readConfigData(), storage, latest.Codec)
|
||||
|
||||
if err != nil {
|
||||
glog.Fatalf("Error parsing %v as an object for %v: %v\n", *config, storage, err)
|
||||
@@ -296,7 +297,7 @@ func executeAPIRequest(method string, c *client.Client) bool {
|
||||
if setBody {
|
||||
if version != 0 {
|
||||
data := readConfig(storage)
|
||||
obj, err := runtime.DefaultCodec.Decode(data)
|
||||
obj, err := latest.Codec.Decode(data)
|
||||
if err != nil {
|
||||
glog.Fatalf("error setting resource version: %v", err)
|
||||
}
|
||||
@@ -305,7 +306,7 @@ func executeAPIRequest(method string, c *client.Client) bool {
|
||||
glog.Fatalf("error setting resource version: %v", err)
|
||||
}
|
||||
jsonBase.SetResourceVersion(version)
|
||||
data, err = runtime.DefaultCodec.Encode(obj)
|
||||
data, err = latest.Codec.Encode(obj)
|
||||
if err != nil {
|
||||
glog.Fatalf("error setting resource version: %v", err)
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/golang/glog"
|
||||
@@ -103,7 +103,7 @@ func TestApiExamples(t *testing.T) {
|
||||
return
|
||||
}
|
||||
tested += 1
|
||||
if err := runtime.DefaultCodec.DecodeInto(data, expectedType); err != nil {
|
||||
if err := latest.Codec.DecodeInto(data, expectedType); err != nil {
|
||||
t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data))
|
||||
return
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func TestExamples(t *testing.T) {
|
||||
return
|
||||
}
|
||||
tested += 1
|
||||
if err := runtime.DefaultCodec.DecodeInto(data, expectedType); err != nil {
|
||||
if err := latest.Codec.DecodeInto(data, expectedType); err != nil {
|
||||
t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data))
|
||||
return
|
||||
}
|
||||
@@ -168,14 +168,14 @@ func TestReadme(t *testing.T) {
|
||||
}
|
||||
for _, json := range match[1:] {
|
||||
expectedType := &api.Pod{}
|
||||
if err := runtime.DefaultCodec.DecodeInto([]byte(json), expectedType); err != nil {
|
||||
if err := latest.Codec.DecodeInto([]byte(json), expectedType); err != nil {
|
||||
t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data))
|
||||
return
|
||||
}
|
||||
if errors := validateObject(expectedType); len(errors) > 0 {
|
||||
t.Errorf("%s did not validate correctly: %v", path, errors)
|
||||
}
|
||||
encoded, err := runtime.DefaultCodec.Encode(expectedType)
|
||||
encoded, err := latest.Codec.Encode(expectedType)
|
||||
if err != nil {
|
||||
t.Errorf("Could not encode object: %v", err)
|
||||
continue
|
||||
|
55
pkg/api/conversion.go
Normal file
55
pkg/api/conversion.go
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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/runtime"
|
||||
)
|
||||
|
||||
// Codec is the identity codec for this package - it can only convert itself
|
||||
// to itself.
|
||||
var Codec = runtime.CodecFor(Scheme, "")
|
||||
|
||||
// EmbeddedObject implements a Codec specific version of an
|
||||
// embedded object.
|
||||
type EmbeddedObject struct {
|
||||
runtime.Object
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (a *EmbeddedObject) UnmarshalJSON(b []byte) error {
|
||||
obj, err := runtime.CodecUnmarshalJSON(Codec, b)
|
||||
a.Object = obj
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (a EmbeddedObject) MarshalJSON() ([]byte, error) {
|
||||
return runtime.CodecMarshalJSON(Codec, a.Object)
|
||||
}
|
||||
|
||||
// SetYAML implements the yaml.Setter interface.
|
||||
func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
|
||||
obj, ok := runtime.CodecSetYAML(Codec, tag, value)
|
||||
a.Object = obj
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetYAML implements the yaml.Getter interface.
|
||||
func (a EmbeddedObject) GetYAML() (tag string, value interface{}) {
|
||||
return runtime.CodecGetYAML(Codec, a.Object)
|
||||
}
|
20
pkg/api/latest/doc.go
Normal file
20
pkg/api/latest/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
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 latest defines the default output serializations that code should
|
||||
// use and imports the required schemas. It also ensures all previously known
|
||||
// and supported API versions are available for conversion.
|
||||
package latest
|
37
pkg/api/latest/latest.go
Normal file
37
pkg/api/latest/latest.go
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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 latest
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// Version is the string that represents the current external default version
|
||||
var Version = "v1beta1"
|
||||
|
||||
// Codec is the default codec for serializing output that should use
|
||||
// the latest supported version. Use this Codec when writing to
|
||||
// disk, a data store that is not dynamically versioned, or in tests.
|
||||
// This codec can decode any object that Kubernetes is aware of.
|
||||
var Codec = v1beta1.Codec
|
||||
|
||||
// ResourceVersioner describes a default versioner that can handle all types
|
||||
// of versioning.
|
||||
// TODO: when versioning changes, make this part of each API definition.
|
||||
var ResourceVersioner = runtime.NewJSONBaseResourceVersioner()
|
146
pkg/api/latest/latest_test.go
Normal file
146
pkg/api/latest/latest_test.go
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
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 latest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
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"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
// apiObjectFuzzer can randomly populate api objects.
|
||||
var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
||||
func(j *internal.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 TestInternalRoundTrip(t *testing.T) {
|
||||
latest := "v1beta2"
|
||||
|
||||
for k, _ := range internal.Scheme.KnownTypes("") {
|
||||
obj, err := internal.Scheme.New("", k)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
apiObjectFuzzer.Fuzz(obj)
|
||||
|
||||
newer, err := internal.Scheme.New(latest, k)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := internal.Scheme.Convert(obj, newer); err != nil {
|
||||
t.Errorf("unable to convert %#v to %#v: %v", obj, newer, err)
|
||||
}
|
||||
|
||||
actual, err := internal.Scheme.New("", k)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := internal.Scheme.Convert(newer, actual); err != nil {
|
||||
t.Errorf("unable to convert %#v to %#v: %v", newer, actual, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(obj, actual) {
|
||||
t.Errorf("%s: diff %s", k, runtime.ObjectDiff(obj, actual))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceVersioner(t *testing.T) {
|
||||
pod := internal.Pod{JSONBase: internal.JSONBase{ResourceVersion: 10}}
|
||||
version, err := ResourceVersioner.ResourceVersion(&pod)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if version != 10 {
|
||||
t.Errorf("unexpected version %d", version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodec(t *testing.T) {
|
||||
pod := internal.Pod{}
|
||||
data, err := Codec.Encode(&pod)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
other := internal.Pod{}
|
||||
if err := json.Unmarshal(data, &other); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if other.APIVersion != Version || other.Kind != "Pod" {
|
||||
t.Errorf("unexpected unmarshalled object %#v", other)
|
||||
}
|
||||
}
|
@@ -20,8 +20,10 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
|
||||
func init() {
|
||||
runtime.DefaultScheme.AddKnownTypes("",
|
||||
Scheme.AddKnownTypes("",
|
||||
&PodList{},
|
||||
&Pod{},
|
||||
&ReplicationControllerList{},
|
||||
|
@@ -17,21 +17,21 @@ 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/api/latest"
|
||||
"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"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
var fuzzIters = flag.Int("fuzz_iters", 50, "How many fuzzing iterations to do.")
|
||||
var fuzzIters = flag.Int("fuzz_iters", 40, "How many fuzzing iterations to do.")
|
||||
|
||||
// apiObjectFuzzer can randomly populate api objects.
|
||||
var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
||||
@@ -105,27 +105,7 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
||||
},
|
||||
)
|
||||
|
||||
func objDiff(a, b runtime.Object) 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 runtime.Object) {
|
||||
func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) {
|
||||
name := reflect.TypeOf(source).Elem().Name()
|
||||
apiObjectFuzzer.Fuzz(source)
|
||||
j, err := runtime.FindJSONBase(source)
|
||||
@@ -135,30 +115,30 @@ func runTest(t *testing.T, source runtime.Object) {
|
||||
j.SetKind("")
|
||||
j.SetAPIVersion("")
|
||||
|
||||
data, err := runtime.DefaultCodec.Encode(source)
|
||||
data, err := codec.Encode(source)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v (%#v)", name, err, source)
|
||||
return
|
||||
}
|
||||
|
||||
obj2, err := runtime.DefaultCodec.Decode(data)
|
||||
obj2, err := codec.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))
|
||||
t.Errorf("1: %v: diff: %v", name, runtime.ObjectDiff(source, obj2))
|
||||
return
|
||||
}
|
||||
}
|
||||
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface().(runtime.Object)
|
||||
err = runtime.DefaultCodec.DecodeInto(data, obj3)
|
||||
err = codec.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))
|
||||
t.Errorf("3: %v: diff: %v", name, runtime.ObjectDiff(source, obj3))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -184,7 +164,9 @@ func TestTypes(t *testing.T) {
|
||||
for _, item := range table {
|
||||
// Try a few times, since runTest uses random values.
|
||||
for i := 0; i < *fuzzIters; i++ {
|
||||
runTest(t, item)
|
||||
runTest(t, v1beta1.Codec, item)
|
||||
runTest(t, v1beta2.Codec, item)
|
||||
runTest(t, api.Codec, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,8 +176,8 @@ func TestEncode_Ptr(t *testing.T) {
|
||||
Labels: map[string]string{"name": "foo"},
|
||||
}
|
||||
obj := runtime.Object(pod)
|
||||
data, err := runtime.DefaultCodec.Encode(obj)
|
||||
obj2, err2 := runtime.DefaultCodec.Decode(data)
|
||||
data, err := latest.Codec.Encode(obj)
|
||||
obj2, err2 := latest.Codec.Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
}
|
||||
@@ -209,11 +191,11 @@ func TestEncode_Ptr(t *testing.T) {
|
||||
|
||||
func TestBadJSONRejection(t *testing.T) {
|
||||
badJSONMissingKind := []byte(`{ }`)
|
||||
if _, err := runtime.DefaultCodec.Decode(badJSONMissingKind); err == nil {
|
||||
if _, err := latest.Codec.Decode(badJSONMissingKind); err == nil {
|
||||
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
|
||||
}
|
||||
badJSONUnknownType := []byte(`{"kind": "bar"}`)
|
||||
if _, err1 := runtime.DefaultCodec.Decode(badJSONUnknownType); err1 == nil {
|
||||
if _, err1 := latest.Codec.Decode(badJSONUnknownType); err1 == nil {
|
||||
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
|
||||
}
|
||||
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
|
||||
|
@@ -17,9 +17,7 @@ limitations under the License.
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
@@ -623,13 +621,3 @@ type ServerOpList struct {
|
||||
}
|
||||
|
||||
func (*ServerOpList) IsAnAPIObject() {}
|
||||
|
||||
// WatchEvent objects are streamed from the api server in response to a watch request.
|
||||
type WatchEvent struct {
|
||||
// The type of the watch event; added, modified, or deleted.
|
||||
Type watch.EventType
|
||||
|
||||
// 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 runtime.EmbeddedObject
|
||||
}
|
||||
|
@@ -17,14 +17,13 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
// Alias this so it can be easily changed when we cut the next version.
|
||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func init() {
|
||||
runtime.DefaultScheme.AddConversionFuncs(
|
||||
newer.Scheme.AddConversionFuncs(
|
||||
// EnvVar's Key is deprecated in favor of Name.
|
||||
func(in *newer.EnvVar, out *EnvVar, s conversion.Scope) error {
|
||||
out.Value = in.Value
|
||||
@@ -81,3 +80,33 @@ func init() {
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// EmbeddedObject implements a Codec specific version of an
|
||||
// embedded object.
|
||||
type EmbeddedObject struct {
|
||||
runtime.Object
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (a *EmbeddedObject) UnmarshalJSON(b []byte) error {
|
||||
obj, err := runtime.CodecUnmarshalJSON(Codec, b)
|
||||
a.Object = obj
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (a EmbeddedObject) MarshalJSON() ([]byte, error) {
|
||||
return runtime.CodecMarshalJSON(Codec, a.Object)
|
||||
}
|
||||
|
||||
// SetYAML implements the yaml.Setter interface.
|
||||
func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
|
||||
obj, ok := runtime.CodecSetYAML(Codec, tag, value)
|
||||
a.Object = obj
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetYAML implements the yaml.Getter interface.
|
||||
func (a EmbeddedObject) GetYAML() (tag string, value interface{}) {
|
||||
return runtime.CodecGetYAML(Codec, a.Object)
|
||||
}
|
||||
|
@@ -22,10 +22,9 @@ import (
|
||||
|
||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
var Convert = runtime.DefaultScheme.Convert
|
||||
var Convert = newer.Scheme.Convert
|
||||
|
||||
func TestEnvConversion(t *testing.T) {
|
||||
nonCanonical := []v1beta1.EnvVar{
|
||||
|
@@ -17,11 +17,15 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// Codec encodes internal objects to the v1beta1 scheme
|
||||
var Codec = runtime.CodecFor(api.Scheme, "v1beta1")
|
||||
|
||||
func init() {
|
||||
runtime.DefaultScheme.AddKnownTypes("v1beta1",
|
||||
api.Scheme.AddKnownTypes("v1beta1",
|
||||
&PodList{},
|
||||
&Pod{},
|
||||
&ReplicationControllerList{},
|
||||
|
@@ -17,9 +17,7 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
@@ -625,13 +623,3 @@ type ServerOpList struct {
|
||||
}
|
||||
|
||||
func (*ServerOpList) IsAnAPIObject() {}
|
||||
|
||||
// WatchEvent objects are streamed from the api server in response to a watch request.
|
||||
type WatchEvent struct {
|
||||
// The type of the watch event; added, modified, or deleted.
|
||||
Type watch.EventType
|
||||
|
||||
// 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 runtime.EmbeddedObject
|
||||
}
|
||||
|
111
pkg/api/v1beta2/conversion.go
Normal file
111
pkg/api/v1beta2/conversion.go
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
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 v1beta2
|
||||
|
||||
import (
|
||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func init() {
|
||||
newer.Scheme.AddConversionFuncs(
|
||||
// EnvVar's Key is deprecated in favor of Name.
|
||||
func(in *newer.EnvVar, out *EnvVar, s conversion.Scope) error {
|
||||
out.Value = in.Value
|
||||
out.Key = in.Name
|
||||
out.Name = in.Name
|
||||
return nil
|
||||
},
|
||||
func(in *EnvVar, out *newer.EnvVar, s conversion.Scope) error {
|
||||
out.Value = in.Value
|
||||
if in.Name != "" {
|
||||
out.Name = in.Name
|
||||
} else {
|
||||
out.Name = in.Key
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
// Path & MountType are deprecated.
|
||||
func(in *newer.VolumeMount, out *VolumeMount, s conversion.Scope) error {
|
||||
out.Name = in.Name
|
||||
out.ReadOnly = in.ReadOnly
|
||||
out.MountPath = in.MountPath
|
||||
out.Path = in.MountPath
|
||||
out.MountType = "" // MountType is ignored.
|
||||
return nil
|
||||
},
|
||||
func(in *VolumeMount, out *newer.VolumeMount, s conversion.Scope) error {
|
||||
out.Name = in.Name
|
||||
out.ReadOnly = in.ReadOnly
|
||||
if in.MountPath == "" {
|
||||
out.MountPath = in.Path
|
||||
} else {
|
||||
out.MountPath = in.MountPath
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
// MinionList.Items had a wrong name in v1beta1
|
||||
func(in *newer.MinionList, out *MinionList, s conversion.Scope) error {
|
||||
s.Convert(&in.JSONBase, &out.JSONBase, 0)
|
||||
s.Convert(&in.Items, &out.Items, 0)
|
||||
out.Minions = out.Items
|
||||
return nil
|
||||
},
|
||||
func(in *MinionList, out *newer.MinionList, s conversion.Scope) error {
|
||||
s.Convert(&in.JSONBase, &out.JSONBase, 0)
|
||||
if len(in.Items) == 0 {
|
||||
s.Convert(&in.Minions, &out.Items, 0)
|
||||
} else {
|
||||
s.Convert(&in.Items, &out.Items, 0)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// EmbeddedObject implements a Codec specific version of an
|
||||
// embedded object.
|
||||
type EmbeddedObject struct {
|
||||
runtime.Object
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (a *EmbeddedObject) UnmarshalJSON(b []byte) error {
|
||||
obj, err := runtime.CodecUnmarshalJSON(Codec, b)
|
||||
a.Object = obj
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (a EmbeddedObject) MarshalJSON() ([]byte, error) {
|
||||
return runtime.CodecMarshalJSON(Codec, a.Object)
|
||||
}
|
||||
|
||||
// SetYAML implements the yaml.Setter interface.
|
||||
func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
|
||||
obj, ok := runtime.CodecSetYAML(Codec, tag, value)
|
||||
a.Object = obj
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetYAML implements the yaml.Getter interface.
|
||||
func (a EmbeddedObject) GetYAML() (tag string, value interface{}) {
|
||||
return runtime.CodecGetYAML(Codec, a.Object)
|
||||
}
|
19
pkg/api/v1beta2/conversion_test.go
Normal file
19
pkg/api/v1beta2/conversion_test.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 v1beta2_test
|
||||
|
||||
import ()
|
18
pkg/api/v1beta2/doc.go
Normal file
18
pkg/api/v1beta2/doc.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
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 v1beta2 is the v1beta2 version of the API.
|
||||
package v1beta2
|
45
pkg/api/v1beta2/register.go
Normal file
45
pkg/api/v1beta2/register.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
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 v1beta2
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// Codec encodes internal objects to the v1beta2 scheme
|
||||
var Codec = runtime.CodecFor(api.Scheme, "v1beta2")
|
||||
|
||||
func init() {
|
||||
api.Scheme.AddKnownTypes("v1beta2",
|
||||
&PodList{},
|
||||
&Pod{},
|
||||
&ReplicationControllerList{},
|
||||
&ReplicationController{},
|
||||
&ServiceList{},
|
||||
&Service{},
|
||||
&MinionList{},
|
||||
&Minion{},
|
||||
&Status{},
|
||||
&ServerOpList{},
|
||||
&ServerOp{},
|
||||
&ContainerManifestList{},
|
||||
&Endpoints{},
|
||||
&EndpointsList{},
|
||||
&Binding{},
|
||||
)
|
||||
}
|
635
pkg/api/v1beta2/types.go
Normal file
635
pkg/api/v1beta2/types.go
Normal file
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
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 v1beta2
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
// Common string formats
|
||||
// ---------------------
|
||||
// Many fields in this API have formatting requirements. The commonly used
|
||||
// formats are defined here.
|
||||
//
|
||||
// C_IDENTIFIER: This is a string that conforms the definition of an "identifier"
|
||||
// in the C language. This is captured by the following regex:
|
||||
// [A-Za-z_][A-Za-z0-9_]*
|
||||
// This defines the format, but not the length restriction, which should be
|
||||
// specified at the definition of any field of this type.
|
||||
//
|
||||
// DNS_LABEL: This is a string, no more than 63 characters long, that conforms
|
||||
// to the definition of a "label" in RFCs 1035 and 1123. This is captured
|
||||
// by the following regex:
|
||||
// [a-z0-9]([-a-z0-9]*[a-z0-9])?
|
||||
//
|
||||
// DNS_SUBDOMAIN: This is a string, no more than 253 characters long, that conforms
|
||||
// to the definition of a "subdomain" in RFCs 1035 and 1123. This is captured
|
||||
// by the following regex:
|
||||
// [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
|
||||
// or more simply:
|
||||
// DNS_LABEL(\.DNS_LABEL)*
|
||||
|
||||
// ContainerManifest corresponds to the Container Manifest format, documented at:
|
||||
// https://developers.google.com/compute/docs/containers/container_vms#container_manifest
|
||||
// This is used as the representation of Kubernetes workloads.
|
||||
type ContainerManifest struct {
|
||||
// Required: This must be a supported version string, such as "v1beta1".
|
||||
Version string `yaml:"version" json:"version"`
|
||||
// Required: This must be a DNS_SUBDOMAIN.
|
||||
// TODO: ID on Manifest is deprecated and will be removed in the future.
|
||||
ID string `yaml:"id" json:"id"`
|
||||
// TODO: UUID on Manifest is deprecated in the future once we are done
|
||||
// with the API refactoring. It is required for now to determine the instance
|
||||
// of a Pod.
|
||||
UUID string `yaml:"uuid,omitempty" json:"uuid,omitempty"`
|
||||
Volumes []Volume `yaml:"volumes" json:"volumes"`
|
||||
Containers []Container `yaml:"containers" json:"containers"`
|
||||
RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerManifestList is used to communicate container manifests to kubelet.
|
||||
type ContainerManifestList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*ContainerManifestList) IsAnAPIObject() {}
|
||||
|
||||
// Volume represents a named volume in a pod that may be accessed by any containers in the pod.
|
||||
type Volume struct {
|
||||
// Required: This must be a DNS_LABEL. Each volume in a pod must have
|
||||
// a unique name.
|
||||
Name string `yaml:"name" json:"name"`
|
||||
// Source represents the location and type of a volume to mount.
|
||||
// This is optional for now. If not specified, the Volume is implied to be an EmptyDir.
|
||||
// This implied behavior is deprecated and will be removed in a future version.
|
||||
Source *VolumeSource `yaml:"source" json:"source"`
|
||||
}
|
||||
|
||||
type VolumeSource struct {
|
||||
// Only one of the following sources may be specified
|
||||
// HostDirectory represents a pre-existing directory on the host machine that is directly
|
||||
// exposed to the container. This is generally used for system agents or other privileged
|
||||
// things that are allowed to see the host machine. Most containers will NOT need this.
|
||||
// TODO(jonesdl) We need to restrict who can use host directory mounts and
|
||||
// who can/can not mount host directories as read/write.
|
||||
HostDirectory *HostDirectory `yaml:"hostDir" json:"hostDir"`
|
||||
// EmptyDirectory represents a temporary directory that shares a pod's lifetime.
|
||||
EmptyDirectory *EmptyDirectory `yaml:"emptyDir" json:"emptyDir"`
|
||||
}
|
||||
|
||||
// HostDirectory represents bare host directory volume.
|
||||
type HostDirectory struct {
|
||||
Path string `yaml:"path" json:"path"`
|
||||
}
|
||||
|
||||
type EmptyDirectory struct{}
|
||||
|
||||
// Port represents a network port in a single container.
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
// in a pod must have a unique name.
|
||||
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||
// Optional: If specified, this must be a valid port number, 0 < x < 65536.
|
||||
HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
|
||||
// Required: This must be a valid port number, 0 < x < 65536.
|
||||
ContainerPort int `yaml:"containerPort" json:"containerPort"`
|
||||
// Optional: Supports "TCP" and "UDP". Defaults to "TCP".
|
||||
Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
|
||||
// Optional: What host IP to bind the external port to.
|
||||
HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty"`
|
||||
}
|
||||
|
||||
// VolumeMount describes a mounting of a Volume within a container.
|
||||
type VolumeMount struct {
|
||||
// Required: This must match the Name of a Volume [above].
|
||||
Name string `yaml:"name" json:"name"`
|
||||
// Optional: Defaults to false (read-write).
|
||||
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
|
||||
// Required.
|
||||
// Exactly one of the following must be set. If both are set, prefer MountPath.
|
||||
// DEPRECATED: Path will be removed in a future version of the API.
|
||||
MountPath string `yaml:"mountPath,omitempty" json:"mountPath,omitempty"`
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
// One of: "LOCAL" (local volume) or "HOST" (external mount from the host). Default: LOCAL.
|
||||
// DEPRECATED: MountType will be removed in a future version of the API.
|
||||
MountType string `yaml:"mountType,omitempty" json:"mountType,omitempty"`
|
||||
}
|
||||
|
||||
// EnvVar represents an environment variable present in a Container.
|
||||
type EnvVar struct {
|
||||
// Required: This must be a C_IDENTIFIER.
|
||||
// Exactly one of the following must be set. If both are set, prefer Name.
|
||||
// DEPRECATED: EnvVar.Key will be removed in a future version of the API.
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Key string `yaml:"key,omitempty" json:"key,omitempty"`
|
||||
// Optional: defaults to "".
|
||||
Value string `yaml:"value,omitempty" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// HTTPGetAction describes an action based on HTTP Get requests.
|
||||
type HTTPGetAction struct {
|
||||
// Optional: Path to access on the HTTP server.
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
// Required: Name or number of the port to access on the container.
|
||||
Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
// Optional: Host name to connect to, defaults to the pod IP.
|
||||
Host string `yaml:"host,omitempty" json:"host,omitempty"`
|
||||
}
|
||||
|
||||
// TCPSocketAction describes an action based on opening a socket
|
||||
type TCPSocketAction struct {
|
||||
// Required: Port to connect to.
|
||||
Port util.IntOrString `yaml:"port,omitempty" json:"port,omitempty"`
|
||||
}
|
||||
|
||||
// ExecAction describes a "run in container" action.
|
||||
type ExecAction struct {
|
||||
// Command is the command line to execute inside the container, the working directory for the
|
||||
// command is root ('/') in the container's filesystem. The command is simply exec'd, it is
|
||||
// not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
|
||||
// a shell, you need to explicitly call out to that shell.
|
||||
Command []string `yaml:"command,omitempty" json:"command,omitempty"`
|
||||
}
|
||||
|
||||
// LivenessProbe describes a liveness probe to be examined to the container.
|
||||
// TODO: pass structured data to the actions, and document that data here.
|
||||
type LivenessProbe struct {
|
||||
// Type of liveness probe. Current legal values "http", "tcp"
|
||||
Type string `yaml:"type,omitempty" json:"type,omitempty"`
|
||||
// HTTPGetProbe parameters, required if Type == 'http'
|
||||
HTTPGet *HTTPGetAction `yaml:"httpGet,omitempty" json:"httpGet,omitempty"`
|
||||
// TCPSocketProbe parameter, required if Type == 'tcp'
|
||||
TCPSocket *TCPSocketAction `yaml:"tcpSocket,omitempty" json:"tcpSocket,omitempty"`
|
||||
// ExecProbe parameter, required if Type == 'exec'
|
||||
Exec *ExecAction `yaml:"exec,omitempty" json:"exec,omitempty"`
|
||||
// Length of time before health checking is activated. In seconds.
|
||||
InitialDelaySeconds int64 `yaml:"initialDelaySeconds,omitempty" json:"initialDelaySeconds,omitempty"`
|
||||
}
|
||||
|
||||
// Container represents a single container that is expected to be run on the host.
|
||||
type Container struct {
|
||||
// Required: This must be a DNS_LABEL. Each container in a pod must
|
||||
// have a unique name.
|
||||
Name string `yaml:"name" json:"name"`
|
||||
// Required.
|
||||
Image string `yaml:"image" json:"image"`
|
||||
// Optional: Defaults to whatever is defined in the image.
|
||||
Command []string `yaml:"command,omitempty" json:"command,omitempty"`
|
||||
// Optional: Defaults to Docker's default.
|
||||
WorkingDir string `yaml:"workingDir,omitempty" json:"workingDir,omitempty"`
|
||||
Ports []Port `yaml:"ports,omitempty" json:"ports,omitempty"`
|
||||
Env []EnvVar `yaml:"env,omitempty" json:"env,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
Memory int `yaml:"memory,omitempty" json:"memory,omitempty"`
|
||||
// Optional: Defaults to unlimited.
|
||||
CPU int `yaml:"cpu,omitempty" json:"cpu,omitempty"`
|
||||
VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty"`
|
||||
LivenessProbe *LivenessProbe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"`
|
||||
Lifecycle *Lifecycle `yaml:"lifecycle,omitempty" json:"lifecycle,omitempty"`
|
||||
// Optional: Default to false.
|
||||
Privileged bool `json:"privileged,omitempty" yaml:"privileged,omitempty"`
|
||||
}
|
||||
|
||||
// Handler defines a specific action that should be taken
|
||||
// TODO: pass structured data to these actions, and document that data here.
|
||||
type Handler struct {
|
||||
// One and only one of the following should be specified.
|
||||
// Exec specifies the action to take.
|
||||
Exec *ExecAction `yaml:"exec,omitempty" json:"exec,omitempty"`
|
||||
// HTTPGet specifies the http request to perform.
|
||||
HTTPGet *HTTPGetAction `yaml:"httpGet,omitempty" json:"httpGet,omitempty"`
|
||||
}
|
||||
|
||||
// Lifecycle describes actions that the management system should take in response to container lifecycle
|
||||
// events. For the PostStart and PreStop lifecycle handlers, management of the container blocks
|
||||
// until the action is complete, unless the container process fails, in which case the handler is aborted.
|
||||
type Lifecycle struct {
|
||||
// PostStart is called immediately after a container is created. If the handler fails, the container
|
||||
// is terminated and restarted.
|
||||
PostStart *Handler `yaml:"postStart,omitempty" json:"postStart,omitempty"`
|
||||
// PreStop is called immediately before a container is terminated. The reason for termination is
|
||||
// passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated.
|
||||
PreStop *Handler `yaml:"preStop,omitempty" json:"preStop,omitempty"`
|
||||
}
|
||||
|
||||
// Event is the representation of an event logged to etcd backends.
|
||||
type Event struct {
|
||||
Event string `json:"event,omitempty"`
|
||||
Manifest *ContainerManifest `json:"manifest,omitempty"`
|
||||
Container *Container `json:"container,omitempty"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// The below types are used by kube_client and api_server.
|
||||
|
||||
// JSONBase is shared by all objects sent to, or returned from the client.
|
||||
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"`
|
||||
}
|
||||
|
||||
// PodStatus represents a status of a pod.
|
||||
type PodStatus string
|
||||
|
||||
// These are the valid statuses of pods.
|
||||
const (
|
||||
// PodWaiting means that we're waiting for the pod to begin running.
|
||||
PodWaiting PodStatus = "Waiting"
|
||||
// PodRunning means that the pod is up and running.
|
||||
PodRunning PodStatus = "Running"
|
||||
// PodTerminated means that the pod has stopped.
|
||||
PodTerminated PodStatus = "Terminated"
|
||||
)
|
||||
|
||||
type ContainerStateWaiting struct {
|
||||
// Reason could be pulling image,
|
||||
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerStateRunning struct {
|
||||
}
|
||||
|
||||
type ContainerStateTerminated struct {
|
||||
ExitCode int `json:"exitCode,omitempty" yaml:"exitCode,omitempty"`
|
||||
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
||||
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerState struct {
|
||||
// Only one of the following ContainerState may be specified.
|
||||
// If none of them is specified, the default one is ContainerStateWaiting.
|
||||
Waiting *ContainerStateWaiting `json:"waiting,omitempty" yaml:"waiting,omitempty"`
|
||||
Running *ContainerStateRunning `json:"running,omitempty" yaml:"running,omitempty"`
|
||||
Termination *ContainerStateTerminated `json:"termination,omitempty" yaml:"termination,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerStatus struct {
|
||||
// TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states
|
||||
// defined for container?
|
||||
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
||||
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
||||
// TODO(dchen1107): Introduce our own NetworkSettings struct here?
|
||||
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
||||
// usage should be included.
|
||||
// TODO(dchen1107): In long run, I think we should replace this with our own struct to remove
|
||||
// the dependency on docker.
|
||||
DetailInfo docker.Container `json:"detailInfo,omitempty" yaml:"detailInfo,omitempty"`
|
||||
}
|
||||
|
||||
// PodInfo contains one entry for every container with available info.
|
||||
// TODO(dchen1107): Replace docker.Container below with ContainerStatus defined above.
|
||||
type PodInfo map[string]docker.Container
|
||||
|
||||
type RestartPolicyAlways struct{}
|
||||
|
||||
// TODO(dchen1107): Define what kinds of failures should restart.
|
||||
// TODO(dchen1107): Decide whether to support policy knobs, and, if so, which ones.
|
||||
type RestartPolicyOnFailure struct{}
|
||||
|
||||
type RestartPolicyNever struct{}
|
||||
|
||||
type RestartPolicy struct {
|
||||
// Only one of the following restart policies may be specified.
|
||||
// If none of the following policies is specified, the default one
|
||||
// is RestartPolicyAlways.
|
||||
Always *RestartPolicyAlways `json:"always,omitempty" yaml:"always,omitempty"`
|
||||
OnFailure *RestartPolicyOnFailure `json:"onFailure,omitempty" yaml:"onFailure,omitempty"`
|
||||
Never *RestartPolicyNever `json:"never,omitempty" yaml:"never,omitempty"`
|
||||
}
|
||||
|
||||
// PodState is the state of a pod, used as either input (desired state) or output (current state).
|
||||
type PodState struct {
|
||||
Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"`
|
||||
Status PodStatus `json:"status,omitempty" yaml:"status,omitempty"`
|
||||
Host string `json:"host,omitempty" yaml:"host,omitempty"`
|
||||
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
|
||||
PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"`
|
||||
|
||||
// The key of this map is the *name* of the container within the manifest; it has one
|
||||
// entry per container in the manifest. The value of this map is currently the output
|
||||
// of `docker inspect`. This output format is *not* final and should not be relied
|
||||
// upon.
|
||||
// TODO: Make real decisions about what our info should look like. Re-enable fuzz test
|
||||
// when we have done this.
|
||||
Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"`
|
||||
}
|
||||
|
||||
// PodList is a list of Pods.
|
||||
type PodList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []Pod `json:"items" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*PodList) IsAnAPIObject() {}
|
||||
|
||||
// Pod is a collection of containers, used as either input (create, update) or as output (list, get).
|
||||
type Pod struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
|
||||
CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"`
|
||||
}
|
||||
|
||||
func (*Pod) IsAnAPIObject() {}
|
||||
|
||||
// ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get).
|
||||
type ReplicationControllerState struct {
|
||||
Replicas int `json:"replicas" yaml:"replicas"`
|
||||
ReplicaSelector map[string]string `json:"replicaSelector,omitempty" yaml:"replicaSelector,omitempty"`
|
||||
PodTemplate PodTemplate `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty"`
|
||||
}
|
||||
|
||||
// ReplicationControllerList is a collection of replication controllers.
|
||||
type ReplicationControllerList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*ReplicationControllerList) IsAnAPIObject() {}
|
||||
|
||||
// ReplicationController represents the configuration of a replication controller.
|
||||
type ReplicationController struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
DesiredState ReplicationControllerState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
|
||||
CurrentState ReplicationControllerState `json:"currentState,omitempty" yaml:"currentState,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
}
|
||||
|
||||
func (*ReplicationController) IsAnAPIObject() {}
|
||||
|
||||
// PodTemplate holds the information used for creating pods.
|
||||
type PodTemplate struct {
|
||||
DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceList holds a list of services.
|
||||
type ServiceList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []Service `json:"items" yaml:"items"`
|
||||
}
|
||||
|
||||
func (*ServiceList) IsAnAPIObject() {}
|
||||
|
||||
// Service is a named abstraction of software service (for example, mysql) consisting of local port
|
||||
// (for example 3306) that the proxy listens on, and the selector that determines which pods
|
||||
// will answer requests sent through the proxy.
|
||||
type Service struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
|
||||
// Required.
|
||||
Port int `json:"port" yaml:"port"`
|
||||
// Optional: Supports "TCP" and "UDP". Defaults to "TCP".
|
||||
Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
|
||||
|
||||
// This service's labels.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
|
||||
// This service will route traffic to pods having labels matching this selector.
|
||||
Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
|
||||
|
||||
// ContainerPort is the name of the port on the container to direct traffic to.
|
||||
// Optional, if unspecified use the first port on the container.
|
||||
ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"`
|
||||
}
|
||||
|
||||
func (*Service) IsAnAPIObject() {}
|
||||
|
||||
// Endpoints is a collection of endpoints that implement the actual service, for example:
|
||||
// Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"]
|
||||
type Endpoints struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty"`
|
||||
}
|
||||
|
||||
func (*Endpoints) IsAnAPIObject() {}
|
||||
|
||||
// EndpointsList is a list of endpoints.
|
||||
type EndpointsList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
Items []Endpoints `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*EndpointsList) IsAnAPIObject() {}
|
||||
|
||||
// Minion is a worker node in Kubernetenes.
|
||||
// The name of the minion according to etcd is in JSONBase.ID.
|
||||
type Minion struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
// Queried from cloud provider, if available.
|
||||
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
|
||||
}
|
||||
|
||||
func (*Minion) IsAnAPIObject() {}
|
||||
|
||||
// MinionList is a list of minions.
|
||||
type MinionList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
// DEPRECATED: the below Minions is due to a naming mistake and
|
||||
// will be replaced with Items in the future.
|
||||
Minions []Minion `json:"minions,omitempty" yaml:"minions,omitempty"`
|
||||
Items []Minion `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*MinionList) IsAnAPIObject() {}
|
||||
|
||||
// Binding is written by a scheduler to cause a pod to be bound to a host.
|
||||
type Binding struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
PodID string `json:"podID" yaml:"podID"`
|
||||
Host string `json:"host" yaml:"host"`
|
||||
}
|
||||
|
||||
func (*Binding) IsAnAPIObject() {}
|
||||
|
||||
// Status is a return value for calls that don't return other objects.
|
||||
// TODO: this could go in apiserver, but I'm including it here so clients needn't
|
||||
// import both.
|
||||
type Status struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
// One of: "success", "failure", "working" (for operations not yet completed)
|
||||
Status string `json:"status,omitempty" yaml:"status,omitempty"`
|
||||
// A human-readable description of the status of this operation.
|
||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||
// A machine-readable description of why this operation is in the
|
||||
// "failure" or "working" status. If this value is empty there
|
||||
// is no information available. A Reason clarifies an HTTP status
|
||||
// code but does not override it.
|
||||
Reason StatusReason `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||
// Extended data associated with the reason. Each reason may define its
|
||||
// own extended details. This field is optional and the data returned
|
||||
// is not guaranteed to conform to any schema except that defined by
|
||||
// the reason type.
|
||||
Details *StatusDetails `json:"details,omitempty" yaml:"details,omitempty"`
|
||||
// Suggested HTTP return code for this status, 0 if not set.
|
||||
Code int `json:"code,omitempty" yaml:"code,omitempty"`
|
||||
}
|
||||
|
||||
func (*Status) IsAnAPIObject() {}
|
||||
|
||||
// StatusDetails is a set of additional properties that MAY be set by the
|
||||
// server to provide additional information about a response. The Reason
|
||||
// field of a Status object defines what attributes will be set. Clients
|
||||
// must ignore fields that do not match the defined type of each attribute,
|
||||
// and should assume that any attribute may be empty, invalid, or under
|
||||
// defined.
|
||||
type StatusDetails struct {
|
||||
// The ID attribute of the resource associated with the status StatusReason
|
||||
// (when there is a single ID which can be described).
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
// The kind attribute of the resource associated with the status StatusReason.
|
||||
// On some operations may differ from the requested resource Kind.
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
// The Causes array includes more details associated with the StatusReason
|
||||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty" yaml:"causes,omitempty"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
const (
|
||||
StatusSuccess = "success"
|
||||
StatusFailure = "failure"
|
||||
StatusWorking = "working"
|
||||
)
|
||||
|
||||
// StatusReason is an enumeration of possible failure causes. Each StatusReason
|
||||
// must map to a single HTTP status code, but multiple reasons may map
|
||||
// to the same HTTP status code.
|
||||
// TODO: move to apiserver
|
||||
type StatusReason string
|
||||
|
||||
const (
|
||||
// StatusReasonUnknown means the server has declined to indicate a specific reason.
|
||||
// The details field may contain other information about this error.
|
||||
// Status code 500.
|
||||
StatusReasonUnknown StatusReason = ""
|
||||
|
||||
// StatusReasonWorking means the server is processing this request and will complete
|
||||
// at a future time.
|
||||
// Details (optional):
|
||||
// "kind" string - the name of the resource being referenced ("operation" today)
|
||||
// "id" string - the identifier of the Operation resource where updates
|
||||
// will be returned
|
||||
// Headers (optional):
|
||||
// "Location" - HTTP header populated with a URL that can retrieved the final
|
||||
// status of this operation.
|
||||
// Status code 202
|
||||
StatusReasonWorking StatusReason = "working"
|
||||
|
||||
// StatusReasonNotFound means one or more resources required for this operation
|
||||
// could not be found.
|
||||
// Details (optional):
|
||||
// "kind" string - the kind attribute of the missing resource
|
||||
// on some operations may differ from the requested
|
||||
// resource.
|
||||
// "id" string - the identifier of the missing resource
|
||||
// Status code 404
|
||||
StatusReasonNotFound StatusReason = "not_found"
|
||||
|
||||
// StatusReasonAlreadyExists means the resource you are creating already exists.
|
||||
// Details (optional):
|
||||
// "kind" string - the kind attribute of the conflicting resource
|
||||
// "id" string - the identifier of the conflicting resource
|
||||
// Status code 409
|
||||
StatusReasonAlreadyExists StatusReason = "already_exists"
|
||||
|
||||
// StatusReasonConflict means the requested update operation cannot be completed
|
||||
// due to a conflict in the operation. The client may need to alter the request.
|
||||
// Each resource may define custom details that indicate the nature of the
|
||||
// conflict.
|
||||
// Status code 409
|
||||
StatusReasonConflict StatusReason = "conflict"
|
||||
|
||||
// StatusReasonInvalid means the requested create or update operation cannot be
|
||||
// completed due to invalid data provided as part of the request. The client may
|
||||
// need to alter the request. When set, the client may use the StatusDetails
|
||||
// message field as a summary of the issues encountered.
|
||||
// Details (optional):
|
||||
// "kind" string - the kind attribute of the invalid resource
|
||||
// "id" string - the identifier of the invalid resource
|
||||
// "causes" - one or more StatusCause entries indicating the data in the
|
||||
// provided resource that was invalid. The code, message, and
|
||||
// field attributes will be set.
|
||||
// Status code 422
|
||||
StatusReasonInvalid StatusReason = "invalid"
|
||||
)
|
||||
|
||||
// StatusCause provides more information about an api.Status failure, including
|
||||
// cases when multiple errors are encountered.
|
||||
type StatusCause struct {
|
||||
// A machine-readable description of the cause of the error. If this value is
|
||||
// empty there is no information available.
|
||||
Type CauseType `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||
// A human-readable description of the cause of the error. This field may be
|
||||
// presented as-is to a reader.
|
||||
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||
// The field of the resource that has caused this error, as named by its JSON
|
||||
// serialization. May include dot and postfix notation for nested attributes.
|
||||
// Arrays are zero-indexed. Fields may appear more than once in an array of
|
||||
// causes due to fields having multiple errors.
|
||||
// Optional.
|
||||
//
|
||||
// Examples:
|
||||
// "name" - the field "name" on the current resource
|
||||
// "items[0].name" - the field "name" on the first array entry in "items"
|
||||
Field string `json:"field,omitempty" yaml:"field,omitempty"`
|
||||
}
|
||||
|
||||
// CauseType is a machine readable value providing more detail about what
|
||||
// occured in a status response. An operation may have multiple causes for a
|
||||
// status (whether failure, success, or working).
|
||||
type CauseType string
|
||||
|
||||
const (
|
||||
// CauseTypeFieldValueNotFound is used to report failure to find a requested value
|
||||
// (e.g. looking up an ID).
|
||||
CauseTypeFieldValueNotFound CauseType = "fieldValueNotFound"
|
||||
// CauseTypeFieldValueInvalid is used to report required values that are not
|
||||
// provided (e.g. empty strings, null values, or empty arrays).
|
||||
CauseTypeFieldValueRequired CauseType = "fieldValueRequired"
|
||||
// CauseTypeFieldValueDuplicate is used to report collisions of values that must be
|
||||
// unique (e.g. unique IDs).
|
||||
CauseTypeFieldValueDuplicate CauseType = "fieldValueDuplicate"
|
||||
// CauseTypeFieldValueInvalid is used to report malformed values (e.g. failed regex
|
||||
// match).
|
||||
CauseTypeFieldValueInvalid CauseType = "fieldValueInvalid"
|
||||
// CauseTypeFieldValueNotSupported is used to report valid (as per formatting rules)
|
||||
// values that can not be handled (e.g. an enumerated string).
|
||||
CauseTypeFieldValueNotSupported CauseType = "fieldValueNotSupported"
|
||||
)
|
||||
|
||||
// ServerOp is an operation delivered to API clients.
|
||||
type ServerOp struct {
|
||||
JSONBase `yaml:",inline" json:",inline"`
|
||||
}
|
||||
|
||||
func (*ServerOp) IsAnAPIObject() {}
|
||||
|
||||
// ServerOpList is a list of operations, as delivered to API clients.
|
||||
type ServerOpList struct {
|
||||
JSONBase `yaml:",inline" json:",inline"`
|
||||
Items []ServerOp `yaml:"items,omitempty" json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*ServerOpList) IsAnAPIObject() {}
|
@@ -14,12 +14,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
package v1beta3
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
@@ -55,8 +53,8 @@ type ContainerManifest struct {
|
||||
// Required: This must be a DNS_SUBDOMAIN.
|
||||
// TODO: ID on Manifest is deprecated and will be removed in the future.
|
||||
ID string `yaml:"id" json:"id"`
|
||||
// TODO: UUID on Manifext is deprecated in the future once we are done
|
||||
// with the API refactory. It is required for now to determine the instance
|
||||
// TODO: UUID on Manifest is deprecated in the future once we are done
|
||||
// with the API refactoring. It is required for now to determine the instance
|
||||
// of a Pod.
|
||||
UUID string `yaml:"uuid,omitempty" json:"uuid,omitempty"`
|
||||
Volumes []Volume `yaml:"volumes" json:"volumes"`
|
||||
@@ -124,22 +122,13 @@ type VolumeMount struct {
|
||||
// Optional: Defaults to false (read-write).
|
||||
ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
|
||||
// Required.
|
||||
// Exactly one of the following must be set. If both are set, prefer MountPath.
|
||||
// DEPRECATED: Path will be removed in a future version of the API.
|
||||
MountPath string `yaml:"mountPath,omitempty" json:"mountPath,omitempty"`
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
// One of: "LOCAL" (local volume) or "HOST" (external mount from the host). Default: LOCAL.
|
||||
// DEPRECATED: MountType will be removed in a future version of the API.
|
||||
MountType string `yaml:"mountType,omitempty" json:"mountType,omitempty"`
|
||||
}
|
||||
|
||||
// EnvVar represents an environment variable present in a Container.
|
||||
type EnvVar struct {
|
||||
// Required: This must be a C_IDENTIFIER.
|
||||
// Exactly one of the following must be set. If both are set, prefer Name.
|
||||
// DEPRECATED: EnvVar.Key will be removed in a future version of the API.
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Key string `yaml:"key,omitempty" json:"key,omitempty"`
|
||||
// Optional: defaults to "".
|
||||
Value string `yaml:"value,omitempty" json:"value,omitempty"`
|
||||
}
|
||||
@@ -166,7 +155,6 @@ type ExecAction struct {
|
||||
// command is root ('/') in the container's filesystem. The command is simply exec'd, it is
|
||||
// not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
|
||||
// a shell, you need to explicitly call out to that shell.
|
||||
// A return code of zero is treated as 'Healthy', non-zero is 'Unhealthy'
|
||||
Command []string `yaml:"command,omitempty" json:"command,omitempty"`
|
||||
}
|
||||
|
||||
@@ -210,7 +198,6 @@ type Container struct {
|
||||
}
|
||||
|
||||
// Handler defines a specific action that should be taken
|
||||
// TODO: merge this with liveness probing?
|
||||
// TODO: pass structured data to these actions, and document that data here.
|
||||
type Handler struct {
|
||||
// One and only one of the following should be specified.
|
||||
@@ -252,8 +239,6 @@ type JSONBase struct {
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
func (*JSONBase) IsAnAPIObject() {}
|
||||
|
||||
// PodStatus represents a status of a pod.
|
||||
type PodStatus string
|
||||
|
||||
@@ -303,18 +288,19 @@ type ContainerStatus struct {
|
||||
}
|
||||
|
||||
// PodInfo contains one entry for every container with available info.
|
||||
// TODO(dchen1107): Replace docker.Container below with ContainerStatus defined above.
|
||||
type PodInfo map[string]docker.Container
|
||||
|
||||
type RestartPolicyAlways struct{}
|
||||
|
||||
// TODO(dchen1107): Define what kinds of failures should restart
|
||||
// TODO(dchen1107): Define what kinds of failures should restart.
|
||||
// TODO(dchen1107): Decide whether to support policy knobs, and, if so, which ones.
|
||||
type RestartPolicyOnFailure struct{}
|
||||
|
||||
type RestartPolicyNever struct{}
|
||||
|
||||
type RestartPolicy struct {
|
||||
// Only one of the following restart policy may be specified.
|
||||
// Only one of the following restart policies may be specified.
|
||||
// If none of the following policies is specified, the default one
|
||||
// is RestartPolicyAlways.
|
||||
Always *RestartPolicyAlways `json:"always,omitempty" yaml:"always,omitempty"`
|
||||
@@ -333,9 +319,9 @@ type PodState struct {
|
||||
// The key of this map is the *name* of the container within the manifest; it has one
|
||||
// entry per container in the manifest. The value of this map is currently the output
|
||||
// of `docker inspect`. This output format is *not* final and should not be relied
|
||||
// upon. To allow marshalling/unmarshalling, we copied the client's structs and added
|
||||
// json/yaml tags.
|
||||
// TODO: Make real decisions about what our info should look like.
|
||||
// upon.
|
||||
// TODO: Make real decisions about what our info should look like. Re-enable fuzz test
|
||||
// when we have done this.
|
||||
Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"`
|
||||
}
|
||||
|
||||
@@ -451,10 +437,7 @@ func (*Minion) IsAnAPIObject() {}
|
||||
// MinionList is a list of minions.
|
||||
type MinionList struct {
|
||||
JSONBase `json:",inline" yaml:",inline"`
|
||||
// DEPRECATED: the below Minions is due to a naming mistake and
|
||||
// will be replaced with Items in the future.
|
||||
Minions []Minion `json:"minions,omitempty" yaml:"minions,omitempty"`
|
||||
Items []Minion `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
Items []Minion `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (*MinionList) IsAnAPIObject() {}
|
||||
@@ -550,14 +533,14 @@ const (
|
||||
// resource.
|
||||
// "id" string - the identifier of the missing resource
|
||||
// Status code 404
|
||||
StatusReasonNotFound StatusReason = "notFound"
|
||||
StatusReasonNotFound StatusReason = "not_found"
|
||||
|
||||
// StatusReasonAlreadyExists means the resource you are creating already exists.
|
||||
// Details (optional):
|
||||
// "kind" string - the kind attribute of the conflicting resource
|
||||
// "id" string - the identifier of the conflicting resource
|
||||
// Status code 409
|
||||
StatusReasonAlreadyExists StatusReason = "alreadyExists"
|
||||
StatusReasonAlreadyExists StatusReason = "already_exists"
|
||||
|
||||
// StatusReasonConflict means the requested update operation cannot be completed
|
||||
// due to a conflict in the operation. The client may need to alter the request.
|
||||
@@ -565,6 +548,19 @@ const (
|
||||
// conflict.
|
||||
// Status code 409
|
||||
StatusReasonConflict StatusReason = "conflict"
|
||||
|
||||
// StatusReasonInvalid means the requested create or update operation cannot be
|
||||
// completed due to invalid data provided as part of the request. The client may
|
||||
// need to alter the request. When set, the client may use the StatusDetails
|
||||
// message field as a summary of the issues encountered.
|
||||
// Details (optional):
|
||||
// "kind" string - the kind attribute of the invalid resource
|
||||
// "id" string - the identifier of the invalid resource
|
||||
// "causes" - one or more StatusCause entries indicating the data in the
|
||||
// provided resource that was invalid. The code, message, and
|
||||
// field attributes will be set.
|
||||
// Status code 422
|
||||
StatusReasonInvalid StatusReason = "invalid"
|
||||
)
|
||||
|
||||
// StatusCause provides more information about an api.Status failure, including
|
||||
@@ -625,13 +621,3 @@ type ServerOpList struct {
|
||||
}
|
||||
|
||||
func (*ServerOpList) IsAnAPIObject() {}
|
||||
|
||||
// WatchEvent objects are streamed from the api server in response to a watch request.
|
||||
type WatchEvent struct {
|
||||
// The type of the watch event; added, modified, or deleted.
|
||||
Type watch.EventType
|
||||
|
||||
// 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 runtime.EmbeddedObject
|
||||
}
|
||||
|
57
pkg/api/watch.go
Normal file
57
pkg/api/watch.go
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// WatchEvent objects are streamed from the api server in response to a watch request.
|
||||
// These are not API objects and are unversioned today.
|
||||
type WatchEvent struct {
|
||||
// The type of the watch event; added, modified, or deleted.
|
||||
Type watch.EventType
|
||||
|
||||
// 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 EmbeddedObject
|
||||
}
|
||||
|
||||
// watchSerialization defines the JSON wire equivalent of watch.Event
|
||||
type watchSerialization struct {
|
||||
Type watch.EventType
|
||||
Object json.RawMessage
|
||||
}
|
||||
|
||||
// NewJSONWatcHEvent returns an object that will serialize to JSON and back
|
||||
// to a WatchEvent.
|
||||
func NewJSONWatchEvent(codec runtime.Codec, event watch.Event) (interface{}, error) {
|
||||
obj, ok := event.Object.(runtime.Object)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("The event object cannot be safely converted to JSON: %v", reflect.TypeOf(event.Object).Name())
|
||||
}
|
||||
data, err := codec.Encode(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &watchSerialization{event.Type, json.RawMessage(data)}, nil
|
||||
}
|
43
pkg/api/watch_test.go
Normal file
43
pkg/api/watch_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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 (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEmbeddedDefaultSerialization(t *testing.T) {
|
||||
expected := WatchEvent{
|
||||
Type: "foo",
|
||||
Object: EmbeddedObject{&Pod{}},
|
||||
}
|
||||
data, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
actual := WatchEvent{}
|
||||
if err := json.Unmarshal(data, &actual); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("Expected %#v, Got %#v", expected, actual)
|
||||
}
|
||||
}
|
@@ -32,6 +32,7 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@@ -43,11 +44,11 @@ func convert(obj runtime.Object) (runtime.Object, error) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
var codec = runtime.DefaultCodec
|
||||
var codec = latest.Codec
|
||||
|
||||
func init() {
|
||||
runtime.DefaultScheme.AddKnownTypes("", &Simple{}, &SimpleList{})
|
||||
runtime.DefaultScheme.AddKnownTypes("v1beta1", &Simple{}, &SimpleList{})
|
||||
api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{})
|
||||
api.Scheme.AddKnownTypes(latest.Version, &Simple{}, &SimpleList{})
|
||||
}
|
||||
|
||||
type Simple struct {
|
||||
@@ -95,7 +96,7 @@ func (storage *SimpleRESTStorage) List(labels.Selector) (runtime.Object, error)
|
||||
}
|
||||
|
||||
func (storage *SimpleRESTStorage) Get(id string) (runtime.Object, error) {
|
||||
return runtime.DefaultScheme.CopyOrDie(&storage.item), storage.errors["get"]
|
||||
return api.Scheme.CopyOrDie(&storage.item), storage.errors["get"]
|
||||
}
|
||||
|
||||
func (storage *SimpleRESTStorage) Delete(id string) (<-chan runtime.Object, error) {
|
||||
@@ -676,7 +677,7 @@ func (*UnregisteredAPIObject) IsAnAPIObject() {}
|
||||
|
||||
func TestWriteJSONDecodeError(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
writeJSON(http.StatusOK, runtime.DefaultCodec, &UnregisteredAPIObject{"Undecodable"}, w)
|
||||
writeJSON(http.StatusOK, latest.Codec, &UnregisteredAPIObject{"Undecodable"}, w)
|
||||
}))
|
||||
status := expectApiStatus(t, "GET", server.URL, nil, http.StatusInternalServerError)
|
||||
if status.Reason != api.StatusReasonUnknown {
|
||||
|
@@ -74,7 +74,7 @@ func (h *WatchHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
// TODO: This is one watch per connection. We want to multiplex, so that
|
||||
// multiple watches of the same thing don't create two watches downstream.
|
||||
watchServer := &WatchServer{watching}
|
||||
watchServer := &WatchServer{watching, h.codec}
|
||||
if req.Header.Get("Connection") == "Upgrade" && req.Header.Get("Upgrade") == "websocket" {
|
||||
websocket.Handler(watchServer.HandleWS).ServeHTTP(httplog.Unlogged(w), req)
|
||||
} else {
|
||||
@@ -89,6 +89,7 @@ func (h *WatchHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// WatchServer serves a watch.Interface over a websocket or vanilla HTTP.
|
||||
type WatchServer struct {
|
||||
watching watch.Interface
|
||||
codec runtime.Codec
|
||||
}
|
||||
|
||||
// HandleWS implements a websocket handler.
|
||||
@@ -111,15 +112,17 @@ func (w *WatchServer) HandleWS(ws *websocket.Conn) {
|
||||
// End of results.
|
||||
return
|
||||
}
|
||||
err := websocket.JSON.Send(ws, &api.WatchEvent{
|
||||
Type: event.Type,
|
||||
Object: runtime.EmbeddedObject{event.Object},
|
||||
})
|
||||
obj, err := api.NewJSONWatchEvent(w.codec, event)
|
||||
if err != nil {
|
||||
// Client disconnect.
|
||||
w.watching.Stop()
|
||||
return
|
||||
}
|
||||
if err := websocket.JSON.Send(ws, obj); err != nil {
|
||||
// Client disconnect.
|
||||
w.watching.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,15 +161,17 @@ func (self *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// End of results.
|
||||
return
|
||||
}
|
||||
err := encoder.Encode(&api.WatchEvent{
|
||||
Type: event.Type,
|
||||
Object: runtime.EmbeddedObject{event.Object},
|
||||
})
|
||||
obj, err := api.NewJSONWatchEvent(self.codec, event)
|
||||
if err != nil {
|
||||
// Client disconnect.
|
||||
self.watching.Stop()
|
||||
return
|
||||
}
|
||||
if err := encoder.Encode(obj); err != nil {
|
||||
// Client disconnect.
|
||||
self.watching.Stop()
|
||||
return
|
||||
}
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
@@ -114,26 +114,22 @@ func TestWatchHTTP(t *testing.T) {
|
||||
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
|
||||
try := func(action watch.EventType, object runtime.Object) {
|
||||
for i, item := range watchTestTable {
|
||||
// Send
|
||||
simpleStorage.fakeWatch.Action(action, object)
|
||||
simpleStorage.fakeWatch.Action(item.t, item.obj)
|
||||
// Test receive
|
||||
var got api.WatchEvent
|
||||
err := decoder.Decode(&got)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
t.Fatalf("%d: Unexpected error: %v", i, err)
|
||||
}
|
||||
if got.Type != action {
|
||||
t.Errorf("Unexpected type: %v", got.Type)
|
||||
if got.Type != item.t {
|
||||
t.Errorf("%d: Unexpected type: %v", i, got.Type)
|
||||
}
|
||||
if e, a := object, got.Object.Object; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
if e, a := item.obj, got.Object.Object; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%d: Expected %v, got %v", i, e, a)
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range watchTestTable {
|
||||
try(item.t, item.obj)
|
||||
}
|
||||
simpleStorage.fakeWatch.Stop()
|
||||
|
||||
var got api.WatchEvent
|
||||
|
@@ -26,7 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||
@@ -99,7 +99,7 @@ type Client struct {
|
||||
// to a URL will prepend the server path. Returns an error if host cannot be converted to a
|
||||
// valid URL.
|
||||
func New(host string, auth *AuthInfo) (*Client, error) {
|
||||
restClient, err := NewRESTClient(host, auth, "/api/v1beta1/", runtime.DefaultCodec)
|
||||
restClient, err := NewRESTClient(host, auth, "/api/v1beta1/", latest.Codec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -224,7 +224,7 @@ func (c *RESTClient) doRequest(request *http.Request) ([]byte, error) {
|
||||
// Did the server give us a status response?
|
||||
isStatusResponse := false
|
||||
var status api.Status
|
||||
if err := runtime.DefaultCodec.DecodeInto(body, &status); err == nil && status.Status != "" {
|
||||
if err := latest.Codec.DecodeInto(body, &status); err == nil && status.Status != "" {
|
||||
isStatusResponse = true
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@@ -48,7 +49,7 @@ func TestValidatesHostParameter(t *testing.T) {
|
||||
"host/server": {"", "", true},
|
||||
}
|
||||
for k, expected := range testCases {
|
||||
c, err := NewRESTClient(k, nil, "/api/v1beta1/", runtime.DefaultCodec)
|
||||
c, err := NewRESTClient(k, nil, "/api/v1beta1/", latest.Codec)
|
||||
switch {
|
||||
case err == nil && expected.Err:
|
||||
t.Errorf("expected error but was nil")
|
||||
@@ -309,7 +310,7 @@ func TestCreateController(t *testing.T) {
|
||||
|
||||
func body(obj runtime.Object, raw *string) *string {
|
||||
if obj != nil {
|
||||
bs, _ := runtime.DefaultCodec.Encode(obj)
|
||||
bs, _ := latest.Codec.Encode(obj)
|
||||
body := string(bs)
|
||||
return &body
|
||||
}
|
||||
@@ -533,7 +534,7 @@ func TestDoRequest(t *testing.T) {
|
||||
|
||||
func TestDoRequestAccepted(t *testing.T) {
|
||||
status := &api.Status{Status: api.StatusWorking}
|
||||
expectedBody, _ := runtime.DefaultCodec.Encode(status)
|
||||
expectedBody, _ := latest.Codec.Encode(status)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 202,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -570,7 +571,7 @@ func TestDoRequestAccepted(t *testing.T) {
|
||||
|
||||
func TestDoRequestAcceptedSuccess(t *testing.T) {
|
||||
status := &api.Status{Status: api.StatusSuccess}
|
||||
expectedBody, _ := runtime.DefaultCodec.Encode(status)
|
||||
expectedBody, _ := latest.Codec.Encode(status)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 202,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -590,7 +591,7 @@ func TestDoRequestAcceptedSuccess(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %#v", err)
|
||||
}
|
||||
statusOut, err := runtime.DefaultCodec.Decode(body)
|
||||
statusOut, err := latest.Codec.Decode(body)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %#v", err)
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@ package client
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
@@ -44,7 +43,7 @@ type Fake struct {
|
||||
|
||||
func (c *Fake) ListPods(selector labels.Selector) (*api.PodList, error) {
|
||||
c.Actions = append(c.Actions, FakeAction{Action: "list-pods"})
|
||||
return runtime.DefaultScheme.CopyOrDie(&c.Pods).(*api.PodList), nil
|
||||
return api.Scheme.CopyOrDie(&c.Pods).(*api.PodList), nil
|
||||
}
|
||||
|
||||
func (c *Fake) GetPod(name string) (*api.Pod, error) {
|
||||
@@ -74,7 +73,7 @@ func (c *Fake) ListReplicationControllers(selector labels.Selector) (*api.Replic
|
||||
|
||||
func (c *Fake) GetReplicationController(name string) (*api.ReplicationController, error) {
|
||||
c.Actions = append(c.Actions, FakeAction{Action: "get-controller", Value: name})
|
||||
return runtime.DefaultScheme.CopyOrDie(&c.Ctrl).(*api.ReplicationController), nil
|
||||
return api.Scheme.CopyOrDie(&c.Ctrl).(*api.ReplicationController), nil
|
||||
}
|
||||
|
||||
func (c *Fake) CreateReplicationController(controller *api.ReplicationController) (*api.ReplicationController, error) {
|
||||
@@ -129,7 +128,7 @@ func (c *Fake) WatchServices(label, field labels.Selector, resourceVersion uint6
|
||||
|
||||
func (c *Fake) ListEndpoints(selector labels.Selector) (*api.EndpointsList, error) {
|
||||
c.Actions = append(c.Actions, FakeAction{Action: "list-endpoints"})
|
||||
return runtime.DefaultScheme.CopyOrDie(&c.EndpointsList).(*api.EndpointsList), c.Err
|
||||
return api.Scheme.CopyOrDie(&c.EndpointsList).(*api.EndpointsList), c.Err
|
||||
}
|
||||
|
||||
func (c *Fake) WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
|
||||
|
@@ -28,9 +28,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
cwatch "github.com/GoogleCloudPlatform/kubernetes/pkg/client/watch"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
"github.com/golang/glog"
|
||||
@@ -269,7 +269,7 @@ func (r *Request) Watch() (watch.Interface, error) {
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Got status: %v", response.StatusCode)
|
||||
}
|
||||
return watch.NewStreamWatcher(tools.NewAPIEventDecoder(response.Body)), nil
|
||||
return watch.NewStreamWatcher(cwatch.NewAPIEventDecoder(response.Body)), nil
|
||||
}
|
||||
|
||||
// Do formats and executes the request. Returns the API object received, or an error.
|
||||
|
@@ -29,6 +29,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@@ -38,7 +39,7 @@ import (
|
||||
func TestDoRequestNewWay(t *testing.T) {
|
||||
reqBody := "request body"
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -71,9 +72,9 @@ func TestDoRequestNewWay(t *testing.T) {
|
||||
|
||||
func TestDoRequestNewWayReader(t *testing.T) {
|
||||
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
reqBodyExpected, _ := runtime.DefaultCodec.Encode(reqObj)
|
||||
reqBodyExpected, _ := latest.Codec.Encode(reqObj)
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -108,9 +109,9 @@ func TestDoRequestNewWayReader(t *testing.T) {
|
||||
|
||||
func TestDoRequestNewWayObj(t *testing.T) {
|
||||
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
reqBodyExpected, _ := runtime.DefaultCodec.Encode(reqObj)
|
||||
reqBodyExpected, _ := latest.Codec.Encode(reqObj)
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -144,7 +145,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
|
||||
|
||||
func TestDoRequestNewWayFile(t *testing.T) {
|
||||
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
reqBodyExpected, err := runtime.DefaultCodec.Encode(reqObj)
|
||||
reqBodyExpected, err := latest.Codec.Encode(reqObj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -160,7 +161,7 @@ func TestDoRequestNewWayFile(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -295,7 +296,7 @@ func TestPolling(t *testing.T) {
|
||||
|
||||
callNumber := 0
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := runtime.DefaultCodec.Encode(objects[callNumber])
|
||||
data, err := latest.Codec.Encode(objects[callNumber])
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected encode error")
|
||||
}
|
||||
@@ -401,7 +402,13 @@ func TestWatch(t *testing.T) {
|
||||
|
||||
encoder := json.NewEncoder(w)
|
||||
for _, item := range table {
|
||||
encoder.Encode(&api.WatchEvent{item.t, runtime.EmbeddedObject{item.obj}})
|
||||
data, err := api.NewJSONWatchEvent(latest.Codec, watch.Event{item.t, item.obj})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
flusher.Flush()
|
||||
}
|
||||
}))
|
||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tools
|
||||
package watch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -28,6 +28,8 @@ import (
|
||||
|
||||
// APIEventDecoder implements the watch.Decoder interface for io.ReadClosers that
|
||||
// have contents which consist of a series of api.WatchEvent objects encoded via JSON.
|
||||
// It will decode any object which is registered to convert to api.WatchEvent via
|
||||
// api.Scheme
|
||||
type APIEventDecoder struct {
|
||||
stream io.ReadCloser
|
||||
decoder *json.Decoder
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tools
|
||||
package watch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -24,29 +24,37 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
type watchSerialization struct {
|
||||
Type watch.EventType
|
||||
Object json.RawMessage
|
||||
}
|
||||
|
||||
func TestDecoder(t *testing.T) {
|
||||
out, in := io.Pipe()
|
||||
encoder := json.NewEncoder(in)
|
||||
decoder := NewAPIEventDecoder(out)
|
||||
|
||||
expect := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
encoder := json.NewEncoder(in)
|
||||
go func() {
|
||||
err := encoder.Encode(api.WatchEvent{watch.Added, runtime.EmbeddedObject{expect}})
|
||||
data, err := v1beta1.Codec.Encode(expect)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
if err := encoder.Encode(&watchSerialization{watch.Added, json.RawMessage(data)}); err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
in.Close()
|
||||
}()
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
action, got, err := decoder.Decode()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
if e, a := watch.Added, action; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
@@ -54,17 +62,12 @@ func TestDecoder(t *testing.T) {
|
||||
if e, a := expect, got; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
t.Logf("Exited read")
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
break
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Error("Timeout")
|
||||
}
|
||||
<-done
|
||||
|
||||
done = make(chan struct{})
|
||||
|
||||
go func() {
|
||||
_, _, err := decoder.Decode()
|
||||
if err == nil {
|
||||
@@ -72,15 +75,9 @@ func TestDecoder(t *testing.T) {
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
<-done
|
||||
|
||||
decoder.Close()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
break
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Error("Timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecoder_SourceClose(t *testing.T) {
|
@@ -27,6 +27,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@@ -109,7 +111,7 @@ func validateSyncReplication(t *testing.T, fakePodControl *FakePodControl, expec
|
||||
}
|
||||
|
||||
func TestSyncReplicationControllerDoesNothing(t *testing.T) {
|
||||
body, _ := runtime.DefaultCodec.Encode(newPodList(2))
|
||||
body, _ := latest.Codec.Encode(newPodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@@ -129,7 +131,7 @@ func TestSyncReplicationControllerDoesNothing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncReplicationControllerDeletes(t *testing.T) {
|
||||
body, _ := runtime.DefaultCodec.Encode(newPodList(2))
|
||||
body, _ := latest.Codec.Encode(newPodList(2))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@@ -149,7 +151,7 @@ func TestSyncReplicationControllerDeletes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncReplicationControllerCreates(t *testing.T) {
|
||||
body, _ := runtime.DefaultCodec.Encode(newPodList(0))
|
||||
body, _ := latest.Codec.Encode(newPodList(0))
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@@ -169,7 +171,7 @@ func TestSyncReplicationControllerCreates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreateReplica(t *testing.T) {
|
||||
body, _ := runtime.DefaultCodec.Encode(&api.Pod{})
|
||||
body, _ := v1beta1.Codec.Encode(&api.Pod{})
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(body),
|
||||
@@ -209,7 +211,7 @@ func TestCreateReplica(t *testing.T) {
|
||||
expectedPod := api.Pod{
|
||||
JSONBase: api.JSONBase{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1beta1",
|
||||
APIVersion: latest.Version,
|
||||
},
|
||||
Labels: controllerSpec.DesiredState.PodTemplate.Labels,
|
||||
DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState,
|
||||
@@ -287,12 +289,12 @@ func TestSyncronize(t *testing.T) {
|
||||
|
||||
fakePodHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: "{\"apiVersion\": \"v1beta1\", \"kind\": \"PodList\"}",
|
||||
ResponseBody: "{\"apiVersion\": \"" + latest.Version + "\", \"kind\": \"PodList\"}",
|
||||
T: t,
|
||||
}
|
||||
fakeControllerHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: runtime.DefaultScheme.EncodeOrDie(&api.ReplicationControllerList{
|
||||
ResponseBody: runtime.EncodeOrDie(latest.Codec, &api.ReplicationControllerList{
|
||||
Items: []api.ReplicationController{
|
||||
controllerSpec1,
|
||||
controllerSpec2,
|
||||
|
@@ -25,14 +25,14 @@ import (
|
||||
// Decode converts a YAML or JSON string back into a pointer to an api object.
|
||||
// Deduces the type based upon the fields added by the MetaInsertionFactory
|
||||
// technique. The object will be converted, if necessary, into the
|
||||
// s.InternalVersion type before being returned. Decode will refuse to decode
|
||||
// objects without a version, because that's probably an error.
|
||||
// s.InternalVersion type before being returned. Decode will not decode
|
||||
// objects without version set unless InternalVersion is also "".
|
||||
func (s *Scheme) Decode(data []byte) (interface{}, error) {
|
||||
version, kind, err := s.DataVersionAndKind(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if version == "" {
|
||||
if version == "" && s.InternalVersion != "" {
|
||||
return nil, fmt.Errorf("version not set in '%s'", string(data))
|
||||
}
|
||||
obj, err := s.NewObject(version, kind)
|
||||
|
@@ -21,16 +21,7 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests.
|
||||
func (s *Scheme) EncodeOrDie(obj interface{}) string {
|
||||
bytes, err := s.Encode(obj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// Encode turns the given api object into an appropriate JSON string.
|
||||
// EncodeToVersion turns the given api object into an appropriate JSON string.
|
||||
// Obj may be a pointer to a struct, or a struct. If a struct, a copy
|
||||
// will be made, therefore it's recommended to pass a pointer to a
|
||||
// struct. The type must have been registered.
|
||||
@@ -58,11 +49,6 @@ func (s *Scheme) EncodeOrDie(obj interface{}) string {
|
||||
// objects, whether they be in our storage layer (e.g., etcd), or in user's
|
||||
// config files.
|
||||
//
|
||||
func (s *Scheme) Encode(obj interface{}) (data []byte, err error) {
|
||||
return s.EncodeToVersion(obj, s.ExternalVersion)
|
||||
}
|
||||
|
||||
// EncodeToVersion is like Encode, but you may choose the version.
|
||||
func (s *Scheme) EncodeToVersion(obj interface{}, destVersion string) (data []byte, err error) {
|
||||
obj = maybeCopy(obj)
|
||||
v, _ := enforcePtr(obj) // maybeCopy guarantees a pointer
|
||||
|
@@ -66,9 +66,6 @@ type Scheme struct {
|
||||
// you use "" for the internal version.
|
||||
InternalVersion string
|
||||
|
||||
// ExternalVersion is the default external version.
|
||||
ExternalVersion string
|
||||
|
||||
// MetaInsertionFactory is used to create an object to store and retrieve
|
||||
// the version and kind information for all objects. The default uses the
|
||||
// keys "version" and "kind" respectively.
|
||||
@@ -83,7 +80,6 @@ func NewScheme() *Scheme {
|
||||
typeToKind: map[reflect.Type]string{},
|
||||
converter: NewConverter(),
|
||||
InternalVersion: "",
|
||||
ExternalVersion: "v1",
|
||||
MetaInsertionFactory: metaInsertion{},
|
||||
}
|
||||
s.converter.NameFunc = s.nameFunc
|
||||
@@ -146,6 +142,19 @@ func (s *Scheme) AddKnownTypeWithName(version, kind string, obj interface{}) {
|
||||
s.typeToKind[t] = kind
|
||||
}
|
||||
|
||||
// KnownTypes returns an array of the types that are known for a particular version.
|
||||
func (s *Scheme) KnownTypes(version string) map[string]reflect.Type {
|
||||
all, ok := s.versionMap[version]
|
||||
if !ok {
|
||||
return map[string]reflect.Type{}
|
||||
}
|
||||
types := make(map[string]reflect.Type)
|
||||
for k, v := range all {
|
||||
types[k] = v
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@@ -125,7 +125,6 @@ func GetTestScheme() *Scheme {
|
||||
s.AddKnownTypes("v1", &ExternalInternalSame{})
|
||||
s.AddKnownTypeWithName("v1", "TestType1", &ExternalTestType1{})
|
||||
s.AddKnownTypeWithName("v1", "TestType2", &ExternalTestType2{})
|
||||
s.ExternalVersion = "v1"
|
||||
s.InternalVersion = ""
|
||||
s.MetaInsertionFactory = testMetaInsertionFactory{}
|
||||
return s
|
||||
@@ -178,7 +177,7 @@ func runTest(t *testing.T, source interface{}) {
|
||||
TestObjectFuzzer.Fuzz(source)
|
||||
|
||||
s := GetTestScheme()
|
||||
data, err := s.Encode(source)
|
||||
data, err := s.EncodeToVersion(source, "v1")
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v (%#v)", name, err, source)
|
||||
return
|
||||
@@ -221,7 +220,7 @@ func TestEncode_NonPtr(t *testing.T) {
|
||||
s := GetTestScheme()
|
||||
tt := TestType1{A: "I'm not a pointer object"}
|
||||
obj := interface{}(tt)
|
||||
data, err := s.Encode(obj)
|
||||
data, err := s.EncodeToVersion(obj, "v1")
|
||||
obj2, err2 := s.Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
@@ -238,7 +237,7 @@ func TestEncode_Ptr(t *testing.T) {
|
||||
s := GetTestScheme()
|
||||
tt := &TestType1{A: "I am a pointer object"}
|
||||
obj := interface{}(tt)
|
||||
data, err := s.Encode(obj)
|
||||
data, err := s.EncodeToVersion(obj, "v1")
|
||||
obj2, err2 := s.Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
@@ -255,7 +254,6 @@ func TestBadJSONRejection(t *testing.T) {
|
||||
s := GetTestScheme()
|
||||
badJSONs := [][]byte{
|
||||
[]byte(`{"myVersionKey":"v1"}`), // Missing kind
|
||||
[]byte(`{"myKindKey":"TestType1"}`), // Missing version
|
||||
[]byte(`{"myVersionKey":"v1","myKindKey":"bar"}`), // Unknown kind
|
||||
[]byte(`{"myVersionKey":"bar","myKindKey":"TestType1"}`), // Unknown version
|
||||
}
|
||||
@@ -270,6 +268,23 @@ func TestBadJSONRejection(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadJSONRejectionForSetInternalVersion(t *testing.T) {
|
||||
s := GetTestScheme()
|
||||
s.InternalVersion = "v1"
|
||||
badJSONs := [][]byte{
|
||||
[]byte(`{"myKindKey":"TestType1"}`), // Missing version
|
||||
}
|
||||
for _, b := range badJSONs {
|
||||
if _, err := s.Decode(b); err == nil {
|
||||
t.Errorf("Did not reject bad json: %s", string(b))
|
||||
}
|
||||
}
|
||||
badJSONKindMismatch := []byte(`{"myVersionKey":"v1","myKindKey":"ExternalInternalSame"}`)
|
||||
if err := s.DecodeInto(badJSONKindMismatch, &TestType1{}); err == nil {
|
||||
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetaValues(t *testing.T) {
|
||||
type InternalSimple struct {
|
||||
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
||||
@@ -283,7 +298,6 @@ func TestMetaValues(t *testing.T) {
|
||||
}
|
||||
s := NewScheme()
|
||||
s.InternalVersion = ""
|
||||
s.ExternalVersion = "externalVersion"
|
||||
s.AddKnownTypeWithName("", "Simple", &InternalSimple{})
|
||||
s.AddKnownTypeWithName("externalVersion", "Simple", &ExternalSimple{})
|
||||
|
||||
@@ -373,7 +387,6 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
|
||||
}
|
||||
s := NewScheme()
|
||||
s.InternalVersion = ""
|
||||
s.ExternalVersion = "externalVersion"
|
||||
// We deliberately don't register the types.
|
||||
|
||||
internalToExternalCalls := 0
|
||||
|
@@ -26,7 +26,6 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func validateAction(expectedAction, actualAction client.FakeAction, t *testing.T) {
|
||||
@@ -94,7 +93,7 @@ func TestUpdateWithNewImage(t *testing.T) {
|
||||
}
|
||||
validateAction(client.FakeAction{Action: "get-controller", Value: "foo"}, fakeClient.Actions[0], t)
|
||||
|
||||
newCtrl := runtime.DefaultScheme.CopyOrDie(&fakeClient.Ctrl).(*api.ReplicationController)
|
||||
newCtrl := api.Scheme.CopyOrDie(&fakeClient.Ctrl).(*api.ReplicationController)
|
||||
newCtrl.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image = "fooImage:2"
|
||||
validateAction(client.FakeAction{Action: "update-controller", Value: newCtrl}, fakeClient.Actions[1], t)
|
||||
|
||||
|
@@ -21,27 +21,29 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"gopkg.in/v1/yaml"
|
||||
)
|
||||
|
||||
func TestParseBadStorage(t *testing.T) {
|
||||
p := NewParser(map[string]runtime.Object{})
|
||||
_, err := p.ToWireFormat([]byte("{}"), "badstorage", runtime.DefaultCodec)
|
||||
_, err := p.ToWireFormat([]byte("{}"), "badstorage", latest.Codec)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, received none")
|
||||
}
|
||||
}
|
||||
|
||||
func DoParseTest(t *testing.T, storage string, obj runtime.Object, p *Parser) {
|
||||
jsonData, _ := runtime.DefaultCodec.Encode(obj)
|
||||
jsonData, _ := latest.Codec.Encode(obj)
|
||||
var tmp map[string]interface{}
|
||||
json.Unmarshal(jsonData, &tmp)
|
||||
yamlData, _ := yaml.Marshal(tmp)
|
||||
t.Logf("Intermediate yaml:\n%v\n", string(yamlData))
|
||||
t.Logf("Intermediate json:\n%v\n", string(jsonData))
|
||||
jsonGot, jsonErr := p.ToWireFormat(jsonData, storage, runtime.DefaultCodec)
|
||||
yamlGot, yamlErr := p.ToWireFormat(yamlData, storage, runtime.DefaultCodec)
|
||||
jsonGot, jsonErr := p.ToWireFormat(jsonData, storage, latest.Codec)
|
||||
yamlGot, yamlErr := p.ToWireFormat(yamlData, storage, latest.Codec)
|
||||
|
||||
if jsonErr != nil {
|
||||
t.Errorf("json err: %#v", jsonErr)
|
||||
@@ -125,8 +127,9 @@ type TestParseType struct {
|
||||
func (*TestParseType) IsAnAPIObject() {}
|
||||
|
||||
func TestParseCustomType(t *testing.T) {
|
||||
runtime.DefaultScheme.AddKnownTypes("", &TestParseType{})
|
||||
runtime.DefaultScheme.AddKnownTypes("v1beta1", &TestParseType{})
|
||||
api.Scheme.AddKnownTypes("", &TestParseType{})
|
||||
api.Scheme.AddKnownTypes("v1beta1", &TestParseType{})
|
||||
api.Scheme.AddKnownTypes("v1beta2", &TestParseType{})
|
||||
parser := NewParser(map[string]runtime.Object{
|
||||
"custom": &TestParseType{},
|
||||
})
|
||||
|
@@ -21,8 +21,8 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// ProxyServer is a http.Handler which proxies Kubernetes APIs to remote API server.
|
||||
@@ -53,7 +53,7 @@ func (s *ProxyServer) Serve() error {
|
||||
func (s *ProxyServer) doError(w http.ResponseWriter, err error) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Header().Add("Content-type", "application/json")
|
||||
data, _ := runtime.DefaultCodec.Encode(&api.Status{
|
||||
data, _ := latest.Codec.Encode(&api.Status{
|
||||
Status: api.StatusFailure,
|
||||
Message: fmt.Sprintf("internal error: %#v", err),
|
||||
})
|
||||
|
@@ -26,6 +26,7 @@ import (
|
||||
"text/template"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/golang/glog"
|
||||
@@ -50,7 +51,7 @@ func (i *IdentityPrinter) Print(data []byte, w io.Writer) error {
|
||||
|
||||
// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
|
||||
func (i *IdentityPrinter) PrintObj(obj runtime.Object, output io.Writer) error {
|
||||
data, err := runtime.DefaultCodec.Encode(obj)
|
||||
data, err := latest.Codec.Encode(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -260,7 +261,7 @@ func (h *HumanReadablePrinter) Print(data []byte, output io.Writer) error {
|
||||
return fmt.Errorf("unexpected object with no 'kind' field: %s", data)
|
||||
}
|
||||
|
||||
obj, err := runtime.DefaultCodec.Decode(data)
|
||||
obj, err := latest.Codec.Decode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -292,7 +293,7 @@ type TemplatePrinter struct {
|
||||
|
||||
// Print parses the data as JSON, and re-formats it with the Go Template.
|
||||
func (t *TemplatePrinter) Print(data []byte, w io.Writer) error {
|
||||
obj, err := runtime.DefaultCodec.Decode(data)
|
||||
obj, err := latest.Codec.Decode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"gopkg.in/v1/yaml"
|
||||
)
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestIdentityPrinter(t *testing.T) {
|
||||
}
|
||||
buff.Reset()
|
||||
printer.PrintObj(obj, buff)
|
||||
objOut, err := runtime.DefaultCodec.Decode([]byte(buff.String()))
|
||||
objOut, err := latest.Codec.Decode([]byte(buff.String()))
|
||||
if err != nil {
|
||||
t.Errorf("Unexpeted error: %#v", err)
|
||||
}
|
||||
|
@@ -24,9 +24,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
@@ -47,8 +46,8 @@ type SourceEtcd struct {
|
||||
func NewSourceEtcd(key string, client tools.EtcdClient, updates chan<- interface{}) *SourceEtcd {
|
||||
helper := tools.EtcdHelper{
|
||||
client,
|
||||
runtime.DefaultCodec,
|
||||
runtime.DefaultResourceVersioner,
|
||||
latest.Codec,
|
||||
latest.ResourceVersioner,
|
||||
}
|
||||
source := &SourceEtcd{
|
||||
key: key,
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||
@@ -136,5 +136,5 @@ func (m *Master) API_v1beta1() (map[string]apiserver.RESTStorage, runtime.Codec)
|
||||
for k, v := range m.storage {
|
||||
storage[k] = v
|
||||
}
|
||||
return storage, runtime.DefaultCodec
|
||||
return storage, v1beta1.Codec
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/coreos/go-etcd/etcd"
|
||||
@@ -135,7 +135,7 @@ func (s ConfigSourceEtcd) GetServices() ([]api.Service, []api.Endpoints, error)
|
||||
// and create a Service entry for it.
|
||||
for i, node := range response.Node.Nodes {
|
||||
var svc api.Service
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(node.Value), &svc)
|
||||
err = latest.Codec.DecodeInto([]byte(node.Value), &svc)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to load Service: %s (%#v)", node.Value, err)
|
||||
continue
|
||||
@@ -168,7 +168,7 @@ func (s ConfigSourceEtcd) GetEndpoints(service string) (api.Endpoints, error) {
|
||||
}
|
||||
// Parse all the endpoint specifications in this value.
|
||||
var e api.Endpoints
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &e)
|
||||
err = latest.Codec.DecodeInto([]byte(response.Node.Value), &e)
|
||||
return e, err
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func etcdResponseToService(response *etcd.Response) (*api.Service, error) {
|
||||
return nil, fmt.Errorf("invalid response from etcd: %#v", response)
|
||||
}
|
||||
var svc api.Service
|
||||
err := runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &svc)
|
||||
err := latest.Codec.DecodeInto([]byte(response.Node.Value), &svc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func (s ConfigSourceEtcd) ProcessChange(response *etcd.Response) {
|
||||
func (s ConfigSourceEtcd) ProcessEndpointResponse(response *etcd.Response) {
|
||||
glog.Infof("Processing a change in endpoint configuration... %s", *response)
|
||||
var endpoints api.Endpoints
|
||||
err := runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &endpoints)
|
||||
err := latest.Codec.DecodeInto([]byte(response.Node.Value), &endpoints)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to parse service out of etcd key: %v : %+v", response.Node.Value, err)
|
||||
return
|
||||
|
@@ -23,9 +23,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestNewREST(t *testing.T) {
|
||||
@@ -38,12 +37,12 @@ func TestNewREST(t *testing.T) {
|
||||
PodID: "foo",
|
||||
Host: "bar",
|
||||
}
|
||||
body, err := runtime.DefaultCodec.Encode(binding)
|
||||
body, err := latest.Codec.Encode(binding)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected encode error %v", err)
|
||||
}
|
||||
obj := b.New()
|
||||
err = runtime.DefaultCodec.DecodeInto(body, obj)
|
||||
err = latest.Codec.DecodeInto(body, obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
|
@@ -26,10 +26,10 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestListControllersError(t *testing.T) {
|
||||
@@ -113,13 +113,13 @@ func TestControllerDecode(t *testing.T) {
|
||||
ID: "foo",
|
||||
},
|
||||
}
|
||||
body, err := runtime.DefaultCodec.Encode(controller)
|
||||
body, err := latest.Codec.Encode(controller)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
controllerOut := storage.New()
|
||||
if err := runtime.DefaultCodec.DecodeInto(body, controllerOut); err != nil {
|
||||
if err := latest.Codec.DecodeInto(body, controllerOut); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/constraint"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@@ -45,8 +46,8 @@ func NewRegistry(client tools.EtcdClient) *Registry {
|
||||
registry := &Registry{
|
||||
EtcdHelper: tools.EtcdHelper{
|
||||
client,
|
||||
runtime.DefaultCodec,
|
||||
runtime.DefaultResourceVersioner,
|
||||
latest.Codec,
|
||||
latest.ResourceVersioner,
|
||||
},
|
||||
}
|
||||
registry.manifestFactory = &BasicManifestFactory{
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@@ -41,7 +41,7 @@ func NewTestEtcdRegistry(client tools.EtcdClient) *Registry {
|
||||
|
||||
func TestEtcdGetPod(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.Set("/registry/pods/foo", runtime.DefaultScheme.EncodeOrDie(&api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
fakeClient.Set("/registry/pods/foo", runtime.EncodeOrDie(latest.Codec, &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
pod, err := registry.GetPod("foo")
|
||||
if err != nil {
|
||||
@@ -77,7 +77,7 @@ func TestEtcdCreatePod(t *testing.T) {
|
||||
},
|
||||
E: tools.EtcdErrorNotFound,
|
||||
}
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&api.ContainerManifestList{}), 0)
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(latest.Codec, &api.ContainerManifestList{}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
err := registry.CreatePod(&api.Pod{
|
||||
JSONBase: api.JSONBase{
|
||||
@@ -108,7 +108,7 @@ func TestEtcdCreatePod(t *testing.T) {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
var pod api.Pod
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &pod)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &pod)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func TestEtcdCreatePod(t *testing.T) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &manifests)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &manifests)
|
||||
if len(manifests.Items) != 1 || manifests.Items[0].ID != "foo" {
|
||||
t.Errorf("Unexpected manifest list: %#v", manifests)
|
||||
}
|
||||
@@ -133,7 +133,7 @@ func TestEtcdCreatePodAlreadyExisting(t *testing.T) {
|
||||
fakeClient.Data["/registry/pods/foo"] = tools.EtcdResponseWithError{
|
||||
R: &etcd.Response{
|
||||
Node: &etcd.Node{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.Pod{JSONBase: api.JSONBase{ID: "foo"}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}),
|
||||
},
|
||||
},
|
||||
E: nil,
|
||||
@@ -235,7 +235,7 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
var pod api.Pod
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &pod)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &pod)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -249,7 +249,7 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &manifests)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &manifests)
|
||||
if len(manifests.Items) != 1 || manifests.Items[0].ID != "foo" {
|
||||
t.Errorf("Unexpected manifest list: %#v", manifests)
|
||||
}
|
||||
@@ -264,7 +264,7 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
|
||||
},
|
||||
E: tools.EtcdErrorNotFound,
|
||||
}
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&api.ContainerManifestList{
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(latest.Codec, &api.ContainerManifestList{
|
||||
Items: []api.ContainerManifest{
|
||||
{ID: "bar"},
|
||||
},
|
||||
@@ -300,7 +300,7 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
var pod api.Pod
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &pod)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &pod)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -314,7 +314,7 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &manifests)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &manifests)
|
||||
if len(manifests.Items) != 2 || manifests.Items[1].ID != "foo" {
|
||||
t.Errorf("Unexpected manifest list: %#v", manifests)
|
||||
}
|
||||
@@ -325,11 +325,11 @@ func TestEtcdDeletePod(t *testing.T) {
|
||||
fakeClient.TestIndex = true
|
||||
|
||||
key := "/registry/pods/foo"
|
||||
fakeClient.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{
|
||||
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
DesiredState: api.PodState{Host: "machine"},
|
||||
}), 0)
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&api.ContainerManifestList{
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(latest.Codec, &api.ContainerManifestList{
|
||||
Items: []api.ContainerManifest{
|
||||
{ID: "foo"},
|
||||
},
|
||||
@@ -350,7 +350,7 @@ func TestEtcdDeletePod(t *testing.T) {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
var manifests api.ContainerManifestList
|
||||
runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &manifests)
|
||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &manifests)
|
||||
if len(manifests.Items) != 0 {
|
||||
t.Errorf("Unexpected container set: %s, expected empty", response.Node.Value)
|
||||
}
|
||||
@@ -361,11 +361,11 @@ func TestEtcdDeletePodMultipleContainers(t *testing.T) {
|
||||
fakeClient.TestIndex = true
|
||||
|
||||
key := "/registry/pods/foo"
|
||||
fakeClient.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{
|
||||
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
DesiredState: api.PodState{Host: "machine"},
|
||||
}), 0)
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&api.ContainerManifestList{
|
||||
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(latest.Codec, &api.ContainerManifestList{
|
||||
Items: []api.ContainerManifest{
|
||||
{ID: "foo"},
|
||||
{ID: "bar"},
|
||||
@@ -388,7 +388,7 @@ func TestEtcdDeletePodMultipleContainers(t *testing.T) {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
var manifests api.ContainerManifestList
|
||||
runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &manifests)
|
||||
latest.Codec.DecodeInto([]byte(response.Node.Value), &manifests)
|
||||
if len(manifests.Items) != 1 {
|
||||
t.Fatalf("Unexpected manifest set: %#v, expected empty", manifests)
|
||||
}
|
||||
@@ -445,13 +445,13 @@ func TestEtcdListPods(t *testing.T) {
|
||||
Node: &etcd.Node{
|
||||
Nodes: []*etcd.Node{
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.Pod{
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
DesiredState: api.PodState{Host: "machine"},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.Pod{
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{
|
||||
JSONBase: api.JSONBase{ID: "bar"},
|
||||
DesiredState: api.PodState{Host: "machine"},
|
||||
}),
|
||||
@@ -520,10 +520,10 @@ func TestEtcdListControllers(t *testing.T) {
|
||||
Node: &etcd.Node{
|
||||
Nodes: []*etcd.Node{
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}),
|
||||
},
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "bar"}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.ReplicationController{JSONBase: api.JSONBase{ID: "bar"}}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -543,7 +543,7 @@ func TestEtcdListControllers(t *testing.T) {
|
||||
|
||||
func TestEtcdGetController(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.Set("/registry/controllers/foo", runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
fakeClient.Set("/registry/controllers/foo", runtime.EncodeOrDie(latest.Codec, &api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
ctrl, err := registry.GetController("foo")
|
||||
if err != nil {
|
||||
@@ -607,7 +607,7 @@ func TestEtcdCreateController(t *testing.T) {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
var ctrl api.ReplicationController
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &ctrl)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &ctrl)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -619,7 +619,7 @@ func TestEtcdCreateController(t *testing.T) {
|
||||
|
||||
func TestEtcdCreateControllerAlreadyExisting(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.Set("/registry/controllers/foo", runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
fakeClient.Set("/registry/controllers/foo", runtime.EncodeOrDie(latest.Codec, &api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
err := registry.CreateController(&api.ReplicationController{
|
||||
@@ -636,7 +636,7 @@ func TestEtcdUpdateController(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.TestIndex = true
|
||||
|
||||
resp, _ := fakeClient.Set("/registry/controllers/foo", runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
resp, _ := fakeClient.Set("/registry/controllers/foo", runtime.EncodeOrDie(latest.Codec, &api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
err := registry.UpdateController(&api.ReplicationController{
|
||||
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex},
|
||||
@@ -662,10 +662,10 @@ func TestEtcdListServices(t *testing.T) {
|
||||
Node: &etcd.Node{
|
||||
Nodes: []*etcd.Node{
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "foo"}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Service{JSONBase: api.JSONBase{ID: "foo"}}),
|
||||
},
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "bar"}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Service{JSONBase: api.JSONBase{ID: "bar"}}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -699,7 +699,7 @@ func TestEtcdCreateService(t *testing.T) {
|
||||
}
|
||||
|
||||
var service api.Service
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &service)
|
||||
err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &service)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -711,7 +711,7 @@ func TestEtcdCreateService(t *testing.T) {
|
||||
|
||||
func TestEtcdCreateServiceAlreadyExisting(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.Set("/registry/services/specs/foo", runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
fakeClient.Set("/registry/services/specs/foo", runtime.EncodeOrDie(latest.Codec, &api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
err := registry.CreateService(&api.Service{
|
||||
JSONBase: api.JSONBase{ID: "foo"},
|
||||
@@ -723,7 +723,7 @@ func TestEtcdCreateServiceAlreadyExisting(t *testing.T) {
|
||||
|
||||
func TestEtcdGetService(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.Set("/registry/services/specs/foo", runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
fakeClient.Set("/registry/services/specs/foo", runtime.EncodeOrDie(latest.Codec, &api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
service, err := registry.GetService("foo")
|
||||
if err != nil {
|
||||
@@ -775,7 +775,7 @@ func TestEtcdUpdateService(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.TestIndex = true
|
||||
|
||||
resp, _ := fakeClient.Set("/registry/services/specs/foo", runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
resp, _ := fakeClient.Set("/registry/services/specs/foo", runtime.EncodeOrDie(latest.Codec, &api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
testService := api.Service{
|
||||
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex},
|
||||
@@ -812,10 +812,10 @@ func TestEtcdListEndpoints(t *testing.T) {
|
||||
Node: &etcd.Node{
|
||||
Nodes: []*etcd.Node{
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:8345"}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:8345"}}),
|
||||
},
|
||||
{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "bar"}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "bar"}}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -841,7 +841,7 @@ func TestEtcdGetEndpoints(t *testing.T) {
|
||||
Endpoints: []string{"127.0.0.1:34855"},
|
||||
}
|
||||
|
||||
fakeClient.Set("/registry/services/endpoints/foo", runtime.DefaultScheme.EncodeOrDie(endpoints), 0)
|
||||
fakeClient.Set("/registry/services/endpoints/foo", runtime.EncodeOrDie(latest.Codec, endpoints), 0)
|
||||
|
||||
got, err := registry.GetEndpoints("foo")
|
||||
if err != nil {
|
||||
@@ -862,7 +862,7 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
|
||||
Endpoints: []string{"baz", "bar"},
|
||||
}
|
||||
|
||||
fakeClient.Set("/registry/services/endpoints/foo", runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{}), 0)
|
||||
fakeClient.Set("/registry/services/endpoints/foo", runtime.EncodeOrDie(latest.Codec, &api.Endpoints{}), 0)
|
||||
|
||||
err := registry.UpdateEndpoints(&endpoints)
|
||||
if err != nil {
|
||||
@@ -874,7 +874,7 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
var endpointsOut api.Endpoints
|
||||
err = runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &endpointsOut)
|
||||
err = latest.Codec.DecodeInto([]byte(response.Node.Value), &endpointsOut)
|
||||
if !reflect.DeepEqual(endpoints, endpointsOut) {
|
||||
t.Errorf("Unexpected endpoints: %#v, expected %#v", endpointsOut, endpoints)
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||
@@ -201,13 +202,13 @@ func TestPodDecode(t *testing.T) {
|
||||
ID: "foo",
|
||||
},
|
||||
}
|
||||
body, err := runtime.DefaultCodec.Encode(expected)
|
||||
body, err := latest.Codec.Encode(expected)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
actual := storage.New()
|
||||
if err := runtime.DefaultCodec.DecodeInto(body, actual); err != nil {
|
||||
if err := latest.Codec.DecodeInto(body, actual); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
|
@@ -20,42 +20,80 @@ import (
|
||||
"gopkg.in/v1/yaml"
|
||||
)
|
||||
|
||||
// EmbeddedObject must have an 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
|
||||
// Object via the Get() function. Only valid API objects may be stored via EmbeddedObject.
|
||||
// The purpose of this is to allow an API object of type known only at runtime to be
|
||||
// embedded within other API objects.
|
||||
//
|
||||
// Define a Codec variable in your package and import the runtime package and
|
||||
// then use the commented section below
|
||||
|
||||
/*
|
||||
// EmbeddedObject implements a Codec specific version of an
|
||||
// embedded object.
|
||||
type EmbeddedObject struct {
|
||||
runtime.Object
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (a *EmbeddedObject) UnmarshalJSON(b []byte) error {
|
||||
obj, err := runtime.CodecUnmarshalJSON(Codec, b)
|
||||
a.Object = obj
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (a EmbeddedObject) MarshalJSON() ([]byte, error) {
|
||||
return runtime.CodecMarshalJSON(Codec, a.Object)
|
||||
}
|
||||
|
||||
// SetYAML implements the yaml.Setter interface.
|
||||
func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
|
||||
obj, ok := runtime.CodecSetYAML(Codec, tag, value)
|
||||
a.Object = obj
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetYAML implements the yaml.Getter interface.
|
||||
func (a EmbeddedObject) GetYAML() (tag string, value interface{}) {
|
||||
return runtime.CodecGetYAML(Codec, a.Object)
|
||||
}
|
||||
*/
|
||||
|
||||
// Encode()/Decode() are the canonical way of converting an API object to/from
|
||||
// wire format. This file provides utility functions which permit doing so
|
||||
// recursively, such that API objects of types known only at run time can be
|
||||
// embedded within other API types.
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (a *EmbeddedObject) UnmarshalJSON(b []byte) error {
|
||||
func CodecUnmarshalJSON(codec Codec, b []byte) (Object, error) {
|
||||
// Handle JSON's "null": Decode() doesn't expect it.
|
||||
if len(b) == 4 && string(b) == "null" {
|
||||
a.Object = nil
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
obj, err := DefaultCodec.Decode(b)
|
||||
obj, err := codec.Decode(b)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
a.Object = obj
|
||||
return nil
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (a EmbeddedObject) MarshalJSON() ([]byte, error) {
|
||||
if a.Object == nil {
|
||||
func CodecMarshalJSON(codec Codec, obj Object) ([]byte, error) {
|
||||
if obj == nil {
|
||||
// Encode unset/nil objects as JSON's "null".
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
return DefaultCodec.Encode(a.Object)
|
||||
return codec.Encode(obj)
|
||||
}
|
||||
|
||||
// SetYAML implements the yaml.Setter interface.
|
||||
func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
|
||||
func CodecSetYAML(codec Codec, tag string, value interface{}) (Object, bool) {
|
||||
if value == nil {
|
||||
a.Object = nil
|
||||
return true
|
||||
return nil, true
|
||||
}
|
||||
// Why does the yaml package send value as a map[interface{}]interface{}?
|
||||
// It's especially frustrating because encoding/json does the right thing
|
||||
@@ -67,22 +105,21 @@ func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
|
||||
if err != nil {
|
||||
panic("yaml can't reverse its own object")
|
||||
}
|
||||
obj, err := DefaultCodec.Decode(b)
|
||||
obj, err := codec.Decode(b)
|
||||
if err != nil {
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
a.Object = obj
|
||||
return true
|
||||
return obj, true
|
||||
}
|
||||
|
||||
// GetYAML implements the yaml.Getter interface.
|
||||
func (a EmbeddedObject) GetYAML() (tag string, value interface{}) {
|
||||
if a.Object == nil {
|
||||
func CodecGetYAML(codec Codec, obj Object) (tag string, value interface{}) {
|
||||
if obj == nil {
|
||||
value = "null"
|
||||
return
|
||||
}
|
||||
// Encode returns JSON, which is conveniently a subset of YAML.
|
||||
v, err := DefaultCodec.Encode(a.Object)
|
||||
v, err := codec.Encode(obj)
|
||||
if err != nil {
|
||||
panic("impossible to encode API object!")
|
||||
}
|
||||
|
@@ -14,38 +14,72 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runtime
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var Codec = runtime.CodecFor(scheme, "v1test")
|
||||
|
||||
// EmbeddedObject implements a Codec specific version of an
|
||||
// embedded object.
|
||||
type EmbeddedObject struct {
|
||||
runtime.Object
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (a *EmbeddedObject) UnmarshalJSON(b []byte) error {
|
||||
obj, err := runtime.CodecUnmarshalJSON(Codec, b)
|
||||
a.Object = obj
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (a EmbeddedObject) MarshalJSON() ([]byte, error) {
|
||||
return runtime.CodecMarshalJSON(Codec, a.Object)
|
||||
}
|
||||
|
||||
// SetYAML implements the yaml.Setter interface.
|
||||
func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
|
||||
obj, ok := runtime.CodecSetYAML(Codec, tag, value)
|
||||
a.Object = obj
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetYAML implements the yaml.Getter interface.
|
||||
func (a EmbeddedObject) GetYAML() (tag string, value interface{}) {
|
||||
return runtime.CodecGetYAML(Codec, a.Object)
|
||||
}
|
||||
|
||||
type EmbeddedTest struct {
|
||||
JSONBase `yaml:",inline" json:",inline"`
|
||||
Object EmbeddedObject `yaml:"object,omitempty" json:"object,omitempty"`
|
||||
EmptyObject EmbeddedObject `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"`
|
||||
runtime.JSONBase `yaml:",inline" json:",inline"`
|
||||
Object EmbeddedObject `yaml:"object,omitempty" json:"object,omitempty"`
|
||||
EmptyObject EmbeddedObject `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"`
|
||||
}
|
||||
|
||||
func (*EmbeddedTest) IsAnAPIObject() {}
|
||||
|
||||
func TestEmbeddedObject(t *testing.T) {
|
||||
// TODO(dbsmith) fix EmbeddedObject to not use DefaultScheme.
|
||||
s := DefaultScheme
|
||||
s := scheme
|
||||
s.AddKnownTypes("", &EmbeddedTest{})
|
||||
s.AddKnownTypes("v1beta1", &EmbeddedTest{})
|
||||
s.AddKnownTypes("v1test", &EmbeddedTest{})
|
||||
|
||||
outer := &EmbeddedTest{
|
||||
JSONBase: JSONBase{ID: "outer"},
|
||||
JSONBase: runtime.JSONBase{ID: "outer"},
|
||||
Object: EmbeddedObject{
|
||||
&EmbeddedTest{
|
||||
JSONBase: JSONBase{ID: "inner"},
|
||||
JSONBase: runtime.JSONBase{ID: "inner"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
wire, err := s.Encode(outer)
|
||||
wire, err := s.EncodeToVersion(outer, "v1test")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected encode error '%v'", err)
|
||||
}
|
||||
|
@@ -16,13 +16,23 @@ limitations under the License.
|
||||
|
||||
package runtime
|
||||
|
||||
// Codec defines methods for serializing and deserializing API objects.
|
||||
type Codec interface {
|
||||
Encode(obj Object) (data []byte, err error)
|
||||
// Decoder defines methods for deserializing API objects into a given type
|
||||
type Decoder interface {
|
||||
Decode(data []byte) (Object, error)
|
||||
DecodeInto(data []byte, obj Object) error
|
||||
}
|
||||
|
||||
// Encoder defines methods for serializing API objects into bytes
|
||||
type Encoder interface {
|
||||
Encode(obj Object) (data []byte, err error)
|
||||
}
|
||||
|
||||
// Codec defines methods for serializing and deserializing API objects.
|
||||
type Codec interface {
|
||||
Decoder
|
||||
Encoder
|
||||
}
|
||||
|
||||
// ResourceVersioner provides methods for setting and retrieving
|
||||
// the resource version from an API object.
|
||||
type ResourceVersioner interface {
|
||||
|
@@ -17,16 +17,40 @@ limitations under the License.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"gopkg.in/v1/yaml"
|
||||
)
|
||||
|
||||
var DefaultResourceVersioner ResourceVersioner = NewJSONBaseResourceVersioner()
|
||||
var DefaultScheme = NewScheme("", "v1beta1")
|
||||
var DefaultCodec Codec = DefaultScheme
|
||||
// codecWrapper implements encoding to an alternative
|
||||
// default version for a scheme.
|
||||
type codecWrapper struct {
|
||||
*Scheme
|
||||
version string
|
||||
}
|
||||
|
||||
// Encode implements Codec
|
||||
func (c *codecWrapper) Encode(obj Object) ([]byte, error) {
|
||||
return c.Scheme.EncodeToVersion(obj, c.version)
|
||||
}
|
||||
|
||||
// CodecFor returns a Codec that invokes Encode with the provided version.
|
||||
func CodecFor(scheme *Scheme, version string) Codec {
|
||||
return &codecWrapper{scheme, version}
|
||||
}
|
||||
|
||||
// EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests.
|
||||
func EncodeOrDie(codec Codec, obj Object) string {
|
||||
bytes, err := codec.Encode(obj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// Scheme defines methods for serializing and deserializing API objects. It
|
||||
// is an adaptation of conversion's Scheme for our API objects.
|
||||
@@ -36,21 +60,13 @@ type Scheme struct {
|
||||
|
||||
// fromScope gets the input version, desired output version, and desired Scheme
|
||||
// from a conversion.Scope.
|
||||
func fromScope(s conversion.Scope) (inVersion, outVersion string, scheme *Scheme) {
|
||||
scheme = DefaultScheme
|
||||
func (self *Scheme) fromScope(s conversion.Scope) (inVersion, outVersion string, scheme *Scheme) {
|
||||
scheme = self
|
||||
inVersion = s.Meta().SrcVersion
|
||||
outVersion = s.Meta().DestVersion
|
||||
return inVersion, outVersion, scheme
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Set up a generic mapping between RawExtension and EmbeddedObject.
|
||||
DefaultScheme.AddConversionFuncs(
|
||||
embeddedObjectToRawExtension,
|
||||
rawExtensionToEmbeddedObject,
|
||||
)
|
||||
}
|
||||
|
||||
// emptyPlugin is used to copy the Kind field to and from plugin objects.
|
||||
type emptyPlugin struct {
|
||||
PluginBase `json:",inline" yaml:",inline"`
|
||||
@@ -59,14 +75,14 @@ type emptyPlugin struct {
|
||||
// embeddedObjectToRawExtension does the conversion you would expect from the name, using the information
|
||||
// given in conversion.Scope. It's placed in the DefaultScheme as a ConversionFunc to enable plugins;
|
||||
// see the comment for RawExtension.
|
||||
func embeddedObjectToRawExtension(in *EmbeddedObject, out *RawExtension, s conversion.Scope) error {
|
||||
func (self *Scheme) embeddedObjectToRawExtension(in *EmbeddedObject, out *RawExtension, s conversion.Scope) error {
|
||||
if in.Object == nil {
|
||||
out.RawJSON = []byte("null")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Figure out the type and kind of the output object.
|
||||
_, outVersion, scheme := fromScope(s)
|
||||
_, outVersion, scheme := self.fromScope(s)
|
||||
_, kind, err := scheme.raw.ObjectVersionAndKind(in.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -107,13 +123,13 @@ func embeddedObjectToRawExtension(in *EmbeddedObject, out *RawExtension, s conve
|
||||
// rawExtensionToEmbeddedObject does the conversion you would expect from the name, using the information
|
||||
// given in conversion.Scope. It's placed in the DefaultScheme as a ConversionFunc to enable plugins;
|
||||
// see the comment for RawExtension.
|
||||
func rawExtensionToEmbeddedObject(in *RawExtension, out *EmbeddedObject, s conversion.Scope) error {
|
||||
func (self *Scheme) rawExtensionToEmbeddedObject(in *RawExtension, out *EmbeddedObject, s conversion.Scope) error {
|
||||
if len(in.RawJSON) == 4 && string(in.RawJSON) == "null" {
|
||||
out.Object = nil
|
||||
return nil
|
||||
}
|
||||
// Figure out the type and kind of the output object.
|
||||
inVersion, outVersion, scheme := fromScope(s)
|
||||
inVersion, outVersion, scheme := self.fromScope(s)
|
||||
_, kind, err := scheme.raw.DataVersionAndKind(in.RawJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -153,13 +169,15 @@ func rawExtensionToEmbeddedObject(in *RawExtension, out *EmbeddedObject, s conve
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewScheme creates a new Scheme. A default scheme is provided and accessible
|
||||
// as the "DefaultScheme" variable.
|
||||
func NewScheme(internalVersion, externalVersion string) *Scheme {
|
||||
// NewScheme creates a new Scheme. This scheme is pluggable by default.
|
||||
func NewScheme() *Scheme {
|
||||
s := &Scheme{conversion.NewScheme()}
|
||||
s.raw.InternalVersion = internalVersion
|
||||
s.raw.ExternalVersion = externalVersion
|
||||
s.raw.InternalVersion = ""
|
||||
s.raw.MetaInsertionFactory = metaInsertion{}
|
||||
s.raw.AddConversionFuncs(
|
||||
s.embeddedObjectToRawExtension,
|
||||
s.rawExtensionToEmbeddedObject,
|
||||
)
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -180,6 +198,10 @@ func (s *Scheme) AddKnownTypeWithName(version, kind string, obj Object) {
|
||||
s.raw.AddKnownTypeWithName(version, kind, obj)
|
||||
}
|
||||
|
||||
func (s *Scheme) KnownTypes(version string) map[string]reflect.Type {
|
||||
return s.raw.KnownTypes(version)
|
||||
}
|
||||
|
||||
// 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 (s *Scheme) New(versionName, typeName string) (Object, error) {
|
||||
@@ -236,12 +258,7 @@ func FindJSONBase(obj Object) (JSONBaseInterface, error) {
|
||||
return g, nil
|
||||
}
|
||||
|
||||
// EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests.
|
||||
func (s *Scheme) EncodeOrDie(obj Object) string {
|
||||
return s.raw.EncodeOrDie(obj)
|
||||
}
|
||||
|
||||
// Encode turns the given api object into an appropriate JSON string.
|
||||
// EncodeToVersion 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,
|
||||
@@ -269,17 +286,6 @@ func (s *Scheme) EncodeOrDie(obj Object) string {
|
||||
// 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 (s *Scheme) Encode(obj Object) (data []byte, err error) {
|
||||
return s.raw.Encode(obj)
|
||||
}
|
||||
|
||||
// EncodeToVersion is like Encode, but lets you specify the destination version.
|
||||
func (s *Scheme) EncodeToVersion(obj Object, destVersion string) (data []byte, err error) {
|
||||
return s.raw.EncodeToVersion(obj, destVersion)
|
||||
}
|
||||
@@ -332,10 +338,10 @@ func (s *Scheme) DecodeInto(data []byte, obj Object) error {
|
||||
return s.raw.DecodeInto(data, obj)
|
||||
}
|
||||
|
||||
// Does a deep copy of an API object. Useful mostly for tests.
|
||||
// Copy does a deep copy of an API object. Useful mostly for tests.
|
||||
// TODO(dbsmith): implement directly instead of via Encode/Decode
|
||||
func (s *Scheme) Copy(obj Object) (Object, error) {
|
||||
data, err := s.Encode(obj)
|
||||
data, err := s.EncodeToVersion(obj, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -350,6 +356,26 @@ func (s *Scheme) CopyOrDie(obj Object) Object {
|
||||
return newObj
|
||||
}
|
||||
|
||||
func ObjectDiff(a, b Object) string {
|
||||
ab, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("a: %v", err))
|
||||
}
|
||||
bb, err := json.Marshal(b)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("b: %v", err))
|
||||
}
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@@ -43,14 +43,15 @@ func (*InternalSimple) IsAnAPIObject() {}
|
||||
func (*ExternalSimple) IsAnAPIObject() {}
|
||||
|
||||
func TestScheme(t *testing.T) {
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("", "Simple", &InternalSimple{})
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("externalVersion", "Simple", &ExternalSimple{})
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName("", "Simple", &InternalSimple{})
|
||||
scheme.AddKnownTypeWithName("externalVersion", "Simple", &ExternalSimple{})
|
||||
|
||||
internalToExternalCalls := 0
|
||||
externalToInternalCalls := 0
|
||||
|
||||
// Register functions to verify that scope.Meta() gets set correctly.
|
||||
err := runtime.DefaultScheme.AddConversionFuncs(
|
||||
err := scheme.AddConversionFuncs(
|
||||
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
|
||||
if e, a := "", scope.Meta().SrcVersion; e != a {
|
||||
t.Errorf("Expected '%v', got '%v'", e, a)
|
||||
@@ -85,10 +86,10 @@ func TestScheme(t *testing.T) {
|
||||
|
||||
// Test Encode, Decode, and DecodeInto
|
||||
obj := runtime.Object(simple)
|
||||
data, err := runtime.DefaultScheme.EncodeToVersion(obj, "externalVersion")
|
||||
obj2, err2 := runtime.DefaultScheme.Decode(data)
|
||||
data, err := scheme.EncodeToVersion(obj, "externalVersion")
|
||||
obj2, err2 := scheme.Decode(data)
|
||||
obj3 := &InternalSimple{}
|
||||
err3 := runtime.DefaultScheme.DecodeInto(data, obj3)
|
||||
err3 := scheme.DecodeInto(data, obj3)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v' '%v'", err, err2, err3)
|
||||
}
|
||||
@@ -104,7 +105,7 @@ func TestScheme(t *testing.T) {
|
||||
|
||||
// Test Convert
|
||||
external := &ExternalSimple{}
|
||||
err = runtime.DefaultScheme.Convert(simple, external)
|
||||
err = scheme.Convert(simple, external)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
@@ -123,12 +124,13 @@ func TestScheme(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBadJSONRejection(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
badJSONMissingKind := []byte(`{ }`)
|
||||
if _, err := runtime.DefaultScheme.Decode(badJSONMissingKind); err == nil {
|
||||
if _, err := scheme.Decode(badJSONMissingKind); err == nil {
|
||||
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
|
||||
}
|
||||
badJSONUnknownType := []byte(`{"kind": "bar"}`)
|
||||
if _, err1 := runtime.DefaultScheme.Decode(badJSONUnknownType); err1 == nil {
|
||||
if _, err1 := scheme.Decode(badJSONUnknownType); err1 == nil {
|
||||
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
|
||||
}
|
||||
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
|
||||
@@ -163,12 +165,13 @@ func (*ExternalExtensionType) IsAnAPIObject() {}
|
||||
func (*InternalExtensionType) IsAnAPIObject() {}
|
||||
|
||||
func TestExtensionMapping(t *testing.T) {
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("", "ExtensionType", &InternalExtensionType{})
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("", "A", &ExtensionA{})
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("", "B", &ExtensionB{})
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("testExternal", "ExtensionType", &ExternalExtensionType{})
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("testExternal", "A", &ExtensionA{})
|
||||
runtime.DefaultScheme.AddKnownTypeWithName("testExternal", "B", &ExtensionB{})
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName("", "ExtensionType", &InternalExtensionType{})
|
||||
scheme.AddKnownTypeWithName("", "A", &ExtensionA{})
|
||||
scheme.AddKnownTypeWithName("", "B", &ExtensionB{})
|
||||
scheme.AddKnownTypeWithName("testExternal", "ExtensionType", &ExternalExtensionType{})
|
||||
scheme.AddKnownTypeWithName("testExternal", "A", &ExtensionA{})
|
||||
scheme.AddKnownTypeWithName("testExternal", "B", &ExtensionB{})
|
||||
|
||||
table := []struct {
|
||||
obj runtime.Object
|
||||
@@ -187,14 +190,14 @@ func TestExtensionMapping(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
gotEncoded, err := runtime.DefaultScheme.EncodeToVersion(item.obj, "testExternal")
|
||||
gotEncoded, err := scheme.EncodeToVersion(item.obj, "testExternal")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error '%v' (%#v)", err, item.obj)
|
||||
} else if e, a := item.encoded, string(gotEncoded); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
gotDecoded, err := runtime.DefaultScheme.Decode([]byte(item.encoded))
|
||||
gotDecoded, err := scheme.Decode([]byte(item.encoded))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error '%v' (%v)", err, item.encoded)
|
||||
} else if e, a := item.obj, gotDecoded; !reflect.DeepEqual(e, a) {
|
||||
@@ -209,3 +212,25 @@ func TestExtensionMapping(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName("", "Simple", &InternalSimple{})
|
||||
scheme.AddKnownTypeWithName("externalVersion", "Simple", &ExternalSimple{})
|
||||
codec := runtime.CodecFor(scheme, "externalVersion")
|
||||
test := &InternalSimple{
|
||||
TestString: "I'm the same",
|
||||
}
|
||||
obj := runtime.Object(test)
|
||||
data, err := codec.Encode(obj)
|
||||
obj2, err2 := codec.Decode(data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
}
|
||||
if _, ok := obj2.(*InternalSimple); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, test) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &test, obj2)
|
||||
}
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/coreos/go-etcd/etcd"
|
||||
@@ -42,13 +43,14 @@ type TestResource struct {
|
||||
func (*TestResource) IsAnAPIObject() {}
|
||||
|
||||
var scheme *runtime.Scheme
|
||||
var codec = runtime.DefaultCodec
|
||||
var versioner = runtime.DefaultResourceVersioner
|
||||
var codec runtime.Codec
|
||||
var versioner = runtime.NewJSONBaseResourceVersioner()
|
||||
|
||||
func init() {
|
||||
scheme = runtime.NewScheme("", "v1beta1")
|
||||
scheme = runtime.NewScheme()
|
||||
scheme.AddKnownTypes("", &TestResource{})
|
||||
scheme.AddKnownTypes("v1beta1", &TestResource{})
|
||||
codec = runtime.CodecFor(scheme, "v1beta1")
|
||||
}
|
||||
|
||||
func TestIsEtcdNotFound(t *testing.T) {
|
||||
@@ -93,7 +95,7 @@ func TestExtractList(t *testing.T) {
|
||||
}
|
||||
|
||||
var got []api.Pod
|
||||
helper := EtcdHelper{fakeClient, codec, versioner}
|
||||
helper := EtcdHelper{fakeClient, latest.Codec, versioner}
|
||||
resourceVersion := uint64(0)
|
||||
err := helper.ExtractList("/some/key", &got, &resourceVersion)
|
||||
if err != nil {
|
||||
@@ -114,7 +116,7 @@ func TestExtractObj(t *testing.T) {
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
expect := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
fakeClient.Set("/some/key", util.EncodeJSON(expect), 0)
|
||||
helper := EtcdHelper{fakeClient, codec, versioner}
|
||||
helper := EtcdHelper{fakeClient, latest.Codec, versioner}
|
||||
var got api.Pod
|
||||
err := helper.ExtractObj("/some/key", &got, false)
|
||||
if err != nil {
|
||||
@@ -168,12 +170,12 @@ func TestExtractObjNotFoundErr(t *testing.T) {
|
||||
func TestSetObj(t *testing.T) {
|
||||
obj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
helper := EtcdHelper{fakeClient, codec, versioner}
|
||||
helper := EtcdHelper{fakeClient, latest.Codec, versioner}
|
||||
err := helper.SetObj("/some/key", obj)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %#v", err)
|
||||
}
|
||||
data, err := codec.Encode(obj)
|
||||
data, err := latest.Codec.Encode(obj)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %#v", err)
|
||||
}
|
||||
@@ -191,18 +193,18 @@ func TestSetObjWithVersion(t *testing.T) {
|
||||
fakeClient.Data["/some/key"] = EtcdResponseWithError{
|
||||
R: &etcd.Response{
|
||||
Node: &etcd.Node{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(obj),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, obj),
|
||||
ModifiedIndex: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
helper := EtcdHelper{fakeClient, codec, versioner}
|
||||
helper := EtcdHelper{fakeClient, latest.Codec, versioner}
|
||||
err := helper.SetObj("/some/key", obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %#v", err)
|
||||
}
|
||||
data, err := codec.Encode(obj)
|
||||
data, err := latest.Codec.Encode(obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %#v", err)
|
||||
}
|
||||
@@ -216,12 +218,12 @@ func TestSetObjWithVersion(t *testing.T) {
|
||||
func TestSetObjWithoutResourceVersioner(t *testing.T) {
|
||||
obj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
helper := EtcdHelper{fakeClient, codec, nil}
|
||||
helper := EtcdHelper{fakeClient, latest.Codec, nil}
|
||||
err := helper.SetObj("/some/key", obj)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %#v", err)
|
||||
}
|
||||
data, err := codec.Encode(obj)
|
||||
data, err := latest.Codec.Encode(obj)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %#v", err)
|
||||
}
|
||||
@@ -235,7 +237,6 @@ func TestSetObjWithoutResourceVersioner(t *testing.T) {
|
||||
func TestAtomicUpdate(t *testing.T) {
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
fakeClient.TestIndex = true
|
||||
codec := scheme
|
||||
helper := EtcdHelper{fakeClient, codec, runtime.NewJSONBaseResourceVersioner()}
|
||||
|
||||
// Create a new node.
|
||||
@@ -290,7 +291,7 @@ func TestAtomicUpdate(t *testing.T) {
|
||||
func TestAtomicUpdateNoChange(t *testing.T) {
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
fakeClient.TestIndex = true
|
||||
helper := EtcdHelper{fakeClient, scheme, runtime.NewJSONBaseResourceVersioner()}
|
||||
helper := EtcdHelper{fakeClient, codec, runtime.NewJSONBaseResourceVersioner()}
|
||||
|
||||
// Create a new node.
|
||||
fakeClient.ExpectNotFoundGet("/some/key")
|
||||
@@ -321,7 +322,6 @@ func TestAtomicUpdateNoChange(t *testing.T) {
|
||||
func TestAtomicUpdate_CreateCollision(t *testing.T) {
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
fakeClient.TestIndex = true
|
||||
codec := scheme
|
||||
helper := EtcdHelper{fakeClient, codec, runtime.NewJSONBaseResourceVersioner()}
|
||||
|
||||
fakeClient.ExpectNotFoundGet("/some/key")
|
||||
|
@@ -23,12 +23,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
"github.com/coreos/go-etcd/etcd"
|
||||
)
|
||||
|
||||
func TestWatchInterpretations(t *testing.T) {
|
||||
codec := latest.Codec
|
||||
// Declare some pods to make the test cases compact.
|
||||
podFoo := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
podBar := &api.Pod{JSONBase: api.JSONBase{ID: "bar"}}
|
||||
@@ -48,62 +50,62 @@ func TestWatchInterpretations(t *testing.T) {
|
||||
}{
|
||||
"create": {
|
||||
actions: []string{"create", "get"},
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podBar),
|
||||
expectEmit: true,
|
||||
expectType: watch.Added,
|
||||
expectObject: podBar,
|
||||
},
|
||||
"create but filter blocks": {
|
||||
actions: []string{"create", "get"},
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podFoo),
|
||||
expectEmit: false,
|
||||
},
|
||||
"delete": {
|
||||
actions: []string{"delete"},
|
||||
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
|
||||
prevNodeValue: runtime.EncodeOrDie(codec, podBar),
|
||||
expectEmit: true,
|
||||
expectType: watch.Deleted,
|
||||
expectObject: podBar,
|
||||
},
|
||||
"delete but filter blocks": {
|
||||
actions: []string{"delete"},
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podFoo),
|
||||
expectEmit: false,
|
||||
},
|
||||
"modify appears to create 1": {
|
||||
actions: []string{"set", "compareAndSwap"},
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podBar),
|
||||
expectEmit: true,
|
||||
expectType: watch.Added,
|
||||
expectObject: podBar,
|
||||
},
|
||||
"modify appears to create 2": {
|
||||
actions: []string{"set", "compareAndSwap"},
|
||||
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
|
||||
prevNodeValue: runtime.EncodeOrDie(codec, podFoo),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podBar),
|
||||
expectEmit: true,
|
||||
expectType: watch.Added,
|
||||
expectObject: podBar,
|
||||
},
|
||||
"modify appears to delete": {
|
||||
actions: []string{"set", "compareAndSwap"},
|
||||
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
|
||||
prevNodeValue: runtime.EncodeOrDie(codec, podBar),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podFoo),
|
||||
expectEmit: true,
|
||||
expectType: watch.Deleted,
|
||||
expectObject: podBar, // Should return last state that passed the filter!
|
||||
},
|
||||
"modify modifies": {
|
||||
actions: []string{"set", "compareAndSwap"},
|
||||
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBaz),
|
||||
prevNodeValue: runtime.EncodeOrDie(codec, podBar),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podBaz),
|
||||
expectEmit: true,
|
||||
expectType: watch.Modified,
|
||||
expectObject: podBaz,
|
||||
},
|
||||
"modify ignores": {
|
||||
actions: []string{"set", "compareAndSwap"},
|
||||
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
|
||||
nodeValue: runtime.EncodeOrDie(codec, podFoo),
|
||||
expectEmit: false,
|
||||
},
|
||||
}
|
||||
@@ -197,6 +199,7 @@ func TestWatchInterpretation_ResponseBadData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
codec := latest.Codec
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
fakeClient.expectNotFoundGetSet["/some/key"] = struct{}{}
|
||||
h := EtcdHelper{fakeClient, codec, versioner}
|
||||
@@ -243,6 +246,7 @@ func TestWatch(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWatchEtcdState(t *testing.T) {
|
||||
codec := latest.Codec
|
||||
type T struct {
|
||||
Type watch.EventType
|
||||
Endpoints []string
|
||||
@@ -259,7 +263,7 @@ func TestWatchEtcdState(t *testing.T) {
|
||||
{
|
||||
Action: "create",
|
||||
Node: &etcd.Node{
|
||||
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
Value: string(runtime.EncodeOrDie(codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -273,12 +277,12 @@ func TestWatchEtcdState(t *testing.T) {
|
||||
{
|
||||
Action: "compareAndSwap",
|
||||
Node: &etcd.Node{
|
||||
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
|
||||
Value: string(runtime.EncodeOrDie(codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 2,
|
||||
},
|
||||
PrevNode: &etcd.Node{
|
||||
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
Value: string(runtime.EncodeOrDie(codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 1,
|
||||
},
|
||||
@@ -295,7 +299,7 @@ func TestWatchEtcdState(t *testing.T) {
|
||||
R: &etcd.Response{
|
||||
Action: "get",
|
||||
Node: &etcd.Node{
|
||||
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
Value: string(runtime.EncodeOrDie(codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 1,
|
||||
},
|
||||
@@ -308,12 +312,12 @@ func TestWatchEtcdState(t *testing.T) {
|
||||
{
|
||||
Action: "compareAndSwap",
|
||||
Node: &etcd.Node{
|
||||
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
|
||||
Value: string(runtime.EncodeOrDie(codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 2,
|
||||
},
|
||||
PrevNode: &etcd.Node{
|
||||
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
Value: string(runtime.EncodeOrDie(codec, &api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 1,
|
||||
},
|
||||
@@ -359,6 +363,7 @@ func TestWatchEtcdState(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWatchFromZeroIndex(t *testing.T) {
|
||||
codec := latest.Codec
|
||||
pod := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
|
||||
testCases := map[string]struct {
|
||||
@@ -370,7 +375,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
|
||||
EtcdResponseWithError{
|
||||
R: &etcd.Response{
|
||||
Node: &etcd.Node{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(pod),
|
||||
Value: runtime.EncodeOrDie(codec, pod),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 1,
|
||||
},
|
||||
@@ -385,7 +390,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
|
||||
EtcdResponseWithError{
|
||||
R: &etcd.Response{
|
||||
Node: &etcd.Node{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(pod),
|
||||
Value: runtime.EncodeOrDie(codec, pod),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 2,
|
||||
},
|
||||
@@ -434,6 +439,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWatchListFromZeroIndex(t *testing.T) {
|
||||
codec := latest.Codec
|
||||
pod := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
|
||||
fakeClient := NewFakeEtcdClient(t)
|
||||
@@ -443,13 +449,13 @@ func TestWatchListFromZeroIndex(t *testing.T) {
|
||||
Dir: true,
|
||||
Nodes: etcd.Nodes{
|
||||
&etcd.Node{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(pod),
|
||||
Value: runtime.EncodeOrDie(codec, pod),
|
||||
CreatedIndex: 1,
|
||||
ModifiedIndex: 1,
|
||||
Nodes: etcd.Nodes{},
|
||||
},
|
||||
&etcd.Node{
|
||||
Value: runtime.DefaultScheme.EncodeOrDie(pod),
|
||||
Value: runtime.EncodeOrDie(codec, pod),
|
||||
CreatedIndex: 2,
|
||||
ModifiedIndex: 2,
|
||||
Nodes: etcd.Nodes{},
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
@@ -113,7 +114,7 @@ func TestPollMinions(t *testing.T) {
|
||||
ml := &api.MinionList{Items: item.minions}
|
||||
handler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: runtime.DefaultScheme.EncodeOrDie(ml),
|
||||
ResponseBody: runtime.EncodeOrDie(latest.Codec, ml),
|
||||
T: t,
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
@@ -140,7 +141,7 @@ func TestDefaultErrorFunc(t *testing.T) {
|
||||
testPod := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
handler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: runtime.DefaultScheme.EncodeOrDie(testPod),
|
||||
ResponseBody: runtime.EncodeOrDie(latest.Codec, testPod),
|
||||
T: t,
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
@@ -259,7 +260,7 @@ func TestBind(t *testing.T) {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
expectedBody := runtime.DefaultScheme.EncodeOrDie(item.binding)
|
||||
expectedBody := runtime.EncodeOrDie(latest.Codec, item.binding)
|
||||
handler.ValidateRequest(t, "/api/v1beta1/bindings", "POST", &expectedBody)
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
@@ -90,9 +92,9 @@ func TestExtractObj(t *testing.T) {
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
client := newEtcdClient()
|
||||
helper := tools.EtcdHelper{Client: client, Codec: runtime.DefaultCodec, ResourceVersioner: runtime.DefaultResourceVersioner}
|
||||
helper := tools.EtcdHelper{Client: client, Codec: latest.Codec, ResourceVersioner: latest.ResourceVersioner}
|
||||
withEtcdKey(func(key string) {
|
||||
resp, err := client.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
resp, err := client.Set(key, runtime.EncodeOrDie(v1beta1.Codec, &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user