mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-17 15:13:08 +00:00
Make runtime less global for Codec
* Make Codec separate from Scheme * Move EncodeOrDie off Scheme to take a Codec * Make Copy work without a Codec * Create a "latest" package that imports all versions and sets global defaults for "most recent encoding" * v1beta1 is the current "latest", v1beta2 exists * Kill DefaultCodec, replace it with "latest.Codec" * This updates the client and etcd to store the latest known version * EmbeddedObject is per schema and per package now * Move runtime.DefaultScheme to api.Scheme * Split out WatchEvent since it's not an API object today, treat it like a special object in api * Kill DefaultResourceVersioner, instead place it on "latest" (as the package that understands all packages) * Move objDiff to runtime.ObjectDiff
This commit is contained in:
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,14 +17,14 @@ 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"
|
||||
@@ -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 := latest.Codec.Encode(source)
|
||||
data, err := codec.Encode(source)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v (%#v)", name, err, source)
|
||||
return
|
||||
}
|
||||
|
||||
obj2, err := latest.Codec.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 = latest.Codec.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,8 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -17,11 +17,67 @@ 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() {
|
||||
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
|
||||
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
|
||||
|
@@ -17,14 +17,15 @@ limitations under the License.
|
||||
package v1beta2
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// Codec encodes runtime objects to the v1beta2 scheme
|
||||
var Codec = runtime.CodecFor(runtime.DefaultScheme, "v1beta2")
|
||||
// Codec encodes internal objects to the v1beta2 scheme
|
||||
var Codec = runtime.CodecFor(api.Scheme, "v1beta2")
|
||||
|
||||
func init() {
|
||||
runtime.DefaultScheme.AddKnownTypes("v1beta2",
|
||||
api.Scheme.AddKnownTypes("v1beta2",
|
||||
&PodList{},
|
||||
&Pod{},
|
||||
&ReplicationControllerList{},
|
||||
|
@@ -17,9 +17,7 @@ limitations under the License.
|
||||
package v1beta2
|
||||
|
||||
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"`
|
||||
@@ -166,7 +164,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 +207,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 +248,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 +297,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 +328,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"`
|
||||
}
|
||||
|
||||
@@ -550,14 +545,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 +560,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 +633,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
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user