Merge pull request #1202 from lavalamp/fixApi3

Please expedite: the rarely attempted interface{} -> runtime.Object rename
This commit is contained in:
Daniel Smith
2014-09-08 11:55:09 -07:00
89 changed files with 974 additions and 812 deletions

View File

@@ -179,7 +179,7 @@ func runReplicationControllerTest(c *client.Client) {
}
glog.Infof("Creating replication controllers")
if _, err := c.CreateReplicationController(controllerRequest); err != nil {
if _, err := c.CreateReplicationController(&controllerRequest); err != nil {
glog.Fatalf("Unexpected error: %#v", err)
}
glog.Infof("Done creating replication controllers")
@@ -194,7 +194,7 @@ func runReplicationControllerTest(c *client.Client) {
if err != nil {
glog.Fatalf("FAILED: unable to get pods to list: %v", err)
}
if err := wait.Poll(time.Second, time.Second*10, podsOnMinions(c, pods)); err != nil {
if err := wait.Poll(time.Second, time.Second*10, podsOnMinions(c, *pods)); err != nil {
glog.Fatalf("FAILED: pods never started running %v", err)
}
@@ -204,7 +204,7 @@ func runReplicationControllerTest(c *client.Client) {
func runAtomicPutTest(c *client.Client) {
var svc api.Service
err := c.Post().Path("services").Body(
api.Service{
&api.Service{
JSONBase: api.JSONBase{ID: "atomicservice", APIVersion: "v1beta1"},
Port: 12345,
Labels: map[string]string{

View File

@@ -58,11 +58,11 @@ var (
imageName = flag.String("image", "", "Image used when updating a replicationController. Will apply to the first container in the pod template.")
)
var parser = kubecfg.NewParser(map[string]interface{}{
"pods": api.Pod{},
"services": api.Service{},
"replicationControllers": api.ReplicationController{},
"minions": api.Minion{},
var parser = kubecfg.NewParser(map[string]runtime.Object{
"pods": &api.Pod{},
"services": &api.Service{},
"replicationControllers": &api.ReplicationController{},
"minions": &api.Minion{},
})
func usage() {
@@ -266,7 +266,7 @@ func executeAPIRequest(method string, c *client.Client) bool {
if setBody {
if version != 0 {
data := readConfig(storage)
obj, err := runtime.Decode(data)
obj, err := runtime.DefaultCodec.Decode(data)
if err != nil {
glog.Fatalf("error setting resource version: %v", err)
}
@@ -275,7 +275,7 @@ func executeAPIRequest(method string, c *client.Client) bool {
glog.Fatalf("error setting resource version: %v", err)
}
jsonBase.SetResourceVersion(version)
data, err = runtime.Encode(obj)
data, err = runtime.DefaultCodec.Encode(obj)
if err != nil {
glog.Fatalf("error setting resource version: %v", err)
}

View File

@@ -31,7 +31,7 @@ import (
"github.com/golang/glog"
)
func validateObject(obj interface{}) (errors []error) {
func validateObject(obj runtime.Object) (errors []error) {
switch t := obj.(type) {
case *api.ReplicationController:
errors = validation.ValidateManifest(&t.DesiredState.PodTemplate.DesiredState.Manifest)
@@ -85,7 +85,7 @@ func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error
}
func TestApiExamples(t *testing.T) {
expected := map[string]interface{}{
expected := map[string]runtime.Object{
"controller": &api.ReplicationController{},
"controller-list": &api.ReplicationControllerList{},
"pod": &api.Pod{},
@@ -103,7 +103,7 @@ func TestApiExamples(t *testing.T) {
return
}
tested += 1
if err := runtime.DecodeInto(data, expectedType); err != nil {
if err := runtime.DefaultCodec.DecodeInto(data, expectedType); err != nil {
t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data))
return
}
@@ -120,7 +120,7 @@ func TestApiExamples(t *testing.T) {
}
func TestExamples(t *testing.T) {
expected := map[string]interface{}{
expected := map[string]runtime.Object{
"frontend-controller": &api.ReplicationController{},
"redis-slave-controller": &api.ReplicationController{},
"redis-master": &api.Pod{},
@@ -137,7 +137,7 @@ func TestExamples(t *testing.T) {
return
}
tested += 1
if err := runtime.DecodeInto(data, expectedType); err != nil {
if err := runtime.DefaultCodec.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.DecodeInto([]byte(json), expectedType); err != nil {
if err := runtime.DefaultCodec.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.Encode(expectedType)
encoded, err := runtime.DefaultCodec.Encode(expectedType)
if err != nil {
t.Errorf("Could not encode object: %v", err)
continue

View File

@@ -21,21 +21,21 @@ import (
)
func init() {
runtime.AddKnownTypes("",
PodList{},
Pod{},
ReplicationControllerList{},
ReplicationController{},
ServiceList{},
Service{},
MinionList{},
Minion{},
Status{},
ServerOpList{},
ServerOp{},
ContainerManifestList{},
Endpoints{},
EndpointsList{},
Binding{},
runtime.DefaultScheme.AddKnownTypes("",
&PodList{},
&Pod{},
&ReplicationControllerList{},
&ReplicationController{},
&ServiceList{},
&Service{},
&MinionList{},
&Minion{},
&Status{},
&ServerOpList{},
&ServerOp{},
&ContainerManifestList{},
&Endpoints{},
&EndpointsList{},
&Binding{},
)
}

View File

@@ -85,7 +85,7 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
},
)
func objDiff(a, b interface{}) string {
func objDiff(a, b runtime.Object) string {
ab, err := json.Marshal(a)
if err != nil {
panic("a")
@@ -105,7 +105,7 @@ func objDiff(a, b interface{}) string {
)
}
func runTest(t *testing.T, source interface{}) {
func runTest(t *testing.T, source runtime.Object) {
name := reflect.TypeOf(source).Elem().Name()
apiObjectFuzzer.Fuzz(source)
j, err := runtime.FindJSONBase(source)
@@ -115,13 +115,13 @@ func runTest(t *testing.T, source interface{}) {
j.SetKind("")
j.SetAPIVersion("")
data, err := runtime.Encode(source)
data, err := runtime.DefaultCodec.Encode(source)
if err != nil {
t.Errorf("%v: %v (%#v)", name, err, source)
return
}
obj2, err := runtime.Decode(data)
obj2, err := runtime.DefaultCodec.Decode(data)
if err != nil {
t.Errorf("%v: %v", name, err)
return
@@ -131,8 +131,8 @@ func runTest(t *testing.T, source interface{}) {
return
}
}
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface()
err = runtime.DecodeInto(data, obj3)
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface().(runtime.Object)
err = runtime.DefaultCodec.DecodeInto(data, obj3)
if err != nil {
t.Errorf("2: %v: %v", name, err)
return
@@ -145,7 +145,7 @@ func runTest(t *testing.T, source interface{}) {
}
func TestTypes(t *testing.T) {
table := []interface{}{
table := []runtime.Object{
&api.PodList{},
&api.Pod{},
&api.ServiceList{},
@@ -169,31 +169,13 @@ func TestTypes(t *testing.T) {
}
}
func TestEncode_NonPtr(t *testing.T) {
pod := api.Pod{
Labels: map[string]string{"name": "foo"},
}
obj := interface{}(pod)
data, err := runtime.Encode(obj)
obj2, err2 := runtime.Decode(data)
if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2)
}
if _, ok := obj2.(*api.Pod); !ok {
t.Fatalf("Got wrong type")
}
if !reflect.DeepEqual(obj2, &pod) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
}
}
func TestEncode_Ptr(t *testing.T) {
pod := &api.Pod{
Labels: map[string]string{"name": "foo"},
}
obj := interface{}(pod)
data, err := runtime.Encode(obj)
obj2, err2 := runtime.Decode(data)
obj := runtime.Object(pod)
data, err := runtime.DefaultCodec.Encode(obj)
obj2, err2 := runtime.DefaultCodec.Decode(data)
if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2)
}
@@ -207,11 +189,11 @@ func TestEncode_Ptr(t *testing.T) {
func TestBadJSONRejection(t *testing.T) {
badJSONMissingKind := []byte(`{ }`)
if _, err := runtime.Decode(badJSONMissingKind); err == nil {
if _, err := runtime.DefaultCodec.Decode(badJSONMissingKind); err == nil {
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
}
badJSONUnknownType := []byte(`{"kind": "bar"}`)
if _, err1 := runtime.Decode(badJSONUnknownType); err1 == nil {
if _, err1 := runtime.DefaultCodec.Decode(badJSONUnknownType); err1 == nil {
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
}
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)

View File

@@ -65,6 +65,8 @@ type ContainerManifestList struct {
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
@@ -287,6 +289,8 @@ type PodList struct {
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"`
@@ -295,6 +299,8 @@ type Pod struct {
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"`
@@ -308,6 +314,8 @@ type ReplicationControllerList struct {
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"`
@@ -315,6 +323,8 @@ type ReplicationController struct {
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"`
@@ -327,6 +337,8 @@ type ServiceList struct {
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.
@@ -346,6 +358,8 @@ type Service struct {
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 {
@@ -353,12 +367,16 @@ type Endpoints struct {
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 {
@@ -367,12 +385,16 @@ type Minion struct {
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"`
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"`
@@ -380,6 +402,8 @@ type Binding struct {
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.
@@ -403,6 +427,8 @@ type Status struct {
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
@@ -539,12 +565,16 @@ 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() {}
// 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.

View File

@@ -19,22 +19,20 @@ 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() {
// Shortcut for sub-conversions. TODO: This should possibly be refactored
// such that this convert function is passed to each conversion func.
Convert := runtime.Convert
runtime.AddConversionFuncs(
runtime.DefaultScheme.AddConversionFuncs(
// EnvVar's Key is deprecated in favor of Name.
func(in *newer.EnvVar, out *EnvVar) error {
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) error {
func(in *EnvVar, out *newer.EnvVar, s conversion.Scope) error {
out.Value = in.Value
if in.Name != "" {
out.Name = in.Name
@@ -45,7 +43,7 @@ func init() {
},
// Path & MountType are deprecated.
func(in *newer.VolumeMount, out *VolumeMount) error {
func(in *newer.VolumeMount, out *VolumeMount, s conversion.Scope) error {
out.Name = in.Name
out.ReadOnly = in.ReadOnly
out.MountPath = in.MountPath
@@ -53,7 +51,7 @@ func init() {
out.MountType = "" // MountType is ignored.
return nil
},
func(in *VolumeMount, out *newer.VolumeMount) error {
func(in *VolumeMount, out *newer.VolumeMount, s conversion.Scope) error {
out.Name = in.Name
out.ReadOnly = in.ReadOnly
if in.MountPath == "" {
@@ -65,18 +63,18 @@ func init() {
},
// MinionList.Items had a wrong name in v1beta1
func(in *newer.MinionList, out *MinionList) error {
Convert(&in.JSONBase, &out.JSONBase)
Convert(&in.Items, &out.Items)
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) error {
Convert(&in.JSONBase, &out.JSONBase)
func(in *MinionList, out *newer.MinionList, s conversion.Scope) error {
s.Convert(&in.JSONBase, &out.JSONBase, 0)
if len(in.Items) == 0 {
Convert(&in.Minions, &out.Items)
s.Convert(&in.Minions, &out.Items, 0)
} else {
Convert(&in.Items, &out.Items)
s.Convert(&in.Items, &out.Items, 0)
}
return nil
},

View File

@@ -25,7 +25,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
var Convert = runtime.Convert
var Convert = runtime.DefaultScheme.Convert
func TestEnvConversion(t *testing.T) {
nonCanonical := []v1beta1.EnvVar{

View File

@@ -21,21 +21,21 @@ import (
)
func init() {
runtime.AddKnownTypes("v1beta1",
PodList{},
Pod{},
ReplicationControllerList{},
ReplicationController{},
ServiceList{},
Service{},
MinionList{},
Minion{},
Status{},
ServerOpList{},
ServerOp{},
ContainerManifestList{},
Endpoints{},
EndpointsList{},
Binding{},
runtime.DefaultScheme.AddKnownTypes("v1beta1",
&PodList{},
&Pod{},
&ReplicationControllerList{},
&ReplicationController{},
&ServiceList{},
&Service{},
&MinionList{},
&Minion{},
&Status{},
&ServerOpList{},
&ServerOp{},
&ContainerManifestList{},
&Endpoints{},
&EndpointsList{},
&Binding{},
)
}

View File

@@ -65,6 +65,8 @@ type ContainerManifestList struct {
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
@@ -243,6 +245,8 @@ type JSONBase struct {
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
}
func (*JSONBase) IsAnAPIObject() {}
// PodStatus represents a status of a pod.
type PodStatus string
@@ -298,6 +302,8 @@ type PodList struct {
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"`
@@ -306,6 +312,8 @@ type Pod struct {
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"`
@@ -319,6 +327,8 @@ type ReplicationControllerList struct {
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"`
@@ -326,6 +336,8 @@ type ReplicationController struct {
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"`
@@ -338,6 +350,8 @@ type ServiceList struct {
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.
@@ -357,6 +371,8 @@ type Service struct {
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 {
@@ -364,12 +380,16 @@ type Endpoints struct {
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 {
@@ -378,6 +398,8 @@ type Minion struct {
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"`
@@ -387,6 +409,8 @@ type MinionList struct {
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"`
@@ -394,6 +418,8 @@ type Binding struct {
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.
@@ -417,6 +443,8 @@ type Status struct {
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
@@ -540,12 +568,16 @@ 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() {}
// 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.

View File

@@ -27,17 +27,11 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
"github.com/golang/glog"
)
// Codec defines methods for serializing and deserializing API objects.
type Codec interface {
Encode(obj interface{}) (data []byte, err error)
Decode(data []byte) (interface{}, error)
DecodeInto(data []byte, obj interface{}) error
}
// mux is an object that can register http handlers.
type mux interface {
Handle(pattern string, handler http.Handler)
@@ -53,7 +47,7 @@ type defaultAPIServer struct {
// Handle returns a Handler function that expose the provided storage interfaces
// as RESTful resources at prefix, serialized by codec, and also includes the support
// http resources.
func Handle(storage map[string]RESTStorage, codec Codec, prefix string) http.Handler {
func Handle(storage map[string]RESTStorage, codec runtime.Codec, prefix string) http.Handler {
group := NewAPIGroup(storage, codec)
mux := http.NewServeMux()
@@ -78,7 +72,7 @@ type APIGroup struct {
// This is a helper method for registering multiple sets of REST handlers under different
// prefixes onto a server.
// TODO: add multitype codec serialization
func NewAPIGroup(storage map[string]RESTStorage, codec Codec) *APIGroup {
func NewAPIGroup(storage map[string]RESTStorage, codec runtime.Codec) *APIGroup {
return &APIGroup{RESTHandler{
storage: storage,
codec: codec,
@@ -147,7 +141,7 @@ func handleVersion(w http.ResponseWriter, req *http.Request) {
}
// writeJSON renders an object as JSON to the response.
func writeJSON(statusCode int, codec Codec, object interface{}, w http.ResponseWriter) {
func writeJSON(statusCode int, codec runtime.Codec, object runtime.Object, w http.ResponseWriter) {
output, err := codec.Encode(object)
if err != nil {
errorJSON(err, codec, w)
@@ -159,7 +153,7 @@ func writeJSON(statusCode int, codec Codec, object interface{}, w http.ResponseW
}
// errorJSON renders an error to the response.
func errorJSON(err error, codec Codec, w http.ResponseWriter) {
func errorJSON(err error, codec runtime.Codec, w http.ResponseWriter) {
status := errToAPIStatus(err)
writeJSON(status.Code, codec, status, w)
}

View File

@@ -38,15 +38,15 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
func convert(obj interface{}) (interface{}, error) {
func convert(obj runtime.Object) (runtime.Object, error) {
return obj, nil
}
var codec = runtime.Codec
var codec = runtime.DefaultCodec
func init() {
runtime.AddKnownTypes("", Simple{}, SimpleList{})
runtime.AddKnownTypes("v1beta1", Simple{}, SimpleList{})
runtime.DefaultScheme.AddKnownTypes("", &Simple{}, &SimpleList{})
runtime.DefaultScheme.AddKnownTypes("v1beta1", &Simple{}, &SimpleList{})
}
type Simple struct {
@@ -54,11 +54,15 @@ type Simple struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
}
func (*Simple) IsAnAPIObject() {}
type SimpleList struct {
api.JSONBase `yaml:",inline" json:",inline"`
Items []Simple `yaml:"items,omitempty" json:"items,omitempty"`
}
func (*SimpleList) IsAnAPIObject() {}
type SimpleRESTStorage struct {
errors map[string]error
list []Simple
@@ -78,43 +82,43 @@ type SimpleRESTStorage struct {
// If non-nil, called inside the WorkFunc when answering update, delete, create.
// obj receives the original input to the update, delete, or create call.
injectedFunction func(obj interface{}) (returnObj interface{}, err error)
injectedFunction func(obj runtime.Object) (returnObj runtime.Object, err error)
}
func (storage *SimpleRESTStorage) List(labels.Selector) (interface{}, error) {
func (storage *SimpleRESTStorage) List(labels.Selector) (runtime.Object, error) {
result := &SimpleList{
Items: storage.list,
}
return result, storage.errors["list"]
}
func (storage *SimpleRESTStorage) Get(id string) (interface{}, error) {
return storage.item, storage.errors["get"]
func (storage *SimpleRESTStorage) Get(id string) (runtime.Object, error) {
return runtime.DefaultScheme.CopyOrDie(&storage.item), storage.errors["get"]
}
func (storage *SimpleRESTStorage) Delete(id string) (<-chan interface{}, error) {
func (storage *SimpleRESTStorage) Delete(id string) (<-chan runtime.Object, error) {
storage.deleted = id
if err := storage.errors["delete"]; err != nil {
return nil, err
}
return MakeAsync(func() (interface{}, error) {
return MakeAsync(func() (runtime.Object, error) {
if storage.injectedFunction != nil {
return storage.injectedFunction(id)
return storage.injectedFunction(&Simple{JSONBase: api.JSONBase{ID: id}})
}
return &api.Status{Status: api.StatusSuccess}, nil
}), nil
}
func (storage *SimpleRESTStorage) New() interface{} {
func (storage *SimpleRESTStorage) New() runtime.Object {
return &Simple{}
}
func (storage *SimpleRESTStorage) Create(obj interface{}) (<-chan interface{}, error) {
func (storage *SimpleRESTStorage) Create(obj runtime.Object) (<-chan runtime.Object, error) {
storage.created = obj.(*Simple)
if err := storage.errors["create"]; err != nil {
return nil, err
}
return MakeAsync(func() (interface{}, error) {
return MakeAsync(func() (runtime.Object, error) {
if storage.injectedFunction != nil {
return storage.injectedFunction(obj)
}
@@ -122,12 +126,12 @@ func (storage *SimpleRESTStorage) Create(obj interface{}) (<-chan interface{}, e
}), nil
}
func (storage *SimpleRESTStorage) Update(obj interface{}) (<-chan interface{}, error) {
func (storage *SimpleRESTStorage) Update(obj runtime.Object) (<-chan runtime.Object, error) {
storage.updated = obj.(*Simple)
if err := storage.errors["update"]; err != nil {
return nil, err
}
return MakeAsync(func() (interface{}, error) {
return MakeAsync(func() (runtime.Object, error) {
if storage.injectedFunction != nil {
return storage.injectedFunction(obj)
}
@@ -156,7 +160,7 @@ func (storage *SimpleRESTStorage) ResourceLocation(id string) (string, error) {
return id, nil
}
func extractBody(response *http.Response, object interface{}) (string, error) {
func extractBody(response *http.Response, object runtime.Object) (string, error) {
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
@@ -398,7 +402,7 @@ func TestUpdate(t *testing.T) {
handler := Handle(storage, codec, "/prefix/version")
server := httptest.NewServer(handler)
item := Simple{
item := &Simple{
Name: "bar",
}
body, err := codec.Encode(item)
@@ -428,7 +432,7 @@ func TestUpdateMissing(t *testing.T) {
handler := Handle(storage, codec, "/prefix/version")
server := httptest.NewServer(handler)
item := Simple{
item := &Simple{
Name: "bar",
}
body, err := codec.Encode(item)
@@ -457,7 +461,7 @@ func TestCreate(t *testing.T) {
server := httptest.NewServer(handler)
client := http.Client{}
simple := Simple{
simple := &Simple{
Name: "foo",
}
data, _ := codec.Encode(simple)
@@ -497,7 +501,7 @@ func TestCreateNotFound(t *testing.T) {
server := httptest.NewServer(handler)
client := http.Client{}
simple := Simple{Name: "foo"}
simple := &Simple{Name: "foo"}
data, _ := codec.Encode(simple)
request, err := http.NewRequest("POST", server.URL+"/prefix/version/simple", bytes.NewBuffer(data))
if err != nil {
@@ -528,7 +532,7 @@ func TestParseTimeout(t *testing.T) {
func TestSyncCreate(t *testing.T) {
storage := SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) {
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
time.Sleep(5 * time.Millisecond)
return obj, nil
},
@@ -539,7 +543,7 @@ func TestSyncCreate(t *testing.T) {
server := httptest.NewServer(handler)
client := http.Client{}
simple := Simple{
simple := &Simple{
Name: "foo",
}
data, _ := codec.Encode(simple)
@@ -566,7 +570,7 @@ func TestSyncCreate(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
if !reflect.DeepEqual(itemOut, simple) {
if !reflect.DeepEqual(&itemOut, simple) {
t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simple, string(body))
}
if response.StatusCode != http.StatusOK {
@@ -600,7 +604,7 @@ func expectApiStatus(t *testing.T, method, url string, data []byte, code int) *a
func TestAsyncDelayReturnsError(t *testing.T) {
storage := SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) {
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
return nil, apierrs.NewAlreadyExists("foo", "bar")
},
}
@@ -617,7 +621,7 @@ func TestAsyncDelayReturnsError(t *testing.T) {
func TestAsyncCreateError(t *testing.T) {
ch := make(chan struct{})
storage := SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) {
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
<-ch
return nil, apierrs.NewAlreadyExists("foo", "bar")
},
@@ -626,7 +630,7 @@ func TestAsyncCreateError(t *testing.T) {
handler.(*defaultAPIServer).group.handler.asyncOpWait = 0
server := httptest.NewServer(handler)
simple := Simple{Name: "foo"}
simple := &Simple{Name: "foo"}
data, _ := codec.Encode(simple)
status := expectApiStatus(t, "POST", fmt.Sprintf("%s/prefix/version/foo", server.URL), data, http.StatusAccepted)
@@ -662,18 +666,21 @@ func TestAsyncCreateError(t *testing.T) {
}
}
type UnregisteredAPIObject struct {
Value string
}
func (*UnregisteredAPIObject) IsAnAPIObject() {}
func TestWriteJSONDecodeError(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
type T struct {
Value string
}
writeJSON(http.StatusOK, runtime.Codec, &T{"Undecodable"}, w)
writeJSON(http.StatusOK, runtime.DefaultCodec, &UnregisteredAPIObject{"Undecodable"}, w)
}))
status := expectApiStatus(t, "GET", server.URL, nil, http.StatusInternalServerError)
if status.Reason != api.StatusReasonUnknown {
t.Errorf("unexpected reason %#v", status)
}
if !strings.Contains(status.Message, "type apiserver.T is not registered") {
if !strings.Contains(status.Message, "type apiserver.UnregisteredAPIObject is not registered") {
t.Errorf("unexpected message %#v", status)
}
}
@@ -705,7 +712,7 @@ func TestSyncCreateTimeout(t *testing.T) {
testOver := make(chan struct{})
defer close(testOver)
storage := SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) {
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
// Eliminate flakes by ensuring the create operation takes longer than this test.
<-testOver
return obj, nil
@@ -716,7 +723,7 @@ func TestSyncCreateTimeout(t *testing.T) {
}, codec, "/prefix/version")
server := httptest.NewServer(handler)
simple := Simple{Name: "foo"}
simple := &Simple{Name: "foo"}
data, _ := codec.Encode(simple)
itemOut := expectApiStatus(t, "POST", server.URL+"/prefix/version/foo?sync=true&timeout=4ms", data, http.StatusAccepted)
if itemOut.Status != api.StatusWorking || itemOut.Details == nil || itemOut.Details.ID == "" {

View File

@@ -17,18 +17,19 @@ limitations under the License.
package apiserver
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
// WorkFunc is used to perform any time consuming work for an api call, after
// the input has been validated. Pass one of these to MakeAsync to create an
// appropriate return value for the Update, Delete, and Create methods.
type WorkFunc func() (result interface{}, err error)
type WorkFunc func() (result runtime.Object, err error)
// MakeAsync takes a function and executes it, delivering the result in the way required
// by RESTStorage's Update, Delete, and Create methods.
func MakeAsync(fn WorkFunc) <-chan interface{} {
channel := make(chan interface{})
func MakeAsync(fn WorkFunc) <-chan runtime.Object {
channel := make(chan runtime.Object)
go func() {
defer util.HandleCrash()
obj, err := fn()

View File

@@ -18,6 +18,7 @@ package apiserver
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
@@ -25,25 +26,25 @@ import (
// Resources which are exported to the RESTful API of apiserver need to implement this interface.
type RESTStorage interface {
// New returns an empty object that can be used with Create and Update after request data has been put into it.
// This object must be a pointer type for use with Codec.DecodeInto([]byte, interface{})
New() interface{}
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
New() runtime.Object
// List selects resources in the storage which match to the selector.
// TODO: add field selector in addition to label selector.
List(labels.Selector) (interface{}, error)
List(labels.Selector) (runtime.Object, error)
// Get finds a resource in the storage by id and returns it.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
// returned error value err when the specified resource is not found.
Get(id string) (interface{}, error)
Get(id string) (runtime.Object, error)
// Delete finds a resource in the storage and deletes it.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
// returned error value err when the specified resource is not found.
Delete(id string) (<-chan interface{}, error)
Delete(id string) (<-chan runtime.Object, error)
Create(interface{}) (<-chan interface{}, error)
Update(interface{}) (<-chan interface{}, error)
Create(runtime.Object) (<-chan runtime.Object, error)
Update(runtime.Object) (<-chan runtime.Object, error)
}
// ResourceWatcher should be implemented by all RESTStorage objects that

View File

@@ -25,12 +25,13 @@ import (
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
type OperationHandler struct {
ops *Operations
codec Codec
codec runtime.Codec
}
func (h *OperationHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
@@ -63,8 +64,8 @@ func (h *OperationHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Operation represents an ongoing action which the server is performing.
type Operation struct {
ID string
result interface{}
awaiting <-chan interface{}
result runtime.Object
awaiting <-chan runtime.Object
finished *time.Time
lock sync.Mutex
notify chan struct{}
@@ -90,7 +91,7 @@ func NewOperations() *Operations {
}
// NewOperation adds a new operation. It is lock-free.
func (ops *Operations) NewOperation(from <-chan interface{}) *Operation {
func (ops *Operations) NewOperation(from <-chan runtime.Object) *Operation {
id := atomic.AddInt64(&ops.lastID, 1)
op := &Operation{
ID: strconv.FormatInt(id, 10),
@@ -110,7 +111,7 @@ func (ops *Operations) insert(op *Operation) {
}
// List lists operations for an API client.
func (ops *Operations) List() api.ServerOpList {
func (ops *Operations) List() *api.ServerOpList {
ops.lock.Lock()
defer ops.lock.Unlock()
@@ -119,7 +120,7 @@ func (ops *Operations) List() api.ServerOpList {
ids = append(ids, id)
}
sort.StringSlice(ids).Sort()
ol := api.ServerOpList{}
ol := &api.ServerOpList{}
for _, id := range ids {
ol.Items = append(ol.Items, api.ServerOp{JSONBase: api.JSONBase{ID: id}})
}
@@ -185,7 +186,7 @@ func (op *Operation) expired(limitTime time.Time) bool {
// StatusOrResult returns status information or the result of the operation if it is complete,
// with a bool indicating true in the latter case.
func (op *Operation) StatusOrResult() (description interface{}, finished bool) {
func (op *Operation) StatusOrResult() (description runtime.Object, finished bool) {
op.lock.Lock()
defer op.lock.Unlock()

View File

@@ -28,12 +28,13 @@ import (
// TODO: remove dependency on api, apiserver should be generic
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
func TestOperation(t *testing.T) {
ops := NewOperations()
c := make(chan interface{})
c := make(chan runtime.Object)
op := ops.NewOperation(c)
// Allow context switch, so that op's ID can get added to the map and Get will work.
// This is just so we can test Get. Ordinary users have no need to call Get immediately
@@ -41,7 +42,7 @@ func TestOperation(t *testing.T) {
time.Sleep(time.Millisecond)
go func() {
time.Sleep(500 * time.Millisecond)
c <- "All done"
c <- &Simple{JSONBase: api.JSONBase{ID: "All done"}}
}()
if op.expired(time.Now().Add(-time.Minute)) {
@@ -89,7 +90,7 @@ func TestOperation(t *testing.T) {
t.Errorf("expire failed to remove the operation %#v", ops)
}
if op.result.(string) != "All done" {
if op.result.(*Simple).ID != "All done" {
t.Errorf("Got unexpected result: %#v", op.result)
}
}
@@ -98,7 +99,7 @@ func TestOperationsList(t *testing.T) {
testOver := make(chan struct{})
defer close(testOver)
simpleStorage := &SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) {
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
// Eliminate flakes by ensuring the create operation takes longer than this test.
<-testOver
return obj, nil
@@ -111,7 +112,7 @@ func TestOperationsList(t *testing.T) {
server := httptest.NewServer(handler)
client := http.Client{}
simple := Simple{
simple := &Simple{
Name: "foo",
}
data, err := codec.Encode(simple)
@@ -154,7 +155,7 @@ func TestOpGet(t *testing.T) {
testOver := make(chan struct{})
defer close(testOver)
simpleStorage := &SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) {
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
// Eliminate flakes by ensuring the create operation takes longer than this test.
<-testOver
return obj, nil
@@ -167,7 +168,7 @@ func TestOpGet(t *testing.T) {
server := httptest.NewServer(handler)
client := http.Client{}
simple := Simple{
simple := &Simple{
Name: "foo",
}
data, err := codec.Encode(simple)

View File

@@ -20,11 +20,12 @@ import (
"net/http"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
type RedirectHandler struct {
storage map[string]RESTStorage
codec Codec
codec runtime.Codec
}
func (r *RedirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {

View File

@@ -23,11 +23,12 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
type RESTHandler struct {
storage map[string]RESTStorage
codec Codec
codec runtime.Codec
ops *Operations
asyncOpWait time.Duration
}
@@ -158,7 +159,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
}
// createOperation creates an operation to process a channel response.
func (h *RESTHandler) createOperation(out <-chan interface{}, sync bool, timeout time.Duration) *Operation {
func (h *RESTHandler) createOperation(out <-chan runtime.Object, sync bool, timeout time.Duration) *Operation {
op := h.ops.NewOperation(out)
if sync {
op.WaitFor(timeout)
@@ -175,11 +176,6 @@ func (h *RESTHandler) finishReq(op *Operation, w http.ResponseWriter) {
if complete {
status := http.StatusOK
switch stat := obj.(type) {
case api.Status:
httplog.LogOf(w).Addf("programmer error: use *api.Status as a result, not api.Status.")
if stat.Code != 0 {
status = stat.Code
}
case *api.Status:
if stat.Code != 0 {
status = stat.Code

View File

@@ -32,7 +32,7 @@ import (
type WatchHandler struct {
storage map[string]RESTStorage
codec Codec
codec runtime.Codec
}
func getWatchParams(query url.Values) (label, field labels.Selector, resourceVersion uint64) {

View File

@@ -26,12 +26,13 @@ import (
"code.google.com/p/go.net/websocket"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
var watchTestTable = []struct {
t watch.EventType
obj interface{}
obj runtime.Object
}{
{watch.Added, &Simple{Name: "A Name"}},
{watch.Modified, &Simple{Name: "Another Name"}},
@@ -56,7 +57,7 @@ func TestWatchWebsocket(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
try := func(action watch.EventType, object interface{}) {
try := func(action watch.EventType, object runtime.Object) {
// Send
simpleStorage.fakeWatch.Action(action, object)
// Test receive
@@ -113,7 +114,7 @@ func TestWatchHTTP(t *testing.T) {
decoder := json.NewDecoder(response.Body)
try := func(action watch.EventType, object interface{}) {
try := func(action watch.EventType, object runtime.Object) {
// Send
simpleStorage.fakeWatch.Action(action, object)
// Test receive

View File

@@ -46,36 +46,36 @@ type Interface interface {
// PodInterface has methods to work with Pod resources.
type PodInterface interface {
ListPods(selector labels.Selector) (api.PodList, error)
GetPod(id string) (api.Pod, error)
ListPods(selector labels.Selector) (*api.PodList, error)
GetPod(id string) (*api.Pod, error)
DeletePod(id string) error
CreatePod(api.Pod) (api.Pod, error)
UpdatePod(api.Pod) (api.Pod, error)
CreatePod(*api.Pod) (*api.Pod, error)
UpdatePod(*api.Pod) (*api.Pod, error)
}
// ReplicationControllerInterface has methods to work with ReplicationController resources.
type ReplicationControllerInterface interface {
ListReplicationControllers(selector labels.Selector) (api.ReplicationControllerList, error)
GetReplicationController(id string) (api.ReplicationController, error)
CreateReplicationController(api.ReplicationController) (api.ReplicationController, error)
UpdateReplicationController(api.ReplicationController) (api.ReplicationController, error)
ListReplicationControllers(selector labels.Selector) (*api.ReplicationControllerList, error)
GetReplicationController(id string) (*api.ReplicationController, error)
CreateReplicationController(*api.ReplicationController) (*api.ReplicationController, error)
UpdateReplicationController(*api.ReplicationController) (*api.ReplicationController, error)
DeleteReplicationController(string) error
WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}
// ServiceInterface has methods to work with Service resources.
type ServiceInterface interface {
ListServices(selector labels.Selector) (api.ServiceList, error)
GetService(id string) (api.Service, error)
CreateService(api.Service) (api.Service, error)
UpdateService(api.Service) (api.Service, error)
ListServices(selector labels.Selector) (*api.ServiceList, error)
GetService(id string) (*api.Service, error)
CreateService(*api.Service) (*api.Service, error)
UpdateService(*api.Service) (*api.Service, error)
DeleteService(string) error
WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}
// EndpointsInterface has methods to work with Endpoints resources
type EndpointsInterface interface {
ListEndpoints(selector labels.Selector) (api.EndpointsList, error)
ListEndpoints(selector labels.Selector) (*api.EndpointsList, error)
WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}
@@ -85,7 +85,7 @@ type VersionInterface interface {
}
type MinionInterface interface {
ListMinions() (api.MinionList, error)
ListMinions() (*api.MinionList, error)
}
// Client is the actual implementation of a Kubernetes client.
@@ -222,7 +222,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.DecodeInto(body, &status); err == nil && status.Status != "" {
if err := runtime.DefaultCodec.DecodeInto(body, &status); err == nil && status.Status != "" {
isStatusResponse = true
}
@@ -247,14 +247,16 @@ func (c *RESTClient) doRequest(request *http.Request) ([]byte, error) {
}
// ListPods takes a selector, and returns the list of pods that match that selector.
func (c *Client) ListPods(selector labels.Selector) (result api.PodList, err error) {
err = c.Get().Path("pods").SelectorParam("labels", selector).Do().Into(&result)
func (c *Client) ListPods(selector labels.Selector) (result *api.PodList, err error) {
result = &api.PodList{}
err = c.Get().Path("pods").SelectorParam("labels", selector).Do().Into(result)
return
}
// GetPod takes the id of the pod, and returns the corresponding Pod object, and an error if it occurs
func (c *Client) GetPod(id string) (result api.Pod, err error) {
err = c.Get().Path("pods").Path(id).Do().Into(&result)
func (c *Client) GetPod(id string) (result *api.Pod, err error) {
result = &api.Pod{}
err = c.Get().Path("pods").Path(id).Do().Into(result)
return
}
@@ -264,46 +266,52 @@ func (c *Client) DeletePod(id string) error {
}
// CreatePod takes the representation of a pod. Returns the server's representation of the pod, and an error, if it occurs.
func (c *Client) CreatePod(pod api.Pod) (result api.Pod, err error) {
err = c.Post().Path("pods").Body(pod).Do().Into(&result)
func (c *Client) CreatePod(pod *api.Pod) (result *api.Pod, err error) {
result = &api.Pod{}
err = c.Post().Path("pods").Body(pod).Do().Into(result)
return
}
// UpdatePod takes the representation of a pod to update. Returns the server's representation of the pod, and an error, if it occurs.
func (c *Client) UpdatePod(pod api.Pod) (result api.Pod, err error) {
func (c *Client) UpdatePod(pod *api.Pod) (result *api.Pod, err error) {
result = &api.Pod{}
if pod.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", pod)
return
}
err = c.Put().Path("pods").Path(pod.ID).Body(pod).Do().Into(&result)
err = c.Put().Path("pods").Path(pod.ID).Body(pod).Do().Into(result)
return
}
// ListReplicationControllers takes a selector, and returns the list of replication controllers that match that selector.
func (c *Client) ListReplicationControllers(selector labels.Selector) (result api.ReplicationControllerList, err error) {
err = c.Get().Path("replicationControllers").SelectorParam("labels", selector).Do().Into(&result)
func (c *Client) ListReplicationControllers(selector labels.Selector) (result *api.ReplicationControllerList, err error) {
result = &api.ReplicationControllerList{}
err = c.Get().Path("replicationControllers").SelectorParam("labels", selector).Do().Into(result)
return
}
// GetReplicationController returns information about a particular replication controller.
func (c *Client) GetReplicationController(id string) (result api.ReplicationController, err error) {
err = c.Get().Path("replicationControllers").Path(id).Do().Into(&result)
func (c *Client) GetReplicationController(id string) (result *api.ReplicationController, err error) {
result = &api.ReplicationController{}
err = c.Get().Path("replicationControllers").Path(id).Do().Into(result)
return
}
// CreateReplicationController creates a new replication controller.
func (c *Client) CreateReplicationController(controller api.ReplicationController) (result api.ReplicationController, err error) {
err = c.Post().Path("replicationControllers").Body(controller).Do().Into(&result)
func (c *Client) CreateReplicationController(controller *api.ReplicationController) (result *api.ReplicationController, err error) {
result = &api.ReplicationController{}
err = c.Post().Path("replicationControllers").Body(controller).Do().Into(result)
return
}
// UpdateReplicationController updates an existing replication controller.
func (c *Client) UpdateReplicationController(controller api.ReplicationController) (result api.ReplicationController, err error) {
func (c *Client) UpdateReplicationController(controller *api.ReplicationController) (result *api.ReplicationController, err error) {
result = &api.ReplicationController{}
if controller.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", controller)
return
}
err = c.Put().Path("replicationControllers").Path(controller.ID).Body(controller).Do().Into(&result)
err = c.Put().Path("replicationControllers").Path(controller.ID).Body(controller).Do().Into(result)
return
}
@@ -324,30 +332,34 @@ func (c *Client) WatchReplicationControllers(label, field labels.Selector, resou
}
// ListServices takes a selector, and returns the list of services that match that selector
func (c *Client) ListServices(selector labels.Selector) (result api.ServiceList, err error) {
err = c.Get().Path("services").SelectorParam("labels", selector).Do().Into(&result)
func (c *Client) ListServices(selector labels.Selector) (result *api.ServiceList, err error) {
result = &api.ServiceList{}
err = c.Get().Path("services").SelectorParam("labels", selector).Do().Into(result)
return
}
// GetService returns information about a particular service.
func (c *Client) GetService(id string) (result api.Service, err error) {
err = c.Get().Path("services").Path(id).Do().Into(&result)
func (c *Client) GetService(id string) (result *api.Service, err error) {
result = &api.Service{}
err = c.Get().Path("services").Path(id).Do().Into(result)
return
}
// CreateService creates a new service.
func (c *Client) CreateService(svc api.Service) (result api.Service, err error) {
err = c.Post().Path("services").Body(svc).Do().Into(&result)
func (c *Client) CreateService(svc *api.Service) (result *api.Service, err error) {
result = &api.Service{}
err = c.Post().Path("services").Body(svc).Do().Into(result)
return
}
// UpdateService updates an existing service.
func (c *Client) UpdateService(svc api.Service) (result api.Service, err error) {
func (c *Client) UpdateService(svc *api.Service) (result *api.Service, err error) {
result = &api.Service{}
if svc.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", svc)
return
}
err = c.Put().Path("services").Path(svc.ID).Body(svc).Do().Into(&result)
err = c.Put().Path("services").Path(svc.ID).Body(svc).Do().Into(result)
return
}
@@ -368,8 +380,9 @@ func (c *Client) WatchServices(label, field labels.Selector, resourceVersion uin
}
// ListEndpoints takes a selector, and returns the list of endpoints that match that selector
func (c *Client) ListEndpoints(selector labels.Selector) (result api.EndpointsList, err error) {
err = c.Get().Path("endpoints").SelectorParam("labels", selector).Do().Into(&result)
func (c *Client) ListEndpoints(selector labels.Selector) (result *api.EndpointsList, err error) {
result = &api.EndpointsList{}
err = c.Get().Path("endpoints").SelectorParam("labels", selector).Do().Into(result)
return
}
@@ -399,7 +412,8 @@ func (c *Client) ServerVersion() (*version.Info, error) {
}
// ListMinions lists all the minions in the cluster.
func (c *Client) ListMinions() (minionList api.MinionList, err error) {
err = c.Get().Path("minions").Do().Into(&minionList)
func (c *Client) ListMinions() (result *api.MinionList, err error) {
result = &api.MinionList{}
err = c.Get().Path("minions").Do().Into(result)
return
}

View File

@@ -73,7 +73,7 @@ func TestValidatesHostParameter(t *testing.T) {
func TestListEmptyPods(t *testing.T) {
c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods"},
Response: Response{StatusCode: 200, Body: api.PodList{}},
Response: Response{StatusCode: 200, Body: &api.PodList{}},
}
podList, err := c.Setup().ListPods(labels.Everything())
c.Validate(t, podList, err)
@@ -83,7 +83,7 @@ func TestListPods(t *testing.T) {
c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods"},
Response: Response{StatusCode: 200,
Body: api.PodList{
Body: &api.PodList{
Items: []api.Pod{
{
CurrentState: api.PodState{
@@ -113,7 +113,7 @@ func TestListPodsLabels(t *testing.T) {
Request: testRequest{Method: "GET", Path: "/pods", Query: url.Values{"labels": []string{"foo=bar,name=baz"}}},
Response: Response{
StatusCode: 200,
Body: api.PodList{
Body: &api.PodList{
Items: []api.Pod{
{
CurrentState: api.PodState{
@@ -140,7 +140,7 @@ func TestGetPod(t *testing.T) {
Request: testRequest{Method: "GET", Path: "/pods/foo"},
Response: Response{
StatusCode: 200,
Body: api.Pod{
Body: &api.Pod{
CurrentState: api.PodState{
Status: "Foobar",
},
@@ -165,7 +165,7 @@ func TestDeletePod(t *testing.T) {
}
func TestCreatePod(t *testing.T) {
requestPod := api.Pod{
requestPod := &api.Pod{
CurrentState: api.PodState{
Status: "Foobar",
},
@@ -186,7 +186,7 @@ func TestCreatePod(t *testing.T) {
}
func TestUpdatePod(t *testing.T) {
requestPod := api.Pod{
requestPod := &api.Pod{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1},
CurrentState: api.PodState{
Status: "Foobar",
@@ -208,7 +208,7 @@ func TestListControllers(t *testing.T) {
c := &testClient{
Request: testRequest{Method: "GET", Path: "/replicationControllers"},
Response: Response{StatusCode: 200,
Body: api.ReplicationControllerList{
Body: &api.ReplicationControllerList{
Items: []api.ReplicationController{
{
JSONBase: api.JSONBase{ID: "foo"},
@@ -234,7 +234,7 @@ func TestGetController(t *testing.T) {
Request: testRequest{Method: "GET", Path: "/replicationControllers/foo"},
Response: Response{
StatusCode: 200,
Body: api.ReplicationController{
Body: &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.ReplicationControllerState{
Replicas: 2,
@@ -251,14 +251,14 @@ func TestGetController(t *testing.T) {
}
func TestUpdateController(t *testing.T) {
requestController := api.ReplicationController{
requestController := &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1},
}
c := &testClient{
Request: testRequest{Method: "PUT", Path: "/replicationControllers/foo"},
Response: Response{
StatusCode: 200,
Body: api.ReplicationController{
Body: &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.ReplicationControllerState{
Replicas: 2,
@@ -284,14 +284,14 @@ func TestDeleteController(t *testing.T) {
}
func TestCreateController(t *testing.T) {
requestController := api.ReplicationController{
requestController := &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"},
}
c := &testClient{
Request: testRequest{Method: "POST", Path: "/replicationControllers", Body: requestController},
Response: Response{
StatusCode: 200,
Body: api.ReplicationController{
Body: &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.ReplicationControllerState{
Replicas: 2,
@@ -307,9 +307,9 @@ func TestCreateController(t *testing.T) {
c.Validate(t, receivedController, err)
}
func body(obj interface{}, raw *string) *string {
func body(obj runtime.Object, raw *string) *string {
if obj != nil {
bs, _ := runtime.Encode(obj)
bs, _ := runtime.DefaultCodec.Encode(obj)
body := string(bs)
return &body
}
@@ -321,13 +321,13 @@ type testRequest struct {
Path string
Header string
Query url.Values
Body interface{}
Body runtime.Object
RawBody *string
}
type Response struct {
StatusCode int
Body interface{}
Body runtime.Object
RawBody *string
}
@@ -338,7 +338,6 @@ type testClient struct {
Error bool
server *httptest.Server
handler *util.FakeHandler
Target interface{}
// For query args, an optional function to validate the contents
// useful when the contents can change but still be correct.
// Maps from query arg key to validator.
@@ -363,7 +362,23 @@ func (c *testClient) Setup() *testClient {
return c
}
func (c *testClient) Validate(t *testing.T, received interface{}, err error) {
func (c *testClient) Validate(t *testing.T, received runtime.Object, err error) {
c.ValidateCommon(t, err)
if c.Response.Body != nil && !reflect.DeepEqual(c.Response.Body, received) {
t.Errorf("bad response for request %#v: expected %s, got %s", c.Request, c.Response.Body, received)
}
}
func (c *testClient) ValidateRaw(t *testing.T, received []byte, err error) {
c.ValidateCommon(t, err)
if c.Response.Body != nil && !reflect.DeepEqual(c.Response.Body, received) {
t.Errorf("bad response for request %#v: expected %s, got %s", c.Request, c.Response.Body, received)
}
}
func (c *testClient) ValidateCommon(t *testing.T, err error) {
defer c.server.Close()
if c.Error {
@@ -401,17 +416,13 @@ func (c *testClient) Validate(t *testing.T, received interface{}, err error) {
if expected, received := requestBody, c.handler.RequestBody; expected != nil && *expected != received {
t.Errorf("bad body for request %#v: expected %s, got %s", c.Request, *expected, received)
}
if c.Response.Body != nil && !reflect.DeepEqual(c.Response.Body, received) {
t.Errorf("bad response for request %#v: expected %s, got %s", c.Request, c.Response.Body, received)
}
}
func TestListServices(t *testing.T) {
c := &testClient{
Request: testRequest{Method: "GET", Path: "/services"},
Response: Response{StatusCode: 200,
Body: api.ServiceList{
Body: &api.ServiceList{
Items: []api.Service{
{
JSONBase: api.JSONBase{ID: "name"},
@@ -435,7 +446,7 @@ func TestListServicesLabels(t *testing.T) {
c := &testClient{
Request: testRequest{Method: "GET", Path: "/services", Query: url.Values{"labels": []string{"foo=bar,name=baz"}}},
Response: Response{StatusCode: 200,
Body: api.ServiceList{
Body: &api.ServiceList{
Items: []api.Service{
{
JSONBase: api.JSONBase{ID: "name"},
@@ -464,7 +475,7 @@ func TestGetService(t *testing.T) {
Response: Response{StatusCode: 200, Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
}
response, err := c.Setup().GetService("1")
c.Validate(t, &response, err)
c.Validate(t, response, err)
}
func TestCreateService(t *testing.T) {
@@ -472,18 +483,18 @@ func TestCreateService(t *testing.T) {
Request: testRequest{Method: "POST", Path: "/services", Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
Response: Response{StatusCode: 200, Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
}).Setup()
response, err := c.Setup().CreateService(api.Service{JSONBase: api.JSONBase{ID: "service-1"}})
c.Validate(t, &response, err)
response, err := c.Setup().CreateService(&api.Service{JSONBase: api.JSONBase{ID: "service-1"}})
c.Validate(t, response, err)
}
func TestUpdateService(t *testing.T) {
svc := api.Service{JSONBase: api.JSONBase{ID: "service-1", ResourceVersion: 1}}
svc := &api.Service{JSONBase: api.JSONBase{ID: "service-1", ResourceVersion: 1}}
c := &testClient{
Request: testRequest{Method: "PUT", Path: "/services/service-1", Body: &svc},
Response: Response{StatusCode: 200, Body: &svc},
Request: testRequest{Method: "PUT", Path: "/services/service-1", Body: svc},
Response: Response{StatusCode: 200, Body: svc},
}
response, err := c.Setup().UpdateService(svc)
c.Validate(t, &response, err)
c.Validate(t, response, err)
}
func TestDeleteService(t *testing.T) {
@@ -503,8 +514,8 @@ func TestDoRequest(t *testing.T) {
{Client: NewOrDie("localhost", &AuthInfo{"foo", "bar"}), Request: testRequest{Method: "GET", Path: "auth", Header: "Authorization"}, Response: Response{StatusCode: 200}},
{Client: &Client{&RESTClient{httpClient: http.DefaultClient}}, Request: testRequest{Method: "GET", Path: "nocertificate"}, Error: true},
{Request: testRequest{Method: "GET", Path: "error"}, Response: Response{StatusCode: 500}, Error: true},
{Request: testRequest{Method: "POST", Path: "faildecode"}, Response: Response{StatusCode: 200, RawBody: &invalid}, Target: &struct{}{}},
{Request: testRequest{Method: "GET", Path: "failread"}, Response: Response{StatusCode: 200, RawBody: &invalid}, Target: &struct{}{}},
{Request: testRequest{Method: "POST", Path: "faildecode"}, Response: Response{StatusCode: 200, RawBody: &invalid}},
{Request: testRequest{Method: "GET", Path: "failread"}, Response: Response{StatusCode: 200, RawBody: &invalid}},
}
for _, c := range testClients {
client := c.Setup()
@@ -516,13 +527,13 @@ func TestDoRequest(t *testing.T) {
URL: prefix,
}
response, err := client.doRequest(request)
c.Validate(t, response, err)
c.ValidateRaw(t, response, err)
}
}
func TestDoRequestAccepted(t *testing.T) {
status := api.Status{Status: api.StatusWorking}
expectedBody, _ := runtime.Encode(status)
status := &api.Status{Status: api.StatusWorking}
expectedBody, _ := runtime.DefaultCodec.Encode(status)
fakeHandler := util.FakeHandler{
StatusCode: 202,
ResponseBody: string(expectedBody),
@@ -548,7 +559,7 @@ func TestDoRequestAccepted(t *testing.T) {
t.Errorf("Unexpected kind of error: %#v", err)
return
}
if !reflect.DeepEqual(se.Status, status) {
if !reflect.DeepEqual(&se.Status, status) {
t.Errorf("Unexpected status: %#v", se.Status)
}
if body != nil {
@@ -558,8 +569,8 @@ func TestDoRequestAccepted(t *testing.T) {
}
func TestDoRequestAcceptedSuccess(t *testing.T) {
status := api.Status{Status: api.StatusSuccess}
expectedBody, _ := runtime.Encode(status)
status := &api.Status{Status: api.StatusSuccess}
expectedBody, _ := runtime.DefaultCodec.Encode(status)
fakeHandler := util.FakeHandler{
StatusCode: 202,
ResponseBody: string(expectedBody),
@@ -579,11 +590,11 @@ func TestDoRequestAcceptedSuccess(t *testing.T) {
if err != nil {
t.Errorf("Unexpected error %#v", err)
}
statusOut, err := runtime.Decode(body)
statusOut, err := runtime.DefaultCodec.Decode(body)
if err != nil {
t.Errorf("Unexpected error %#v", err)
}
if !reflect.DeepEqual(&status, statusOut) {
if !reflect.DeepEqual(status, statusOut) {
t.Errorf("Unexpected mis-match. Expected %#v. Saw %#v", status, statusOut)
}
fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil)
@@ -622,5 +633,5 @@ func TestListMinions(t *testing.T) {
Response: Response{StatusCode: 200, Body: &api.MinionList{JSONBase: api.JSONBase{ID: "minion-1"}}},
}
response, err := c.Setup().ListMinions()
c.Validate(t, &response, err)
c.Validate(t, response, err)
}

View File

@@ -42,14 +42,14 @@ type Fake struct {
Watch watch.Interface
}
func (c *Fake) ListPods(selector labels.Selector) (api.PodList, error) {
func (c *Fake) ListPods(selector labels.Selector) (*api.PodList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-pods"})
return *runtime.CopyOrDie(c.Pods).(*api.PodList), nil
return runtime.DefaultScheme.CopyOrDie(&c.Pods).(*api.PodList), nil
}
func (c *Fake) GetPod(name string) (api.Pod, error) {
func (c *Fake) GetPod(name string) (*api.Pod, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-pod", Value: name})
return api.Pod{}, nil
return &api.Pod{}, nil
}
func (c *Fake) DeletePod(name string) error {
@@ -57,34 +57,34 @@ func (c *Fake) DeletePod(name string) error {
return nil
}
func (c *Fake) CreatePod(pod api.Pod) (api.Pod, error) {
func (c *Fake) CreatePod(pod *api.Pod) (*api.Pod, error) {
c.Actions = append(c.Actions, FakeAction{Action: "create-pod"})
return api.Pod{}, nil
return &api.Pod{}, nil
}
func (c *Fake) UpdatePod(pod api.Pod) (api.Pod, error) {
func (c *Fake) UpdatePod(pod *api.Pod) (*api.Pod, error) {
c.Actions = append(c.Actions, FakeAction{Action: "update-pod", Value: pod.ID})
return api.Pod{}, nil
return &api.Pod{}, nil
}
func (c *Fake) ListReplicationControllers(selector labels.Selector) (api.ReplicationControllerList, error) {
func (c *Fake) ListReplicationControllers(selector labels.Selector) (*api.ReplicationControllerList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-controllers"})
return api.ReplicationControllerList{}, nil
return &api.ReplicationControllerList{}, nil
}
func (c *Fake) GetReplicationController(name string) (api.ReplicationController, error) {
func (c *Fake) GetReplicationController(name string) (*api.ReplicationController, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-controller", Value: name})
return *runtime.CopyOrDie(c.Ctrl).(*api.ReplicationController), nil
return runtime.DefaultScheme.CopyOrDie(&c.Ctrl).(*api.ReplicationController), nil
}
func (c *Fake) CreateReplicationController(controller api.ReplicationController) (api.ReplicationController, error) {
func (c *Fake) CreateReplicationController(controller *api.ReplicationController) (*api.ReplicationController, error) {
c.Actions = append(c.Actions, FakeAction{Action: "create-controller", Value: controller})
return api.ReplicationController{}, nil
return &api.ReplicationController{}, nil
}
func (c *Fake) UpdateReplicationController(controller api.ReplicationController) (api.ReplicationController, error) {
func (c *Fake) UpdateReplicationController(controller *api.ReplicationController) (*api.ReplicationController, error) {
c.Actions = append(c.Actions, FakeAction{Action: "update-controller", Value: controller})
return api.ReplicationController{}, nil
return &api.ReplicationController{}, nil
}
func (c *Fake) DeleteReplicationController(controller string) error {
@@ -97,24 +97,24 @@ func (c *Fake) WatchReplicationControllers(label, field labels.Selector, resourc
return c.Watch, nil
}
func (c *Fake) ListServices(selector labels.Selector) (api.ServiceList, error) {
func (c *Fake) ListServices(selector labels.Selector) (*api.ServiceList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-services"})
return c.ServiceList, c.Err
return &c.ServiceList, c.Err
}
func (c *Fake) GetService(name string) (api.Service, error) {
func (c *Fake) GetService(name string) (*api.Service, error) {
c.Actions = append(c.Actions, FakeAction{Action: "get-service", Value: name})
return api.Service{}, nil
return &api.Service{}, nil
}
func (c *Fake) CreateService(service api.Service) (api.Service, error) {
func (c *Fake) CreateService(service *api.Service) (*api.Service, error) {
c.Actions = append(c.Actions, FakeAction{Action: "create-service", Value: service})
return api.Service{}, nil
return &api.Service{}, nil
}
func (c *Fake) UpdateService(service api.Service) (api.Service, error) {
func (c *Fake) UpdateService(service *api.Service) (*api.Service, error) {
c.Actions = append(c.Actions, FakeAction{Action: "update-service", Value: service})
return api.Service{}, nil
return &api.Service{}, nil
}
func (c *Fake) DeleteService(service string) error {
@@ -127,9 +127,9 @@ func (c *Fake) WatchServices(label, field labels.Selector, resourceVersion uint6
return c.Watch, c.Err
}
func (c *Fake) ListEndpoints(selector labels.Selector) (api.EndpointsList, error) {
func (c *Fake) ListEndpoints(selector labels.Selector) (*api.EndpointsList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-endpoints"})
return c.EndpointsList, c.Err
return runtime.DefaultScheme.CopyOrDie(&c.EndpointsList).(*api.EndpointsList), c.Err
}
func (c *Fake) WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) {
@@ -143,7 +143,7 @@ func (c *Fake) ServerVersion() (*version.Info, error) {
return &versionInfo, nil
}
func (c *Fake) ListMinions() (api.MinionList, error) {
func (c *Fake) ListMinions() (*api.MinionList, error) {
c.Actions = append(c.Actions, FakeAction{Action: "list-minions", Value: nil})
return api.MinionList{}, nil
return &api.MinionList{}, nil
}

View File

@@ -187,7 +187,8 @@ func (r *Request) Timeout(d time.Duration) *Request {
// If obj is a string, try to read a file of that name.
// If obj is a []byte, send it directly.
// If obj is an io.Reader, use it directly.
// Otherwise, assume obj is an api type and marshall it correctly.
// If obj is a runtime.Object, marshal it correctly.
// Otherwise, set an error.
func (r *Request) Body(obj interface{}) *Request {
if r.err != nil {
return r
@@ -204,13 +205,15 @@ func (r *Request) Body(obj interface{}) *Request {
r.body = bytes.NewBuffer(t)
case io.Reader:
r.body = t
default:
data, err := runtime.Encode(obj)
case runtime.Object:
data, err := runtime.DefaultCodec.Encode(t)
if err != nil {
r.err = err
return r
}
r.body = bytes.NewBuffer(data)
default:
r.err = fmt.Errorf("Unknown type used for body: %#v", obj)
}
return r
}
@@ -314,19 +317,19 @@ func (r Result) Raw() ([]byte, error) {
}
// Get returns the result as an object.
func (r Result) Get() (interface{}, error) {
func (r Result) Get() (runtime.Object, error) {
if r.err != nil {
return nil, r.err
}
return runtime.Decode(r.body)
return runtime.DefaultCodec.Decode(r.body)
}
// Into stores the result into obj, if possible.
func (r Result) Into(obj interface{}) error {
func (r Result) Into(obj runtime.Object) error {
if r.err != nil {
return r.err
}
return runtime.DecodeInto(r.body, obj)
return runtime.DefaultCodec.DecodeInto(r.body, obj)
}
// Error returns the error executing the request, nil if no error occurred.

View File

@@ -38,7 +38,7 @@ import (
func TestDoRequestNewWay(t *testing.T) {
reqBody := "request body"
expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj)
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(expectedBody),
@@ -71,9 +71,9 @@ func TestDoRequestNewWay(t *testing.T) {
func TestDoRequestNewWayReader(t *testing.T) {
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
reqBodyExpected, _ := runtime.Encode(reqObj)
reqBodyExpected, _ := runtime.DefaultCodec.Encode(reqObj)
expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj)
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(expectedBody),
@@ -108,9 +108,9 @@ func TestDoRequestNewWayReader(t *testing.T) {
func TestDoRequestNewWayObj(t *testing.T) {
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
reqBodyExpected, _ := runtime.Encode(reqObj)
reqBodyExpected, _ := runtime.DefaultCodec.Encode(reqObj)
expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj)
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(expectedBody),
@@ -144,7 +144,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
func TestDoRequestNewWayFile(t *testing.T) {
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
reqBodyExpected, err := runtime.Encode(reqObj)
reqBodyExpected, err := runtime.DefaultCodec.Encode(reqObj)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@@ -160,7 +160,7 @@ func TestDoRequestNewWayFile(t *testing.T) {
}
expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj)
expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(expectedBody),
@@ -285,7 +285,7 @@ func TestSetPollPeriod(t *testing.T) {
}
func TestPolling(t *testing.T) {
objects := []interface{}{
objects := []runtime.Object{
&api.Status{Status: api.StatusWorking, Details: &api.StatusDetails{ID: "1234"}},
&api.Status{Status: api.StatusWorking, Details: &api.StatusDetails{ID: "1234"}},
&api.Status{Status: api.StatusWorking, Details: &api.StatusDetails{ID: "1234"}},
@@ -295,7 +295,7 @@ func TestPolling(t *testing.T) {
callNumber := 0
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data, err := runtime.Encode(objects[callNumber])
data, err := runtime.DefaultCodec.Encode(objects[callNumber])
if err != nil {
t.Errorf("Unexpected encode error")
}
@@ -380,7 +380,7 @@ func checkAuth(t *testing.T, expect AuthInfo, r *http.Request) {
func TestWatch(t *testing.T) {
var table = []struct {
t watch.EventType
obj interface{}
obj runtime.Object
}{
{watch.Added, &api.Pod{JSONBase: api.JSONBase{ID: "first"}}},
{watch.Modified, &api.Pod{JSONBase: api.JSONBase{ID: "second"}}},

View File

@@ -58,7 +58,7 @@ func (r RealPodControl) createReplica(controllerSpec api.ReplicationController)
if labels != nil {
labels["replicationController"] = controllerSpec.ID
}
pod := api.Pod{
pod := &api.Pod{
DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState,
Labels: controllerSpec.DesiredState.PodTemplate.Labels,
}

View File

@@ -85,7 +85,7 @@ func newReplicationController(replicas int) api.ReplicationController {
}
}
func newPodList(count int) api.PodList {
func newPodList(count int) *api.PodList {
pods := []api.Pod{}
for i := 0; i < count; i++ {
pods = append(pods, api.Pod{
@@ -94,7 +94,7 @@ func newPodList(count int) api.PodList {
},
})
}
return api.PodList{
return &api.PodList{
Items: pods,
}
}
@@ -109,7 +109,7 @@ func validateSyncReplication(t *testing.T, fakePodControl *FakePodControl, expec
}
func TestSyncReplicationControllerDoesNothing(t *testing.T) {
body, _ := runtime.Encode(newPodList(2))
body, _ := runtime.DefaultCodec.Encode(newPodList(2))
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(body),
@@ -129,7 +129,7 @@ func TestSyncReplicationControllerDoesNothing(t *testing.T) {
}
func TestSyncReplicationControllerDeletes(t *testing.T) {
body, _ := runtime.Encode(newPodList(2))
body, _ := runtime.DefaultCodec.Encode(newPodList(2))
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(body),
@@ -149,7 +149,7 @@ func TestSyncReplicationControllerDeletes(t *testing.T) {
}
func TestSyncReplicationControllerCreates(t *testing.T) {
body, _ := runtime.Encode(newPodList(0))
body, _ := runtime.DefaultCodec.Encode(newPodList(0))
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(body),
@@ -169,7 +169,7 @@ func TestSyncReplicationControllerCreates(t *testing.T) {
}
func TestCreateReplica(t *testing.T) {
body, _ := runtime.Encode(api.Pod{})
body, _ := runtime.DefaultCodec.Encode(&api.Pod{})
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(body),
@@ -292,7 +292,7 @@ func TestSyncronize(t *testing.T) {
}
fakeControllerHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: runtime.EncodeOrDie(&api.ReplicationControllerList{
ResponseBody: runtime.DefaultScheme.EncodeOrDie(&api.ReplicationControllerList{
Items: []api.ReplicationController{
controllerSpec1,
controllerSpec2,

View File

@@ -37,7 +37,7 @@ type Converter struct {
// do the conversion.
funcs map[typePair]reflect.Value
// If true, print helpful debugging info. Quite verbose.
// If non-nil, will be called to print helpful debugging info. Quite verbose.
Debug DebugLogger
}
@@ -48,29 +48,43 @@ func NewConverter() *Converter {
}
}
// Scope is passed to conversion funcs to allow them to continue an ongoing conversion.
// If multiple converters exist in the system, Scope will allow you to use the correct one
// from a conversion function--that is, the one your conversion function was called by.
type Scope interface {
// Call Convert to convert sub-objects. Note that if you call it with your own exact
// parameters, you'll run out of stack space before anything useful happens.
Convert(src, dest interface{}, flags FieldMatchingFlags) error
}
// Register registers a conversion func with the Converter. conversionFunc must take
// two parameters, the input and output type. It must take a pointer to each. It must
// return an error.
// three parameters: a pointer to the input type, a pointer to the output type, and
// a conversion.Scope (which should be used if recursive conversion calls are desired).
// It must return an error.
//
// Example:
// c.Register(func(in *Pod, out *v1beta1.Pod) error { ... return nil })
// c.Register(func(in *Pod, out *v1beta1.Pod, s Scope) error { ... return nil })
func (c *Converter) Register(conversionFunc interface{}) error {
fv := reflect.ValueOf(conversionFunc)
ft := fv.Type()
if ft.Kind() != reflect.Func {
return fmt.Errorf("expected func, got: %v", ft)
}
if ft.NumIn() != 2 {
return fmt.Errorf("expected two in params, got: %v", ft)
if ft.NumIn() != 3 {
return fmt.Errorf("expected three 'in' params, got: %v", ft)
}
if ft.NumOut() != 1 {
return fmt.Errorf("expected one out param, got: %v", ft)
return fmt.Errorf("expected one 'out' param, got: %v", ft)
}
if ft.In(0).Kind() != reflect.Ptr {
return fmt.Errorf("expected pointer arg for in param 0, got: %v", ft)
return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft)
}
if ft.In(1).Kind() != reflect.Ptr {
return fmt.Errorf("expected pointer arg for in param 1, got: %v", ft)
return fmt.Errorf("expected pointer arg for 'in' param 1, got: %v", ft)
}
scopeType := Scope(c)
if e, a := reflect.TypeOf(&scopeType).Elem(), ft.In(2); e != a {
return fmt.Errorf("expected '%v' arg for 'in' param 2, got '%v' (%v)", e, a, ft)
}
var forErrorType error
// This convolution is necessary, otherwise TypeOf picks up on the fact
@@ -138,7 +152,8 @@ func (c *Converter) convert(sv, dv reflect.Value, flags FieldMatchingFlags) erro
if c.Debug != nil {
c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt)
}
ret := fv.Call([]reflect.Value{sv.Addr(), dv.Addr()})[0].Interface()
args := []reflect.Value{sv.Addr(), dv.Addr(), reflect.ValueOf(Scope(c))}
ret := fv.Call(args)[0].Interface()
// This convolution is necssary because nil interfaces won't convert
// to errors.
if ret == nil {

View File

@@ -27,28 +27,30 @@ import (
func TestConverter_CallsRegisteredFunctions(t *testing.T) {
type A struct {
Foo string
Baz int
}
type B struct {
Bar string
Baz int
}
type C struct{}
c := NewConverter()
err := c.Register(func(in *A, out *B) error {
err := c.Register(func(in *A, out *B, s Scope) error {
out.Bar = in.Foo
return nil
return s.Convert(&in.Baz, &out.Baz, 0)
})
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = c.Register(func(in *B, out *A) error {
err = c.Register(func(in *B, out *A, s Scope) error {
out.Foo = in.Bar
return nil
return s.Convert(&in.Baz, &out.Baz, 0)
})
if err != nil {
t.Fatalf("unexpected error %v", err)
}
x := A{"hello, intrepid test reader!"}
x := A{"hello, intrepid test reader!", 3}
y := B{}
err = c.Convert(&x, &y, 0)
@@ -58,8 +60,11 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
if e, a := x.Foo, y.Bar; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := x.Baz, y.Baz; e != a {
t.Errorf("expected %v, got %v", e, a)
}
z := B{"all your test are belong to us"}
z := B{"all your test are belong to us", 42}
w := A{}
err = c.Convert(&z, &w, 0)
@@ -69,8 +74,11 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
if e, a := z.Bar, w.Foo; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := z.Baz, w.Baz; e != a {
t.Errorf("expected %v, got %v", e, a)
}
err = c.Register(func(in *A, out *C) error {
err = c.Register(func(in *A, out *C, s Scope) error {
return fmt.Errorf("C can't store an A, silly")
})
if err != nil {
@@ -85,7 +93,7 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
func TestConverter_fuzz(t *testing.T) {
newAnonType := func() interface{} {
return reflect.New(reflect.TypeOf(externalTypeReturn())).Interface()
return reflect.New(reflect.TypeOf(externalTypeReturn()).Elem()).Interface()
}
// Use the same types from the scheme test.
table := []struct {

View File

@@ -85,8 +85,8 @@ func NewScheme() *Scheme {
// AddKnownTypes registers all types passed in 'types' as being members of version 'version.
// Encode() will refuse objects unless their type has been registered with AddKnownTypes.
// All objects passed to types should be structs, not pointers to structs. The name that go
// reports for the struct becomes the "kind" field when encoding.
// All objects passed to types should be pointers to structs. The name that go reports for
// the struct becomes the "kind" field when encoding.
func (s *Scheme) AddKnownTypes(version string, types ...interface{}) {
knownTypes, found := s.versionMap[version]
if !found {
@@ -95,8 +95,12 @@ func (s *Scheme) AddKnownTypes(version string, types ...interface{}) {
}
for _, obj := range types {
t := reflect.TypeOf(obj)
if t.Kind() != reflect.Ptr {
panic("All types must be pointers to structs.")
}
t = t.Elem()
if t.Kind() != reflect.Struct {
panic("All types must be structs.")
panic("All types must be pointers to structs.")
}
knownTypes[t.Name()] = t
s.typeToVersion[t] = version

View File

@@ -90,7 +90,7 @@ func externalTypeReturn() interface{} {
O *TestType2 `yaml:"O,omitempty" json:"O,omitempty"`
P []TestType2 `yaml:"Q,omitempty" json:"Q,omitempty"`
}
return TestType1{}
return &TestType1{}
}
type ExternalInternalSame struct {
@@ -124,8 +124,8 @@ var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
// Returns a new Scheme set up with the test objects.
func GetTestScheme() *Scheme {
s := NewScheme()
s.AddKnownTypes("", TestType1{}, ExternalInternalSame{})
s.AddKnownTypes("v1", externalTypeReturn(), ExternalInternalSame{})
s.AddKnownTypes("", &TestType1{}, &ExternalInternalSame{})
s.AddKnownTypes("v1", externalTypeReturn(), &ExternalInternalSame{})
s.ExternalVersion = "v1"
s.InternalVersion = ""
s.MetaInsertionFactory = testMetaInsertionFactory{}

View File

@@ -27,6 +27,15 @@ import (
"github.com/golang/glog"
)
// Master is used to announce the current elected master.
type Master string
// IsAnAPIObject is used solely so we can work with the watch package.
// TODO: Either fix watch so this isn't necessary, or make this a real API Object.
// TODO: when it becomes clear how this package will be used, move these declarations to
// to the proper place.
func (Master) IsAnAPIObject() {}
// NewEtcdMasterElector returns an implementation of election.MasterElector backed by etcd.
func NewEtcdMasterElector(h tools.EtcdGetSet) MasterElector {
return &etcdMasterElector{etcd: h}
@@ -58,7 +67,7 @@ func (e *etcdMasterElector) run(path, id string) {
case m := <-masters:
e.events <- watch.Event{
Type: watch.Modified,
Object: m,
Object: Master(m),
}
case e := <-errors:
glog.Errorf("error in election: %v", e)

View File

@@ -31,7 +31,7 @@ func TestEtcdMasterOther(t *testing.T) {
master := NewEtcdMasterElector(etcd)
w := master.Elect(path, "bar")
result := <-w.ResultChan()
if result.Type != watch.Modified || result.Object.(string) != "baz" {
if result.Type != watch.Modified || result.Object.(Master) != "baz" {
t.Errorf("unexpected event: %#v", result)
}
w.Stop()
@@ -52,7 +52,7 @@ func TestEtcdMasterNoOther(t *testing.T) {
master := NewEtcdMasterElector(e)
w := master.Elect(path, "bar")
result := <-w.ResultChan()
if result.Type != watch.Modified || result.Object.(string) != "bar" {
if result.Type != watch.Modified || result.Object.(Master) != "bar" {
t.Errorf("unexpected event: %#v", result)
}
w.Stop()
@@ -91,7 +91,7 @@ func TestEtcdMasterNoOtherThenConflict(t *testing.T) {
master := NewEtcdMasterElector(e)
w := master.Elect(path, "bar")
result := <-w.ResultChan()
if result.Type != watch.Modified || result.Object.(string) != "bar" {
if result.Type != watch.Modified || result.Object.(Master) != "bar" {
t.Errorf("unexpected event: %#v", result)
}
w.Stop()

View File

@@ -174,7 +174,7 @@ func portsFromString(spec string) []api.Port {
// RunController creates a new replication controller named 'name' which creates 'replicas' pods running 'image'.
func RunController(image, name string, replicas int, client client.Interface, portSpec string, servicePort int) error {
controller := api.ReplicationController{
controller := &api.ReplicationController{
JSONBase: api.JSONBase{
ID: name,
},
@@ -227,8 +227,8 @@ func RunController(image, name string, replicas int, client client.Interface, po
return nil
}
func createService(name string, port int, client client.Interface) (api.Service, error) {
svc := api.Service{
func createService(name string, port int, client client.Interface) (*api.Service, error) {
svc := &api.Service{
JSONBase: api.JSONBase{ID: name},
Port: port,
Labels: map[string]string{

View File

@@ -46,7 +46,7 @@ func TestUpdateWithPods(t *testing.T) {
}
Update("foo", &fakeClient, 0, "")
if len(fakeClient.Actions) != 5 {
t.Errorf("Unexpected action list %#v", fakeClient.Actions)
t.Fatalf("Unexpected action list %#v", fakeClient.Actions)
}
validateAction(client.FakeAction{Action: "get-controller", Value: "foo"}, fakeClient.Actions[0], t)
validateAction(client.FakeAction{Action: "list-pods"}, fakeClient.Actions[1], t)
@@ -94,7 +94,7 @@ func TestUpdateWithNewImage(t *testing.T) {
}
validateAction(client.FakeAction{Action: "get-controller", Value: "foo"}, fakeClient.Actions[0], t)
newCtrl := *runtime.CopyOrDie(fakeClient.Ctrl).(*api.ReplicationController)
newCtrl := runtime.DefaultScheme.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)
@@ -114,7 +114,7 @@ func TestRunController(t *testing.T) {
if len(fakeClient.Actions) != 1 || fakeClient.Actions[0].Action != "create-controller" {
t.Errorf("Unexpected actions: %#v", fakeClient.Actions)
}
controller := fakeClient.Actions[0].Value.(api.ReplicationController)
controller := fakeClient.Actions[0].Value.(*api.ReplicationController)
if controller.ID != name ||
controller.DesiredState.Replicas != replicas ||
controller.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image != image {
@@ -133,7 +133,7 @@ func TestRunControllerWithService(t *testing.T) {
fakeClient.Actions[1].Action != "create-service" {
t.Errorf("Unexpected actions: %#v", fakeClient.Actions)
}
controller := fakeClient.Actions[0].Value.(api.ReplicationController)
controller := fakeClient.Actions[0].Value.(*api.ReplicationController)
if controller.ID != name ||
controller.DesiredState.Replicas != replicas ||
controller.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image != image {
@@ -152,7 +152,7 @@ func TestStopController(t *testing.T) {
fakeClient.Actions[0].Value.(string) != name {
t.Errorf("Unexpected Action: %#v", fakeClient.Actions[0])
}
controller := fakeClient.Actions[1].Value.(api.ReplicationController)
controller := fakeClient.Actions[1].Value.(*api.ReplicationController)
if fakeClient.Actions[1].Action != "update-controller" ||
controller.DesiredState.Replicas != 0 {
t.Errorf("Unexpected Action: %#v", fakeClient.Actions[1])
@@ -171,7 +171,7 @@ func TestResizeController(t *testing.T) {
fakeClient.Actions[0].Value.(string) != name {
t.Errorf("Unexpected Action: %#v", fakeClient.Actions[0])
}
controller := fakeClient.Actions[1].Value.(api.ReplicationController)
controller := fakeClient.Actions[1].Value.(*api.ReplicationController)
if fakeClient.Actions[1].Action != "update-controller" ||
controller.DesiredState.Replicas != 17 {
t.Errorf("Unexpected Action: %#v", fakeClient.Actions[1])

View File

@@ -27,10 +27,11 @@ type Parser struct {
storageToType map[string]reflect.Type
}
func NewParser(objectMap map[string]interface{}) *Parser {
// NewParser creates a new parser.
func NewParser(objectMap map[string]runtime.Object) *Parser {
typeMap := make(map[string]reflect.Type)
for name, obj := range objectMap {
typeMap[name] = reflect.TypeOf(obj)
typeMap[name] = reflect.TypeOf(obj).Elem()
}
return &Parser{typeMap}
}
@@ -43,12 +44,12 @@ func (p *Parser) ToWireFormat(data []byte, storage string) ([]byte, error) {
return nil, fmt.Errorf("unknown storage type: %v", storage)
}
obj := reflect.New(prototypeType).Interface()
err := runtime.DecodeInto(data, obj)
obj := reflect.New(prototypeType).Interface().(runtime.Object)
err := runtime.DefaultCodec.DecodeInto(data, obj)
if err != nil {
return nil, err
}
return runtime.Encode(obj)
return runtime.DefaultCodec.Encode(obj)
}
func (p *Parser) SupportedWireStorage() []string {

View File

@@ -25,15 +25,15 @@ import (
)
func TestParseBadStorage(t *testing.T) {
p := NewParser(map[string]interface{}{})
p := NewParser(map[string]runtime.Object{})
_, err := p.ToWireFormat([]byte("{}"), "badstorage")
if err == nil {
t.Errorf("Expected error, received none")
}
}
func DoParseTest(t *testing.T, storage string, obj interface{}, p *Parser) {
jsonData, _ := runtime.Encode(obj)
func DoParseTest(t *testing.T, storage string, obj runtime.Object, p *Parser) {
jsonData, _ := runtime.DefaultCodec.Encode(obj)
yamlData, _ := yaml.Marshal(obj)
t.Logf("Intermediate yaml:\n%v\n", string(yamlData))
t.Logf("Intermediate json:\n%v\n", string(jsonData))
@@ -56,14 +56,14 @@ func DoParseTest(t *testing.T, storage string, obj interface{}, p *Parser) {
}
}
var testParser = NewParser(map[string]interface{}{
"pods": api.Pod{},
"services": api.Service{},
"replicationControllers": api.ReplicationController{},
var testParser = NewParser(map[string]runtime.Object{
"pods": &api.Pod{},
"services": &api.Service{},
"replicationControllers": &api.ReplicationController{},
})
func TestParsePod(t *testing.T) {
DoParseTest(t, "pods", api.Pod{
DoParseTest(t, "pods", &api.Pod{
JSONBase: api.JSONBase{APIVersion: "v1beta1", ID: "test pod", Kind: "Pod"},
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
@@ -80,7 +80,7 @@ func TestParsePod(t *testing.T) {
}
func TestParseService(t *testing.T) {
DoParseTest(t, "services", api.Service{
DoParseTest(t, "services", &api.Service{
JSONBase: api.JSONBase{APIVersion: "v1beta1", ID: "my service", Kind: "Service"},
Port: 8080,
Labels: map[string]string{
@@ -93,7 +93,7 @@ func TestParseService(t *testing.T) {
}
func TestParseController(t *testing.T) {
DoParseTest(t, "replicationControllers", api.ReplicationController{
DoParseTest(t, "replicationControllers", &api.ReplicationController{
JSONBase: api.JSONBase{APIVersion: "v1beta1", ID: "my controller", Kind: "ReplicationController"},
DesiredState: api.ReplicationControllerState{
Replicas: 9001,
@@ -119,13 +119,15 @@ type TestParseType struct {
Data string `json:"data" yaml:"data"`
}
func (*TestParseType) IsAnAPIObject() {}
func TestParseCustomType(t *testing.T) {
runtime.AddKnownTypes("", TestParseType{})
runtime.AddKnownTypes("v1beta1", TestParseType{})
parser := NewParser(map[string]interface{}{
"custom": TestParseType{},
runtime.DefaultScheme.AddKnownTypes("", &TestParseType{})
runtime.DefaultScheme.AddKnownTypes("v1beta1", &TestParseType{})
parser := NewParser(map[string]runtime.Object{
"custom": &TestParseType{},
})
DoParseTest(t, "custom", TestParseType{
DoParseTest(t, "custom", &TestParseType{
JSONBase: api.JSONBase{APIVersion: "", ID: "my custom object", Kind: "TestParseType"},
Data: "test data",
}, parser)

View File

@@ -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.Encode(api.Status{
data, _ := runtime.DefaultCodec.Encode(&api.Status{
Status: api.StatusFailure,
Message: fmt.Sprintf("internal error: %#v", err),
})

View File

@@ -36,7 +36,7 @@ import (
type ResourcePrinter interface {
// Print receives an arbitrary JSON body, formats it and prints it to a writer.
Print([]byte, io.Writer) error
PrintObj(interface{}, io.Writer) error
PrintObj(runtime.Object, io.Writer) error
}
// IdentityPrinter is an implementation of ResourcePrinter which simply copies the body out to the output stream.
@@ -49,8 +49,8 @@ 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 interface{}, output io.Writer) error {
data, err := runtime.Encode(obj)
func (i *IdentityPrinter) PrintObj(obj runtime.Object, output io.Writer) error {
data, err := runtime.DefaultCodec.Encode(obj)
if err != nil {
return err
}
@@ -75,7 +75,7 @@ func (y *YAMLPrinter) Print(data []byte, w io.Writer) error {
}
// PrintObj prints the data as YAML.
func (y *YAMLPrinter) PrintObj(obj interface{}, w io.Writer) error {
func (y *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
output, err := yaml.Marshal(obj)
if err != nil {
return err
@@ -251,7 +251,7 @@ func printStatus(status *api.Status, w io.Writer) error {
// Print parses the data as JSON, then prints the parsed data in a human-friendly
// format according to the type of the data.
func (h *HumanReadablePrinter) Print(data []byte, output io.Writer) error {
var mapObj map[string]interface{}
var mapObj map[string]runtime.Object
if err := json.Unmarshal([]byte(data), &mapObj); err != nil {
return err
}
@@ -260,7 +260,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.Decode(data)
obj, err := runtime.DefaultCodec.Decode(data)
if err != nil {
return err
}
@@ -268,7 +268,7 @@ func (h *HumanReadablePrinter) Print(data []byte, output io.Writer) error {
}
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
func (h *HumanReadablePrinter) PrintObj(obj interface{}, output io.Writer) error {
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0)
defer w.Flush()
if handler := h.handlerMap[reflect.TypeOf(obj)]; handler != nil {
@@ -292,7 +292,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.Decode(data)
obj, err := runtime.DefaultCodec.Decode(data)
if err != nil {
return err
}
@@ -300,6 +300,6 @@ func (t *TemplatePrinter) Print(data []byte, w io.Writer) error {
}
// PrintObj formats the obj with the Go Template.
func (t *TemplatePrinter) PrintObj(obj interface{}, w io.Writer) error {
func (t *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
return t.Template.Execute(w, obj)
}

View File

@@ -67,7 +67,7 @@ func TestYAMLPrinterPrint(t *testing.T) {
t.Errorf("Test data and unmarshaled data are not equal: %#v vs %#v", poutput, testData)
}
obj := api.Pod{
obj := &api.Pod{
JSONBase: api.JSONBase{ID: "foo"},
}
buf.Reset()
@@ -77,8 +77,8 @@ func TestYAMLPrinterPrint(t *testing.T) {
if err != nil {
t.Errorf("Unexpeted error: %#v", err)
}
if !reflect.DeepEqual(obj, objOut) {
t.Errorf("Unexpected inequality: %#v vs %#v", obj, objOut)
if !reflect.DeepEqual(obj, &objOut) {
t.Errorf("Unexpected inequality: %#v vs %#v", obj, &objOut)
}
}
@@ -91,16 +91,16 @@ func TestIdentityPrinter(t *testing.T) {
t.Errorf("Bytes are not equal: %s vs %s", str, buff.String())
}
obj := api.Pod{
obj := &api.Pod{
JSONBase: api.JSONBase{ID: "foo"},
}
buff.Reset()
printer.PrintObj(obj, buff)
objOut, err := runtime.Decode([]byte(buff.String()))
objOut, err := runtime.DefaultCodec.Decode([]byte(buff.String()))
if err != nil {
t.Errorf("Unexpeted error: %#v", err)
}
if !reflect.DeepEqual(&obj, objOut) {
if !reflect.DeepEqual(obj, objOut) {
t.Errorf("Unexpected inequality: %#v vs %#v", obj, objOut)
}
}
@@ -109,8 +109,12 @@ type TestPrintType struct {
Data string
}
func (*TestPrintType) IsAnAPIObject() {}
type TestUnknownType struct{}
func (*TestUnknownType) IsAnAPIObject() {}
func PrintCustomType(obj *TestPrintType, w io.Writer) error {
_, err := fmt.Fprintf(w, "%s", obj.Data)
return err

View File

@@ -47,8 +47,8 @@ type SourceEtcd struct {
func NewSourceEtcd(key string, client tools.EtcdClient, updates chan<- interface{}) *SourceEtcd {
helper := tools.EtcdHelper{
client,
runtime.Codec,
runtime.ResourceVersioner,
runtime.DefaultCodec,
runtime.DefaultResourceVersioner,
}
source := &SourceEtcd{
key: key,

View File

@@ -131,10 +131,10 @@ func (m *Master) init(cloud cloudprovider.Interface, podInfoGetter client.PodInf
}
// API_v1beta1 returns the resources and codec for API version v1beta1.
func (m *Master) API_v1beta1() (map[string]apiserver.RESTStorage, apiserver.Codec) {
func (m *Master) API_v1beta1() (map[string]apiserver.RESTStorage, runtime.Codec) {
storage := make(map[string]apiserver.RESTStorage)
for k, v := range m.storage {
storage[k] = v
}
return storage, runtime.Codec
return storage, runtime.DefaultCodec
}

View File

@@ -29,8 +29,8 @@ import (
// Watcher is the interface needed to receive changes to services and endpoints.
type Watcher interface {
ListServices(label labels.Selector) (api.ServiceList, error)
ListEndpoints(label labels.Selector) (api.EndpointsList, error)
ListServices(label labels.Selector) (*api.ServiceList, error)
ListEndpoints(label labels.Selector) (*api.EndpointsList, error)
WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
}

View File

@@ -133,7 +133,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.DecodeInto([]byte(node.Value), &svc)
err = runtime.DefaultCodec.DecodeInto([]byte(node.Value), &svc)
if err != nil {
glog.Errorf("Failed to load Service: %s (%#v)", node.Value, err)
continue
@@ -166,7 +166,7 @@ func (s ConfigSourceEtcd) GetEndpoints(service string) (api.Endpoints, error) {
}
// Parse all the endpoint specifications in this value.
var e api.Endpoints
err = runtime.DecodeInto([]byte(response.Node.Value), &e)
err = runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &e)
return e, err
}
@@ -176,7 +176,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.DecodeInto([]byte(response.Node.Value), &svc)
err := runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &svc)
if err != nil {
return nil, err
}
@@ -230,7 +230,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.DecodeInto([]byte(response.Node.Value), &endpoints)
err := runtime.DefaultCodec.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

View File

@@ -23,6 +23,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
// BindingStorage implements the RESTStorage interface. When bindings are written, it
@@ -40,32 +41,32 @@ func NewBindingStorage(bindingRegistry Registry) *BindingStorage {
}
// List returns an error because bindings are write-only objects.
func (*BindingStorage) List(selector labels.Selector) (interface{}, error) {
func (*BindingStorage) List(selector labels.Selector) (runtime.Object, error) {
return nil, errors.NewNotFound("binding", "list")
}
// Get returns an error because bindings are write-only objects.
func (*BindingStorage) Get(id string) (interface{}, error) {
func (*BindingStorage) Get(id string) (runtime.Object, error) {
return nil, errors.NewNotFound("binding", id)
}
// Delete returns an error because bindings are write-only objects.
func (*BindingStorage) Delete(id string) (<-chan interface{}, error) {
func (*BindingStorage) Delete(id string) (<-chan runtime.Object, error) {
return nil, errors.NewNotFound("binding", id)
}
// New returns a new binding object fit for having data unmarshalled into it.
func (*BindingStorage) New() interface{} {
func (*BindingStorage) New() runtime.Object {
return &api.Binding{}
}
// Create attempts to make the assignment indicated by the binding it recieves.
func (b *BindingStorage) Create(obj interface{}) (<-chan interface{}, error) {
func (b *BindingStorage) Create(obj runtime.Object) (<-chan runtime.Object, error) {
binding, ok := obj.(*api.Binding)
if !ok {
return nil, fmt.Errorf("incorrect type: %#v", obj)
}
return apiserver.MakeAsync(func() (interface{}, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
if err := b.registry.ApplyBinding(binding); err != nil {
return nil, err
}
@@ -74,6 +75,6 @@ func (b *BindingStorage) Create(obj interface{}) (<-chan interface{}, error) {
}
// Update returns an error-- this object may not be updated.
func (b *BindingStorage) Update(obj interface{}) (<-chan interface{}, error) {
func (b *BindingStorage) Update(obj runtime.Object) (<-chan runtime.Object, error) {
return nil, fmt.Errorf("Bindings may not be changed.")
}

View File

@@ -38,12 +38,12 @@ func TestNewBindingStorage(t *testing.T) {
PodID: "foo",
Host: "bar",
}
body, err := runtime.Encode(binding)
body, err := runtime.DefaultCodec.Encode(binding)
if err != nil {
t.Fatalf("Unexpected encode error %v", err)
}
obj := b.New()
err = runtime.DecodeInto(body, obj)
err = runtime.DefaultCodec.DecodeInto(body, obj)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}

View File

@@ -26,7 +26,7 @@ type Registry interface {
ListControllers() (*api.ReplicationControllerList, error)
WatchControllers(resourceVersion uint64) (watch.Interface, error)
GetController(controllerID string) (*api.ReplicationController, error)
CreateController(controller api.ReplicationController) error
UpdateController(controller api.ReplicationController) error
CreateController(controller *api.ReplicationController) error
UpdateController(controller *api.ReplicationController) error
DeleteController(controllerID string) error
}

View File

@@ -26,6 +26,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
@@ -51,7 +52,7 @@ func NewRegistryStorage(registry Registry, podRegistry pod.Registry) apiserver.R
}
// Create registers the given ReplicationController.
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Create(obj runtime.Object) (<-chan runtime.Object, error) {
controller, ok := obj.(*api.ReplicationController)
if !ok {
return nil, fmt.Errorf("not a replication controller: %#v", obj)
@@ -67,8 +68,8 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
controller.CreationTimestamp = util.Now()
return apiserver.MakeAsync(func() (interface{}, error) {
err := rs.registry.CreateController(*controller)
return apiserver.MakeAsync(func() (runtime.Object, error) {
err := rs.registry.CreateController(controller)
if err != nil {
return nil, err
}
@@ -77,14 +78,14 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
}
// Delete asynchronously deletes the ReplicationController specified by its id.
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
return apiserver.MakeAsync(func() (interface{}, error) {
func (rs *RegistryStorage) Delete(id string) (<-chan runtime.Object, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteController(id)
}), nil
}
// Get obtains the ReplicationController specified by its id.
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
func (rs *RegistryStorage) Get(id string) (runtime.Object, error) {
controller, err := rs.registry.GetController(id)
if err != nil {
return nil, err
@@ -93,7 +94,7 @@ func (rs *RegistryStorage) Get(id string) (interface{}, error) {
}
// List obtains a list of ReplicationControllers that match selector.
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
func (rs *RegistryStorage) List(selector labels.Selector) (runtime.Object, error) {
controllers, err := rs.registry.ListControllers()
if err != nil {
return nil, err
@@ -109,13 +110,13 @@ func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
}
// New creates a new ReplicationController for use with Create and Update.
func (rs RegistryStorage) New() interface{} {
func (rs RegistryStorage) New() runtime.Object {
return &api.ReplicationController{}
}
// Update replaces a given ReplicationController instance with an existing
// instance in storage.registry.
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Update(obj runtime.Object) (<-chan runtime.Object, error) {
controller, ok := obj.(*api.ReplicationController)
if !ok {
return nil, fmt.Errorf("not a replication controller: %#v", obj)
@@ -123,8 +124,8 @@ func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
if errs := validation.ValidateReplicationController(controller); len(errs) > 0 {
return nil, errors.NewInvalid("replicationController", controller.ID, errs)
}
return apiserver.MakeAsync(func() (interface{}, error) {
err := rs.registry.UpdateController(*controller)
return apiserver.MakeAsync(func() (runtime.Object, error) {
err := rs.registry.UpdateController(controller)
if err != nil {
return nil, err
}
@@ -148,7 +149,7 @@ func (rs *RegistryStorage) Watch(label, field labels.Selector, resourceVersion u
}), nil
}
func (rs *RegistryStorage) waitForController(ctrl api.ReplicationController) (interface{}, error) {
func (rs *RegistryStorage) waitForController(ctrl *api.ReplicationController) (runtime.Object, error) {
for {
pods, err := rs.podRegistry.ListPods(labels.Set(ctrl.DesiredState.ReplicaSelector).AsSelector())
if err != nil {

View File

@@ -112,13 +112,13 @@ func TestControllerDecode(t *testing.T) {
ID: "foo",
},
}
body, err := runtime.Encode(controller)
body, err := runtime.DefaultCodec.Encode(controller)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
controllerOut := storage.New()
if err := runtime.DecodeInto(body, controllerOut); err != nil {
if err := runtime.DefaultCodec.DecodeInto(body, controllerOut); err != nil {
t.Errorf("unexpected error: %v", err)
}

View File

@@ -27,5 +27,5 @@ type Registry interface {
ListEndpoints() (*api.EndpointsList, error)
GetEndpoints(name string) (*api.Endpoints, error)
WatchEndpoints(labels, fields labels.Selector, resourceVersion uint64) (watch.Interface, error)
UpdateEndpoints(e api.Endpoints) error
UpdateEndpoints(e *api.Endpoints) error
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
@@ -38,12 +39,12 @@ func NewStorage(registry Registry) apiserver.RESTStorage {
}
// Get satisfies the RESTStorage interface.
func (rs *Storage) Get(id string) (interface{}, error) {
func (rs *Storage) Get(id string) (runtime.Object, error) {
return rs.registry.GetEndpoints(id)
}
// List satisfies the RESTStorage interface.
func (rs *Storage) List(selector labels.Selector) (interface{}, error) {
func (rs *Storage) List(selector labels.Selector) (runtime.Object, error) {
if !selector.Empty() {
return nil, errors.New("label selectors are not supported on endpoints")
}
@@ -57,21 +58,21 @@ func (rs *Storage) Watch(label, field labels.Selector, resourceVersion uint64) (
}
// Create satisfies the RESTStorage interface but is unimplemented.
func (rs *Storage) Create(obj interface{}) (<-chan interface{}, error) {
func (rs *Storage) Create(obj runtime.Object) (<-chan runtime.Object, error) {
return nil, errors.New("unimplemented")
}
// Update satisfies the RESTStorage interface but is unimplemented.
func (rs *Storage) Update(obj interface{}) (<-chan interface{}, error) {
func (rs *Storage) Update(obj runtime.Object) (<-chan runtime.Object, error) {
return nil, errors.New("unimplemented")
}
// Delete satisfies the RESTStorage interface but is unimplemented.
func (rs *Storage) Delete(id string) (<-chan interface{}, error) {
func (rs *Storage) Delete(id string) (<-chan runtime.Object, error) {
return nil, errors.New("unimplemented")
}
// New implements the RESTStorage interface.
func (rs Storage) New() interface{} {
func (rs Storage) New() runtime.Object {
return &api.Endpoints{}
}

View File

@@ -45,8 +45,8 @@ func NewRegistry(client tools.EtcdClient) *Registry {
registry := &Registry{
EtcdHelper: tools.EtcdHelper{
client,
runtime.Codec,
runtime.ResourceVersioner,
runtime.DefaultCodec,
runtime.DefaultResourceVersioner,
},
}
registry.manifestFactory = &BasicManifestFactory{
@@ -82,7 +82,7 @@ func (r *Registry) ListPods(selector labels.Selector) (*api.PodList, error) {
// WatchPods begins watching for new, changed, or deleted pods.
func (r *Registry) WatchPods(resourceVersion uint64, filter func(*api.Pod) bool) (watch.Interface, error) {
return r.WatchList("/registry/pods", resourceVersion, func(obj interface{}) bool {
return r.WatchList("/registry/pods", resourceVersion, func(obj runtime.Object) bool {
pod, ok := obj.(*api.Pod)
if !ok {
glog.Errorf("Unexpected object during pod watch: %#v", obj)
@@ -110,14 +110,14 @@ func makeContainerKey(machine string) string {
}
// CreatePod creates a pod based on a specification.
func (r *Registry) CreatePod(pod api.Pod) error {
func (r *Registry) CreatePod(pod *api.Pod) error {
// Set current status to "Waiting".
pod.CurrentState.Status = api.PodWaiting
pod.CurrentState.Host = ""
// DesiredState.Host == "" is a signal to the scheduler that this pod needs scheduling.
pod.DesiredState.Status = api.PodRunning
pod.DesiredState.Host = ""
return r.CreateObj(makePodKey(pod.ID), &pod)
return r.CreateObj(makePodKey(pod.ID), pod)
}
// ApplyBinding implements binding's registry
@@ -129,7 +129,7 @@ func (r *Registry) ApplyBinding(binding *api.Binding) error {
// Returns the current state of the pod, or an error.
func (r *Registry) setPodHostTo(podID, oldMachine, machine string) (finalPod *api.Pod, err error) {
podKey := makePodKey(podID)
err = r.AtomicUpdate(podKey, &api.Pod{}, func(obj interface{}) (interface{}, error) {
err = r.AtomicUpdate(podKey, &api.Pod{}, func(obj runtime.Object) (runtime.Object, error) {
pod, ok := obj.(*api.Pod)
if !ok {
return nil, fmt.Errorf("unexpected object: %#v", obj)
@@ -156,13 +156,13 @@ func (r *Registry) assignPod(podID string, machine string) error {
return err
}
contKey := makeContainerKey(machine)
err = r.AtomicUpdate(contKey, &api.ContainerManifestList{}, func(in interface{}) (interface{}, error) {
err = r.AtomicUpdate(contKey, &api.ContainerManifestList{}, func(in runtime.Object) (runtime.Object, error) {
manifests := *in.(*api.ContainerManifestList)
manifests.Items = append(manifests.Items, manifest)
if !constraint.Allowed(manifests.Items) {
return nil, fmt.Errorf("The assignment would cause a constraint violation")
}
return manifests, nil
return &manifests, nil
})
if err != nil {
// Put the pod's host back the way it was. This is a terrible hack that
@@ -174,7 +174,7 @@ func (r *Registry) assignPod(podID string, machine string) error {
return err
}
func (r *Registry) UpdatePod(pod api.Pod) error {
func (r *Registry) UpdatePod(pod *api.Pod) error {
return fmt.Errorf("unimplemented!")
}
@@ -205,7 +205,7 @@ func (r *Registry) DeletePod(podID string) error {
}
// Next, remove the pod from the machine atomically.
contKey := makeContainerKey(machine)
return r.AtomicUpdate(contKey, &api.ContainerManifestList{}, func(in interface{}) (interface{}, error) {
return r.AtomicUpdate(contKey, &api.ContainerManifestList{}, func(in runtime.Object) (runtime.Object, error) {
manifests := in.(*api.ContainerManifestList)
newManifests := make([]api.ContainerManifest, 0, len(manifests.Items))
found := false
@@ -258,7 +258,7 @@ func (r *Registry) GetController(controllerID string) (*api.ReplicationControlle
}
// CreateController creates a new ReplicationController.
func (r *Registry) CreateController(controller api.ReplicationController) error {
func (r *Registry) CreateController(controller *api.ReplicationController) error {
err := r.CreateObj(makeControllerKey(controller.ID), controller)
if tools.IsEtcdNodeExist(err) {
return errors.NewAlreadyExists("replicationController", controller.ID)
@@ -267,8 +267,8 @@ func (r *Registry) CreateController(controller api.ReplicationController) error
}
// UpdateController replaces an existing ReplicationController.
func (r *Registry) UpdateController(controller api.ReplicationController) error {
return r.SetObj(makeControllerKey(controller.ID), &controller)
func (r *Registry) UpdateController(controller *api.ReplicationController) error {
return r.SetObj(makeControllerKey(controller.ID), controller)
}
// DeleteController deletes a ReplicationController specified by its ID.
@@ -293,7 +293,7 @@ func (r *Registry) ListServices() (*api.ServiceList, error) {
}
// CreateService creates a new Service.
func (r *Registry) CreateService(svc api.Service) error {
func (r *Registry) CreateService(svc *api.Service) error {
err := r.CreateObj(makeServiceKey(svc.ID), svc)
if tools.IsEtcdNodeExist(err) {
return errors.NewAlreadyExists("service", svc.ID)
@@ -352,8 +352,8 @@ func (r *Registry) DeleteService(name string) error {
}
// UpdateService replaces an existing Service.
func (r *Registry) UpdateService(svc api.Service) error {
return r.SetObj(makeServiceKey(svc.ID), &svc)
func (r *Registry) UpdateService(svc *api.Service) error {
return r.SetObj(makeServiceKey(svc.ID), svc)
}
// WatchServices begins watching for new, changed, or deleted service configurations.
@@ -378,10 +378,10 @@ func (r *Registry) ListEndpoints() (*api.EndpointsList, error) {
}
// UpdateEndpoints update Endpoints of a Service.
func (r *Registry) UpdateEndpoints(e api.Endpoints) error {
func (r *Registry) UpdateEndpoints(e *api.Endpoints) error {
// TODO: this is a really bad misuse of AtomicUpdate, need to compute a diff inside the loop.
return r.AtomicUpdate(makeServiceEndpointsKey(e.ID), &api.Endpoints{},
func(input interface{}) (interface{}, error) {
func(input runtime.Object) (runtime.Object, error) {
// TODO: racy - label query is returning different results for two simultaneous updaters
return e, nil
})

View File

@@ -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.EncodeOrDie(api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
fakeClient.Set("/registry/pods/foo", runtime.DefaultScheme.EncodeOrDie(&api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := NewTestEtcdRegistry(fakeClient)
pod, err := registry.GetPod("foo")
if err != nil {
@@ -77,9 +77,9 @@ func TestEtcdCreatePod(t *testing.T) {
},
E: tools.EtcdErrorNotFound,
}
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(&api.ContainerManifestList{}), 0)
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&api.ContainerManifestList{}), 0)
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{
err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{
ID: "foo",
},
@@ -108,7 +108,7 @@ func TestEtcdCreatePod(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
var pod api.Pod
err = runtime.DecodeInto([]byte(resp.Node.Value), &pod)
err = runtime.DefaultCodec.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.DecodeInto([]byte(resp.Node.Value), &manifests)
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &manifests)
if len(manifests.Items) != 1 || manifests.Items[0].ID != "foo" {
t.Errorf("Unexpected manifest list: %#v", manifests)
}
@@ -133,13 +133,13 @@ func TestEtcdCreatePodAlreadyExisting(t *testing.T) {
fakeClient.Data["/registry/pods/foo"] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(api.Pod{JSONBase: api.JSONBase{ID: "foo"}}),
Value: runtime.DefaultScheme.EncodeOrDie(&api.Pod{JSONBase: api.JSONBase{ID: "foo"}}),
},
},
E: nil,
}
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{
err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{
ID: "foo",
},
@@ -165,7 +165,7 @@ func TestEtcdCreatePodWithContainersError(t *testing.T) {
E: tools.EtcdErrorValueRequired,
}
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{
err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{
ID: "foo",
},
@@ -205,7 +205,7 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
E: tools.EtcdErrorNotFound,
}
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{
err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{
ID: "foo",
},
@@ -235,7 +235,7 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
var pod api.Pod
err = runtime.DecodeInto([]byte(resp.Node.Value), &pod)
err = runtime.DefaultCodec.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.DecodeInto([]byte(resp.Node.Value), &manifests)
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &manifests)
if len(manifests.Items) != 1 || manifests.Items[0].ID != "foo" {
t.Errorf("Unexpected manifest list: %#v", manifests)
}
@@ -264,13 +264,13 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
},
E: tools.EtcdErrorNotFound,
}
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(api.ContainerManifestList{
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&api.ContainerManifestList{
Items: []api.ContainerManifest{
{ID: "bar"},
},
}), 0)
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{
err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{
ID: "foo",
},
@@ -300,7 +300,7 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
var pod api.Pod
err = runtime.DecodeInto([]byte(resp.Node.Value), &pod)
err = runtime.DefaultCodec.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.DecodeInto([]byte(resp.Node.Value), &manifests)
err = runtime.DefaultCodec.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.EncodeOrDie(api.Pod{
fakeClient.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{
JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.PodState{Host: "machine"},
}), 0)
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(&api.ContainerManifestList{
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&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.DecodeInto([]byte(response.Node.Value), &manifests)
runtime.DefaultCodec.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.EncodeOrDie(api.Pod{
fakeClient.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{
JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.PodState{Host: "machine"},
}), 0)
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.EncodeOrDie(&api.ContainerManifestList{
fakeClient.Set("/registry/hosts/machine/kubelet", runtime.DefaultScheme.EncodeOrDie(&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.DecodeInto([]byte(response.Node.Value), &manifests)
runtime.DefaultCodec.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.EncodeOrDie(api.Pod{
Value: runtime.DefaultScheme.EncodeOrDie(&api.Pod{
JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.PodState{Host: "machine"},
}),
},
{
Value: runtime.EncodeOrDie(api.Pod{
Value: runtime.DefaultScheme.EncodeOrDie(&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.EncodeOrDie(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}),
Value: runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}),
},
{
Value: runtime.EncodeOrDie(api.ReplicationController{JSONBase: api.JSONBase{ID: "bar"}}),
Value: runtime.DefaultScheme.EncodeOrDie(&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.EncodeOrDie(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
fakeClient.Set("/registry/controllers/foo", runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := NewTestEtcdRegistry(fakeClient)
ctrl, err := registry.GetController("foo")
if err != nil {
@@ -593,7 +593,7 @@ func TestEtcdDeleteController(t *testing.T) {
func TestEtcdCreateController(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateController(api.ReplicationController{
err := registry.CreateController(&api.ReplicationController{
JSONBase: api.JSONBase{
ID: "foo",
},
@@ -607,7 +607,7 @@ func TestEtcdCreateController(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
var ctrl api.ReplicationController
err = runtime.DecodeInto([]byte(resp.Node.Value), &ctrl)
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &ctrl)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@@ -619,10 +619,10 @@ func TestEtcdCreateController(t *testing.T) {
func TestEtcdCreateControllerAlreadyExisting(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
fakeClient.Set("/registry/controllers/foo", runtime.EncodeOrDie(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
fakeClient.Set("/registry/controllers/foo", runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateController(api.ReplicationController{
err := registry.CreateController(&api.ReplicationController{
JSONBase: api.JSONBase{
ID: "foo",
},
@@ -636,9 +636,9 @@ func TestEtcdUpdateController(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
fakeClient.TestIndex = true
resp, _ := fakeClient.Set("/registry/controllers/foo", runtime.EncodeOrDie(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
resp, _ := fakeClient.Set("/registry/controllers/foo", runtime.DefaultScheme.EncodeOrDie(&api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := NewTestEtcdRegistry(fakeClient)
err := registry.UpdateController(api.ReplicationController{
err := registry.UpdateController(&api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex},
DesiredState: api.ReplicationControllerState{
Replicas: 2,
@@ -662,10 +662,10 @@ func TestEtcdListServices(t *testing.T) {
Node: &etcd.Node{
Nodes: []*etcd.Node{
{
Value: runtime.EncodeOrDie(api.Service{JSONBase: api.JSONBase{ID: "foo"}}),
Value: runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "foo"}}),
},
{
Value: runtime.EncodeOrDie(api.Service{JSONBase: api.JSONBase{ID: "bar"}}),
Value: runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "bar"}}),
},
},
},
@@ -686,7 +686,7 @@ func TestEtcdListServices(t *testing.T) {
func TestEtcdCreateService(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateService(api.Service{
err := registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo"},
})
if err != nil {
@@ -699,7 +699,7 @@ func TestEtcdCreateService(t *testing.T) {
}
var service api.Service
err = runtime.DecodeInto([]byte(resp.Node.Value), &service)
err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &service)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@@ -711,9 +711,9 @@ func TestEtcdCreateService(t *testing.T) {
func TestEtcdCreateServiceAlreadyExisting(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
fakeClient.Set("/registry/services/specs/foo", runtime.EncodeOrDie(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
fakeClient.Set("/registry/services/specs/foo", runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateService(api.Service{
err := registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo"},
})
if !errors.IsAlreadyExists(err) {
@@ -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.EncodeOrDie(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
fakeClient.Set("/registry/services/specs/foo", runtime.DefaultScheme.EncodeOrDie(&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.EncodeOrDie(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
resp, _ := fakeClient.Set("/registry/services/specs/foo", runtime.DefaultScheme.EncodeOrDie(&api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := NewTestEtcdRegistry(fakeClient)
testService := api.Service{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex},
@@ -786,7 +786,7 @@ func TestEtcdUpdateService(t *testing.T) {
"baz": "bar",
},
}
err := registry.UpdateService(testService)
err := registry.UpdateService(&testService)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@@ -812,10 +812,10 @@ func TestEtcdListEndpoints(t *testing.T) {
Node: &etcd.Node{
Nodes: []*etcd.Node{
{
Value: runtime.EncodeOrDie(api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:8345"}}),
Value: runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:8345"}}),
},
{
Value: runtime.EncodeOrDie(api.Endpoints{JSONBase: api.JSONBase{ID: "bar"}}),
Value: runtime.DefaultScheme.EncodeOrDie(&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.EncodeOrDie(endpoints), 0)
fakeClient.Set("/registry/services/endpoints/foo", runtime.DefaultScheme.EncodeOrDie(endpoints), 0)
got, err := registry.GetEndpoints("foo")
if err != nil {
@@ -862,9 +862,9 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
Endpoints: []string{"baz", "bar"},
}
fakeClient.Set("/registry/services/endpoints/foo", runtime.EncodeOrDie(api.Endpoints{}), 0)
fakeClient.Set("/registry/services/endpoints/foo", runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{}), 0)
err := registry.UpdateEndpoints(endpoints)
err := registry.UpdateEndpoints(&endpoints)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@@ -874,7 +874,7 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
var endpointsOut api.Endpoints
err = runtime.DecodeInto([]byte(response.Node.Value), &endpointsOut)
err = runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &endpointsOut)
if !reflect.DeepEqual(endpoints, endpointsOut) {
t.Errorf("Unexpected endpoints: %#v, expected %#v", endpointsOut, endpoints)
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
@@ -37,7 +38,7 @@ func NewRegistryStorage(m Registry) apiserver.RESTStorage {
}
}
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Create(obj runtime.Object) (<-chan runtime.Object, error) {
minion, ok := obj.(*api.Minion)
if !ok {
return nil, fmt.Errorf("not a minion: %#v", obj)
@@ -48,7 +49,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
minion.CreationTimestamp = util.Now()
return apiserver.MakeAsync(func() (interface{}, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
err := rs.registry.Insert(minion.ID)
if err != nil {
return nil, err
@@ -64,7 +65,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
}), nil
}
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
func (rs *RegistryStorage) Delete(id string) (<-chan runtime.Object, error) {
exists, err := rs.registry.Contains(id)
if !exists {
return nil, ErrDoesNotExist
@@ -72,12 +73,12 @@ func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
if err != nil {
return nil, err
}
return apiserver.MakeAsync(func() (interface{}, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(id)
}), nil
}
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
func (rs *RegistryStorage) Get(id string) (runtime.Object, error) {
exists, err := rs.registry.Contains(id)
if !exists {
return nil, ErrDoesNotExist
@@ -85,26 +86,26 @@ func (rs *RegistryStorage) Get(id string) (interface{}, error) {
return rs.toApiMinion(id), err
}
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
func (rs *RegistryStorage) List(selector labels.Selector) (runtime.Object, error) {
nameList, err := rs.registry.List()
if err != nil {
return nil, err
}
var list api.MinionList
for _, name := range nameList {
list.Items = append(list.Items, rs.toApiMinion(name))
list.Items = append(list.Items, *rs.toApiMinion(name))
}
return list, nil
return &list, nil
}
func (rs RegistryStorage) New() interface{} {
func (rs RegistryStorage) New() runtime.Object {
return &api.Minion{}
}
func (rs *RegistryStorage) Update(minion interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Update(minion runtime.Object) (<-chan runtime.Object, error) {
return nil, fmt.Errorf("Minions can only be created (inserted) and deleted.")
}
func (rs *RegistryStorage) toApiMinion(name string) api.Minion {
return api.Minion{JSONBase: api.JSONBase{ID: name}}
func (rs *RegistryStorage) toApiMinion(name string) *api.Minion {
return &api.Minion{JSONBase: api.JSONBase{ID: name}}
}

View File

@@ -28,10 +28,10 @@ func TestMinionRegistryStorage(t *testing.T) {
m := NewRegistry([]string{"foo", "bar"})
ms := NewRegistryStorage(m)
if obj, err := ms.Get("foo"); err != nil || obj.(api.Minion).ID != "foo" {
if obj, err := ms.Get("foo"); err != nil || obj.(*api.Minion).ID != "foo" {
t.Errorf("missing expected object")
}
if obj, err := ms.Get("bar"); err != nil || obj.(api.Minion).ID != "bar" {
if obj, err := ms.Get("bar"); err != nil || obj.(*api.Minion).ID != "bar" {
t.Errorf("missing expected object")
}
if _, err := ms.Get("baz"); err != ErrDoesNotExist {
@@ -43,10 +43,10 @@ func TestMinionRegistryStorage(t *testing.T) {
t.Errorf("insert failed")
}
obj := <-c
if m, ok := obj.(api.Minion); !ok || m.ID != "baz" {
if m, ok := obj.(*api.Minion); !ok || m.ID != "baz" {
t.Errorf("insert return value was weird: %#v", obj)
}
if obj, err := ms.Get("baz"); err != nil || obj.(api.Minion).ID != "baz" {
if obj, err := ms.Get("baz"); err != nil || obj.(*api.Minion).ID != "baz" {
t.Errorf("insert didn't actually insert")
}
@@ -78,7 +78,7 @@ func TestMinionRegistryStorage(t *testing.T) {
JSONBase: api.JSONBase{ID: "foo"},
},
}
if !reflect.DeepEqual(list.(api.MinionList).Items, expect) {
if !reflect.DeepEqual(list.(*api.MinionList).Items, expect) {
t.Errorf("Unexpected list value: %#v", list)
}
}

View File

@@ -31,9 +31,9 @@ type Registry interface {
// Get a specific pod
GetPod(podID string) (*api.Pod, error)
// Create a pod based on a specification.
CreatePod(pod api.Pod) error
CreatePod(pod *api.Pod) error
// Update an existing pod
UpdatePod(pod api.Pod) error
UpdatePod(pod *api.Pod) error
// Delete an existing pod
DeletePod(podID string) error
}

View File

@@ -29,6 +29,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
@@ -64,7 +65,7 @@ func NewRegistryStorage(config *RegistryStorageConfig) apiserver.RESTStorage {
}
}
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Create(obj runtime.Object) (<-chan runtime.Object, error) {
pod := obj.(*api.Pod)
if len(pod.ID) == 0 {
pod.ID = uuid.NewUUID().String()
@@ -76,21 +77,21 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
pod.CreationTimestamp = util.Now()
return apiserver.MakeAsync(func() (interface{}, error) {
if err := rs.registry.CreatePod(*pod); err != nil {
return apiserver.MakeAsync(func() (runtime.Object, error) {
if err := rs.registry.CreatePod(pod); err != nil {
return nil, err
}
return rs.registry.GetPod(pod.ID)
}), nil
}
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
return apiserver.MakeAsync(func() (interface{}, error) {
func (rs *RegistryStorage) Delete(id string) (<-chan runtime.Object, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeletePod(id)
}), nil
}
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
func (rs *RegistryStorage) Get(id string) (runtime.Object, error) {
pod, err := rs.registry.GetPod(id)
if err != nil {
return pod, err
@@ -106,7 +107,7 @@ func (rs *RegistryStorage) Get(id string) (interface{}, error) {
return pod, err
}
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
func (rs *RegistryStorage) List(selector labels.Selector) (runtime.Object, error) {
pods, err := rs.registry.ListPods(selector)
if err == nil {
for i := range pods.Items {
@@ -131,17 +132,17 @@ func (rs *RegistryStorage) Watch(label, field labels.Selector, resourceVersion u
})
}
func (rs RegistryStorage) New() interface{} {
func (rs RegistryStorage) New() runtime.Object {
return &api.Pod{}
}
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Update(obj runtime.Object) (<-chan runtime.Object, error) {
pod := obj.(*api.Pod)
if errs := validation.ValidatePod(pod); len(errs) > 0 {
return nil, errors.NewInvalid("pod", pod.ID, errs)
}
return apiserver.MakeAsync(func() (interface{}, error) {
if err := rs.registry.UpdatePod(*pod); err != nil {
return apiserver.MakeAsync(func() (runtime.Object, error) {
if err := rs.registry.UpdatePod(pod); err != nil {
return nil, err
}
return rs.registry.GetPod(pod.ID)
@@ -235,7 +236,7 @@ func getPodStatus(pod *api.Pod) api.PodStatus {
}
}
func (rs *RegistryStorage) waitForPodRunning(pod api.Pod) (interface{}, error) {
func (rs *RegistryStorage) waitForPodRunning(pod *api.Pod) (runtime.Object, error) {
for {
podObj, err := rs.Get(pod.ID)
if err != nil || podObj == nil {

View File

@@ -32,7 +32,7 @@ import (
"github.com/fsouza/go-dockerclient"
)
func expectApiStatusError(t *testing.T, ch <-chan interface{}, msg string) {
func expectApiStatusError(t *testing.T, ch <-chan runtime.Object, msg string) {
out := <-ch
status, ok := out.(*api.Status)
if !ok {
@@ -44,7 +44,7 @@ func expectApiStatusError(t *testing.T, ch <-chan interface{}, msg string) {
}
}
func expectPod(t *testing.T, ch <-chan interface{}) (*api.Pod, bool) {
func expectPod(t *testing.T, ch <-chan runtime.Object) (*api.Pod, bool) {
out := <-ch
pod, ok := out.(*api.Pod)
if !ok || pod == nil {
@@ -178,13 +178,13 @@ func TestPodDecode(t *testing.T) {
ID: "foo",
},
}
body, err := runtime.Encode(expected)
body, err := runtime.DefaultCodec.Encode(expected)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
actual := storage.New()
if err := runtime.DecodeInto(body, actual); err != nil {
if err := runtime.DefaultCodec.DecodeInto(body, actual); err != nil {
t.Errorf("unexpected error: %v", err)
}

View File

@@ -35,11 +35,11 @@ func (r *ControllerRegistry) GetController(ID string) (*api.ReplicationControlle
return &api.ReplicationController{}, r.Err
}
func (r *ControllerRegistry) CreateController(controller api.ReplicationController) error {
func (r *ControllerRegistry) CreateController(controller *api.ReplicationController) error {
return r.Err
}
func (r *ControllerRegistry) UpdateController(controller api.ReplicationController) error {
func (r *ControllerRegistry) UpdateController(controller *api.ReplicationController) error {
return r.Err
}

View File

@@ -68,19 +68,19 @@ func (r *PodRegistry) GetPod(podId string) (*api.Pod, error) {
return r.Pod, r.Err
}
func (r *PodRegistry) CreatePod(pod api.Pod) error {
func (r *PodRegistry) CreatePod(pod *api.Pod) error {
r.Lock()
defer r.Unlock()
r.Pod = &pod
r.mux.Action(watch.Added, &pod)
r.Pod = pod
r.mux.Action(watch.Added, pod)
return r.Err
}
func (r *PodRegistry) UpdatePod(pod api.Pod) error {
func (r *PodRegistry) UpdatePod(pod *api.Pod) error {
r.Lock()
defer r.Unlock()
r.Pod = &pod
r.mux.Action(watch.Modified, &pod)
r.Pod = pod
r.mux.Action(watch.Modified, pod)
return r.Err
}

View File

@@ -42,9 +42,9 @@ func (r *ServiceRegistry) ListServices() (*api.ServiceList, error) {
return &r.List, r.Err
}
func (r *ServiceRegistry) CreateService(svc api.Service) error {
r.Service = &svc
r.List.Items = append(r.List.Items, svc)
func (r *ServiceRegistry) CreateService(svc *api.Service) error {
r.Service = svc
r.List.Items = append(r.List.Items, *svc)
return r.Err
}
@@ -58,7 +58,7 @@ func (r *ServiceRegistry) DeleteService(id string) error {
return r.Err
}
func (r *ServiceRegistry) UpdateService(svc api.Service) error {
func (r *ServiceRegistry) UpdateService(svc *api.Service) error {
r.UpdatedID = svc.ID
return r.Err
}
@@ -76,8 +76,8 @@ func (r *ServiceRegistry) GetEndpoints(id string) (*api.Endpoints, error) {
return &r.Endpoints, r.Err
}
func (r *ServiceRegistry) UpdateEndpoints(e api.Endpoints) error {
r.Endpoints = e
func (r *ServiceRegistry) UpdateEndpoints(e *api.Endpoints) error {
r.Endpoints = *e
return r.Err
}

View File

@@ -26,10 +26,10 @@ import (
// Registry is an interface for things that know how to store services.
type Registry interface {
ListServices() (*api.ServiceList, error)
CreateService(svc api.Service) error
CreateService(svc *api.Service) error
GetService(name string) (*api.Service, error)
DeleteService(name string) error
UpdateService(svc api.Service) error
UpdateService(svc *api.Service) error
WatchServices(labels, fields labels.Selector, resourceVersion uint64) (watch.Interface, error)
// TODO: endpoints and their implementation should be separated, setting endpoints should be

View File

@@ -29,6 +29,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
@@ -49,7 +50,7 @@ func NewRegistryStorage(registry Registry, cloud cloudprovider.Interface, machin
}
}
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Create(obj runtime.Object) (<-chan runtime.Object, error) {
srv := obj.(*api.Service)
if errs := validation.ValidateService(srv); len(errs) > 0 {
return nil, errors.NewInvalid("service", srv.ID, errs)
@@ -57,7 +58,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
srv.CreationTimestamp = util.Now()
return apiserver.MakeAsync(func() (interface{}, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
// TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers
// correctly no matter what http operations happen.
if srv.CreateExternalLoadBalancer {
@@ -85,7 +86,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
return nil, err
}
}
err := rs.registry.CreateService(*srv)
err := rs.registry.CreateService(srv)
if err != nil {
return nil, err
}
@@ -93,18 +94,18 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
}), nil
}
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
func (rs *RegistryStorage) Delete(id string) (<-chan runtime.Object, error) {
service, err := rs.registry.GetService(id)
if err != nil {
return nil, err
}
return apiserver.MakeAsync(func() (interface{}, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
rs.deleteExternalLoadBalancer(service)
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(id)
}), nil
}
func (rs *RegistryStorage) Get(id string) (interface{}, error) {
func (rs *RegistryStorage) Get(id string) (runtime.Object, error) {
s, err := rs.registry.GetService(id)
if err != nil {
return nil, err
@@ -112,7 +113,7 @@ func (rs *RegistryStorage) Get(id string) (interface{}, error) {
return s, err
}
func (rs *RegistryStorage) List(selector labels.Selector) (interface{}, error) {
func (rs *RegistryStorage) List(selector labels.Selector) (runtime.Object, error) {
list, err := rs.registry.ListServices()
if err != nil {
return nil, err
@@ -133,7 +134,7 @@ func (rs *RegistryStorage) Watch(label, field labels.Selector, resourceVersion u
return rs.registry.WatchServices(label, field, resourceVersion)
}
func (rs RegistryStorage) New() interface{} {
func (rs RegistryStorage) New() runtime.Object {
return &api.Service{}
}
@@ -155,14 +156,14 @@ func GetServiceEnvironmentVariables(registry Registry, machine string) ([]api.En
return result, nil
}
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
func (rs *RegistryStorage) Update(obj runtime.Object) (<-chan runtime.Object, error) {
srv := obj.(*api.Service)
if errs := validation.ValidateService(srv); len(errs) > 0 {
return nil, errors.NewInvalid("service", srv.ID, errs)
}
return apiserver.MakeAsync(func() (interface{}, error) {
return apiserver.MakeAsync(func() (runtime.Object, error) {
// TODO: check to see if external load balancer status changed
err := rs.registry.UpdateService(*srv)
err := rs.registry.UpdateService(srv)
if err != nil {
return nil, err
}

View File

@@ -89,7 +89,7 @@ func TestServiceStorageValidatesCreate(t *testing.T) {
func TestServiceRegistryUpdate(t *testing.T) {
registry := registrytest.NewServiceRegistry()
registry.CreateService(api.Service{
registry.CreateService(&api.Service{
Port: 6502,
JSONBase: api.JSONBase{ID: "foo"},
Selector: map[string]string{"bar": "baz1"},
@@ -118,7 +118,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
func TestServiceStorageValidatesUpdate(t *testing.T) {
registry := registrytest.NewServiceRegistry()
registry.CreateService(api.Service{
registry.CreateService(&api.Service{
Port: 6502,
JSONBase: api.JSONBase{ID: "foo"},
Selector: map[string]string{"bar": "baz"},
@@ -200,7 +200,7 @@ func TestServiceRegistryDelete(t *testing.T) {
fakeCloud := &cloud.FakeCloud{}
machines := []string{"foo", "bar", "baz"}
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
svc := api.Service{
svc := &api.Service{
JSONBase: api.JSONBase{ID: "foo"},
Selector: map[string]string{"bar": "baz"},
}
@@ -220,7 +220,7 @@ func TestServiceRegistryDeleteExternal(t *testing.T) {
fakeCloud := &cloud.FakeCloud{}
machines := []string{"foo", "bar", "baz"}
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
svc := api.Service{
svc := &api.Service{
JSONBase: api.JSONBase{ID: "foo"},
Selector: map[string]string{"bar": "baz"},
CreateExternalLoadBalancer: true,
@@ -263,7 +263,7 @@ func TestServiceRegistryGet(t *testing.T) {
fakeCloud := &cloud.FakeCloud{}
machines := []string{"foo", "bar", "baz"}
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
registry.CreateService(api.Service{
registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo"},
Selector: map[string]string{"bar": "baz"},
})
@@ -282,7 +282,7 @@ func TestServiceRegistryResourceLocation(t *testing.T) {
fakeCloud := &cloud.FakeCloud{}
machines := []string{"foo", "bar", "baz"}
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
registry.CreateService(api.Service{
registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo"},
Selector: map[string]string{"bar": "baz"},
})
@@ -310,11 +310,11 @@ func TestServiceRegistryList(t *testing.T) {
fakeCloud := &cloud.FakeCloud{}
machines := []string{"foo", "bar", "baz"}
storage := NewRegistryStorage(registry, fakeCloud, minion.NewRegistry(machines))
registry.CreateService(api.Service{
registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo"},
Selector: map[string]string{"bar": "baz"},
})
registry.CreateService(api.Service{
registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo2"},
Selector: map[string]string{"bar2": "baz2"},
})

View File

@@ -33,7 +33,7 @@ func (a *EmbeddedObject) UnmarshalJSON(b []byte) error {
return nil
}
obj, err := Decode(b)
obj, err := DefaultCodec.Decode(b)
if err != nil {
return err
}
@@ -48,7 +48,7 @@ func (a EmbeddedObject) MarshalJSON() ([]byte, error) {
return []byte("null"), nil
}
return Encode(a.Object)
return DefaultCodec.Encode(a.Object)
}
// SetYAML implements the yaml.Setter interface.
@@ -67,7 +67,7 @@ func (a *EmbeddedObject) SetYAML(tag string, value interface{}) bool {
if err != nil {
panic("yaml can't reverse its own object")
}
obj, err := Decode(b)
obj, err := DefaultCodec.Decode(b)
if err != nil {
return false
}
@@ -82,7 +82,7 @@ func (a EmbeddedObject) GetYAML() (tag string, value interface{}) {
return
}
// Encode returns JSON, which is conveniently a subset of YAML.
v, err := Encode(a.Object)
v, err := DefaultCodec.Encode(a.Object)
if err != nil {
panic("impossible to encode API object!")
}

View File

@@ -22,14 +22,19 @@ import (
"testing"
)
type EmbeddedTest struct {
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) {
type EmbeddedTest struct {
JSONBase `yaml:",inline" json:",inline"`
Object EmbeddedObject `yaml:"object,omitempty" json:"object,omitempty"`
EmptyObject EmbeddedObject `yaml:"emptyObject,omitempty" json:"emptyObject,omitempty"`
}
AddKnownTypes("", EmbeddedTest{})
AddKnownTypes("v1beta1", EmbeddedTest{})
// TODO(dbsmith) fix EmbeddedObject to not use DefaultScheme.
s := DefaultScheme
s.AddKnownTypes("", &EmbeddedTest{})
s.AddKnownTypes("v1beta1", &EmbeddedTest{})
outer := &EmbeddedTest{
JSONBase: JSONBase{ID: "outer"},
@@ -40,14 +45,14 @@ func TestEmbeddedObject(t *testing.T) {
},
}
wire, err := Encode(outer)
wire, err := s.Encode(outer)
if err != nil {
t.Fatalf("Unexpected encode error '%v'", err)
}
t.Logf("Wire format is:\n%v\n", string(wire))
decoded, err := Decode(wire)
decoded, err := s.Decode(wire)
if err != nil {
t.Fatalf("Unexpected decode error %v", err)
}

View File

@@ -24,41 +24,44 @@ import (
"gopkg.in/v1/yaml"
)
// codec defines methods for serializing and deserializing API
// objects.
type codec interface {
Encode(obj interface{}) (data []byte, err error)
Decode(data []byte) (interface{}, error)
DecodeInto(data []byte, obj interface{}) error
var DefaultResourceVersioner ResourceVersioner = NewJSONBaseResourceVersioner()
var DefaultScheme = NewScheme("", "v1beta1")
var DefaultCodec Codec = DefaultScheme
// Scheme defines methods for serializing and deserializing API objects. It
// is an adaptation of conversion's Scheme for our API objects.
type Scheme struct {
raw *conversion.Scheme
}
// resourceVersioner provides methods for setting and retrieving
// the resource version from an API object.
type resourceVersioner interface {
SetResourceVersion(obj interface{}, version uint64) error
ResourceVersion(obj interface{}) (uint64, error)
}
var ResourceVersioner resourceVersioner = NewJSONBaseResourceVersioner()
var conversionScheme = conversion.NewScheme()
var Codec codec = conversionScheme
func init() {
conversionScheme.InternalVersion = ""
conversionScheme.ExternalVersion = "v1beta1"
conversionScheme.MetaInsertionFactory = metaInsertion{}
// NewScheme creates a new Scheme. A default scheme is provided and accessible
// as the "DefaultScheme" variable.
func NewScheme(internalVersion, externalVersion string) *Scheme {
s := &Scheme{conversion.NewScheme()}
s.raw.InternalVersion = internalVersion
s.raw.ExternalVersion = externalVersion
s.raw.MetaInsertionFactory = metaInsertion{}
return s
}
// AddKnownTypes registers the types of the arguments to the marshaller of the package api.
// Encode() refuses the object unless its type is registered with AddKnownTypes.
func AddKnownTypes(version string, types ...interface{}) {
conversionScheme.AddKnownTypes(version, types...)
func (s *Scheme) AddKnownTypes(version string, types ...Object) {
interfaces := make([]interface{}, len(types))
for i := range types {
interfaces[i] = types[i]
}
s.raw.AddKnownTypes(version, interfaces...)
}
// New returns a new API object of the given version ("" for internal
// representation) and name, or an error if it hasn't been registered.
func New(versionName, typeName string) (interface{}, error) {
return conversionScheme.NewObject(versionName, typeName)
func (s *Scheme) New(versionName, typeName string) (Object, error) {
obj, err := s.raw.NewObject(versionName, typeName)
if err != nil {
return nil, err
}
return obj.(Object), nil
}
// AddConversionFuncs adds a function to the list of conversion functions. The given
@@ -73,20 +76,20 @@ func New(versionName, typeName string) (interface{}, error) {
// sanely copy fields that have the same names. It's OK if the destination type has
// extra fields, but it must not remove any. So you only need to add a conversion
// function for things with changed/removed fields.
func AddConversionFuncs(conversionFuncs ...interface{}) error {
return conversionScheme.AddConversionFuncs(conversionFuncs...)
func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
return s.raw.AddConversionFuncs(conversionFuncs...)
}
// Convert will attempt to convert in into out. Both must be pointers to API objects.
// Convert will attempt to convert in into out. Both must be pointers.
// For easy testing of conversion functions. Returns an error if the conversion isn't
// possible.
func Convert(in, out interface{}) error {
return conversionScheme.Convert(in, out)
func (s *Scheme) Convert(in, out interface{}) error {
return s.raw.Convert(in, out)
}
// FindJSONBase takes an arbitary api type, returns pointer to its JSONBase field.
// obj must be a pointer to an api type.
func FindJSONBase(obj interface{}) (JSONBaseInterface, error) {
func FindJSONBase(obj Object) (JSONBaseInterface, error) {
v, err := enforcePtr(obj)
if err != nil {
return nil, err
@@ -108,8 +111,8 @@ func FindJSONBase(obj interface{}) (JSONBaseInterface, error) {
}
// EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests.
func EncodeOrDie(obj interface{}) string {
return conversionScheme.EncodeOrDie(obj)
func (s *Scheme) EncodeOrDie(obj Object) string {
return s.raw.EncodeOrDie(obj)
}
// Encode turns the given api object into an appropriate JSON string.
@@ -146,14 +149,14 @@ func EncodeOrDie(obj interface{}) string {
// default will be needed, to allow operating in clusters that haven't yet
// upgraded.
//
func Encode(obj interface{}) (data []byte, err error) {
return conversionScheme.Encode(obj)
func (s *Scheme) Encode(obj Object) (data []byte, err error) {
return s.raw.Encode(obj)
}
// enforcePtr ensures that obj is a pointer of some sort. Returns a reflect.Value of the
// dereferenced pointer, ensuring that it is settable/addressable.
// Returns an error if this is not possible.
func enforcePtr(obj interface{}) (reflect.Value, error) {
func enforcePtr(obj Object) (reflect.Value, error) {
v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr {
return reflect.Value{}, fmt.Errorf("expected pointer, but got %v", v.Type().Name())
@@ -181,8 +184,12 @@ func VersionAndKind(data []byte) (version, kind string, err error) {
// Deduces the type based upon the APIVersion and Kind fields, which are set
// by Encode. Only versioned objects (APIVersion != "") are accepted. The object
// will be converted into the in-memory unversioned type before being returned.
func Decode(data []byte) (interface{}, error) {
return conversionScheme.Decode(data)
func (s *Scheme) Decode(data []byte) (Object, error) {
obj, err := s.raw.Decode(data)
if err != nil {
return nil, err
}
return obj.(Object), nil
}
// DecodeInto parses a YAML or JSON string and stores it in obj. Returns an error
@@ -190,22 +197,22 @@ func Decode(data []byte) (interface{}, error) {
// pointer to an api type.
// If obj's APIVersion doesn't match that in data, an attempt will be made to convert
// data into obj's version.
func DecodeInto(data []byte, obj interface{}) error {
return conversionScheme.DecodeInto(data, obj)
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.
// TODO(dbsmith): implement directly instead of via Encode/Decode
func Copy(obj interface{}) (interface{}, error) {
data, err := Encode(obj)
func (s *Scheme) Copy(obj Object) (Object, error) {
data, err := s.Encode(obj)
if err != nil {
return nil, err
}
return Decode(data)
return s.Decode(data)
}
func CopyOrDie(obj interface{}) interface{} {
newObj, err := Copy(obj)
func (s *Scheme) CopyOrDie(obj Object) Object {
newObj, err := s.Copy(obj)
if err != nil {
panic(err)
}

View File

@@ -25,31 +25,13 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
func TestEncode_NonPtr(t *testing.T) {
pod := api.Pod{
Labels: map[string]string{"name": "foo"},
}
obj := interface{}(pod)
data, err := runtime.Encode(obj)
obj2, err2 := runtime.Decode(data)
if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2)
}
if _, ok := obj2.(*api.Pod); !ok {
t.Fatalf("Got wrong type")
}
if !reflect.DeepEqual(obj2, &pod) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
}
}
func TestEncode_Ptr(t *testing.T) {
func TestEncode(t *testing.T) {
pod := &api.Pod{
Labels: map[string]string{"name": "foo"},
}
obj := interface{}(pod)
data, err := runtime.Encode(obj)
obj2, err2 := runtime.Decode(data)
obj := runtime.Object(pod)
data, err := runtime.DefaultScheme.Encode(obj)
obj2, err2 := runtime.DefaultScheme.Decode(data)
if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2)
}
@@ -63,11 +45,11 @@ func TestEncode_Ptr(t *testing.T) {
func TestBadJSONRejection(t *testing.T) {
badJSONMissingKind := []byte(`{ }`)
if _, err := runtime.Decode(badJSONMissingKind); err == nil {
if _, err := runtime.DefaultScheme.Decode(badJSONMissingKind); err == nil {
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
}
badJSONUnknownType := []byte(`{"kind": "bar"}`)
if _, err1 := runtime.Decode(badJSONUnknownType); err1 == nil {
if _, err1 := runtime.DefaultScheme.Decode(badJSONUnknownType); err1 == nil {
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
}
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)

40
pkg/runtime/interfaces.go Normal file
View File

@@ -0,0 +1,40 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package runtime
// Codec defines methods for serializing and deserializing API objects.
type Codec interface {
Encode(obj Object) (data []byte, err error)
Decode(data []byte) (Object, error)
DecodeInto(data []byte, obj Object) error
}
// ResourceVersioner provides methods for setting and retrieving
// the resource version from an API object.
type ResourceVersioner interface {
SetResourceVersion(obj Object, version uint64) error
ResourceVersion(obj Object) (uint64, error)
}
// All api types must support the Object interface. It's deliberately tiny so that this is not an onerous
// burden. Implement it with a pointer reciever; this will allow us to use the go compiler to check the
// one thing about our objects that it's capable of checking for us.
type Object interface {
// This function is used only to enforce membership. It's never called.
// TODO: Consider mass rename in the future to make it do something useful.
IsAnAPIObject()
}

View File

@@ -23,13 +23,13 @@ import (
// NewJSONBaseResourceVersioner returns a resourceVersioner that can set or
// retrieve ResourceVersion on objects derived from JSONBase.
func NewJSONBaseResourceVersioner() resourceVersioner {
func NewJSONBaseResourceVersioner() ResourceVersioner {
return &jsonBaseResourceVersioner{}
}
type jsonBaseResourceVersioner struct{}
func (v jsonBaseResourceVersioner) ResourceVersion(obj interface{}) (uint64, error) {
func (v jsonBaseResourceVersioner) ResourceVersion(obj Object) (uint64, error) {
json, err := FindJSONBase(obj)
if err != nil {
return 0, err
@@ -37,7 +37,7 @@ func (v jsonBaseResourceVersioner) ResourceVersion(obj interface{}) (uint64, err
return json.ResourceVersion(), nil
}
func (v jsonBaseResourceVersioner) SetResourceVersion(obj interface{}, version uint64) error {
func (v jsonBaseResourceVersioner) SetResourceVersion(obj Object, version uint64) error {
json, err := FindJSONBase(obj)
if err != nil {
return err

View File

@@ -77,20 +77,20 @@ func TestGenericJSONBase(t *testing.T) {
}
}
type MyAPIObject struct {
JSONBase `yaml:",inline" json:",inline"`
}
func (*MyAPIObject) IsAnAPIObject() {}
type MyIncorrectlyMarkedAsAPIObject struct {
}
func (*MyIncorrectlyMarkedAsAPIObject) IsAnAPIObject() {}
func TestResourceVersionerOfAPI(t *testing.T) {
type JSONBase struct {
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
ID string `json:"id,omitempty" yaml:"id,omitempty"`
CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
}
type MyAPIObject struct {
JSONBase `yaml:",inline" json:",inline"`
}
type T struct {
Object interface{}
Object
Expected uint64
}
testCases := map[string]T{
@@ -110,10 +110,10 @@ func TestResourceVersionerOfAPI(t *testing.T) {
}
failingCases := map[string]struct {
Object interface{}
Object
Expected uint64
}{
"not a valid object to try": {JSONBase{ResourceVersion: 1}, 1},
"not a valid object to try": {&MyIncorrectlyMarkedAsAPIObject{}, 1},
}
for key, testCase := range failingCases {
_, err := versioning.ResourceVersion(testCase.Object)
@@ -123,7 +123,7 @@ func TestResourceVersionerOfAPI(t *testing.T) {
}
setCases := map[string]struct {
Object interface{}
Object
Expected uint64
}{
"pointer to api object with version": {&MyAPIObject{JSONBase: JSONBase{ResourceVersion: 1}}, 1},
@@ -140,17 +140,4 @@ func TestResourceVersionerOfAPI(t *testing.T) {
t.Errorf("%s: expected %d, got %d", key, 5, actual)
}
}
failingSetCases := map[string]struct {
Object interface{}
Expected uint64
}{
"empty api object": {MyAPIObject{}, 0},
"api object with version": {MyAPIObject{JSONBase: JSONBase{ResourceVersion: 1}}, 1},
}
for key, testCase := range failingSetCases {
if err := versioning.SetResourceVersion(testCase.Object, 5); err == nil {
t.Errorf("%s: unexpected non-error", key)
}
}
}

View File

@@ -29,8 +29,9 @@ import (
// runtime.JSONBase `yaml:",inline" json:",inline"`
// ... // other fields
// }
// func (*MyAwesomeAPIObject) IsAnAPIObject() {}
//
// JSONBase is provided here for convenience. You may use it directlly from this package or define
// JSONBase is provided here for convenience. You may use it directly from this package or define
// your own with the same fields.
//
type JSONBase struct {
@@ -43,17 +44,16 @@ type JSONBase struct {
}
// EmbeddedObject has appropriate encoder and decoder functions, such that on the wire, it's
// stored as a []byte, but in memory, the contained object is accessable as an interface{}
// via the Get() function. Only objects having a JSONBase may be stored via Object.
// 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.
//
// Note that object assumes that you've registered all of your api types with the api package.
//
// Note that objects will be serialized into the api package's default external versioned type;
// this should be fixed in the future to use the version of the current Codec instead.
// TODO(dbsmith): Stop using runtime.Codec, use the codec appropriate for the conversion (I have a plan).
type EmbeddedObject struct {
Object interface{}
Object
}
// Extension allows api objects with unknown types to be passed-through. This can be used
@@ -61,4 +61,8 @@ type EmbeddedObject struct {
// JSONBase features-- kind, version, resourceVersion, etc.
// TODO: Not implemented yet
type Extension struct {
JSONBase `yaml:",inline" json:",inline"`
// RawJSON to go here.
}
func (*Extension) IsAnAPIObject() {}

View File

@@ -73,7 +73,7 @@ func (e *EndpointController) SyncServiceEndpoints() error {
endpoints[ix] = net.JoinHostPort(pod.CurrentState.PodIP, strconv.Itoa(port))
}
// TODO: this is totally broken, we need to compute this and store inside an AtomicUpdate loop.
err = e.serviceRegistry.UpdateEndpoints(api.Endpoints{
err = e.serviceRegistry.UpdateEndpoints(&api.Endpoints{
JSONBase: api.JSONBase{ID: service.ID},
Endpoints: endpoints,
})

View File

@@ -22,6 +22,7 @@ import (
"io"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
)
@@ -42,7 +43,7 @@ func NewAPIEventDecoder(stream io.ReadCloser) *APIEventDecoder {
// Decode blocks until it can return the next object in the stream. Returns an error
// if the stream is closed or an object can't be decoded.
func (d *APIEventDecoder) Decode() (action watch.EventType, object interface{}, err error) {
func (d *APIEventDecoder) Decode() (action watch.EventType, object runtime.Object, err error) {
var got api.WatchEvent
err = d.decoder.Decode(&got)
if err != nil {

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"reflect"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/coreos/go-etcd/etcd"
)
@@ -38,19 +39,6 @@ var (
EtcdErrorValueRequired = &etcd.EtcdError{ErrorCode: EtcdErrorCodeValueRequired}
)
// Codec provides methods for transforming Etcd values into objects and back.
type Codec interface {
Encode(obj interface{}) (data []byte, err error)
Decode(data []byte) (interface{}, error)
DecodeInto(data []byte, obj interface{}) error
}
// ResourceVersioner provides methods for managing object modification tracking.
type ResourceVersioner interface {
SetResourceVersion(obj interface{}, version uint64) error
ResourceVersion(obj interface{}) (uint64, error)
}
// EtcdClient is an injectable interface for testing.
type EtcdClient interface {
AddChild(key, data string, ttl uint64) (*etcd.Response, error)
@@ -77,9 +65,9 @@ type EtcdGetSet interface {
// EtcdHelper offers common object marshalling/unmarshalling operations on an etcd client.
type EtcdHelper struct {
Client EtcdGetSet
Codec Codec
Codec runtime.Codec
// optional, no atomic operations can be performed without this interface
ResourceVersioner ResourceVersioner
ResourceVersioner runtime.ResourceVersioner
}
// IsEtcdNotFound returns true iff err is an etcd not found error.
@@ -151,9 +139,9 @@ func (h *EtcdHelper) ExtractList(key string, slicePtr interface{}, resourceVersi
v := pv.Elem()
for _, node := range nodes {
obj := reflect.New(v.Type().Elem())
err = h.Codec.DecodeInto([]byte(node.Value), obj.Interface())
err = h.Codec.DecodeInto([]byte(node.Value), obj.Interface().(runtime.Object))
if h.ResourceVersioner != nil {
_ = h.ResourceVersioner.SetResourceVersion(obj.Interface(), node.ModifiedIndex)
_ = h.ResourceVersioner.SetResourceVersion(obj.Interface().(runtime.Object), node.ModifiedIndex)
// being unable to set the version does not prevent the object from being extracted
}
if err != nil {
@@ -167,12 +155,12 @@ func (h *EtcdHelper) ExtractList(key string, slicePtr interface{}, resourceVersi
// ExtractObj unmarshals json found at key into objPtr. On a not found error, will either return
// a zero object of the requested type, or an error, depending on ignoreNotFound. Treats
// empty responses and nil response nodes exactly like a not found error.
func (h *EtcdHelper) ExtractObj(key string, objPtr interface{}, ignoreNotFound bool) error {
func (h *EtcdHelper) ExtractObj(key string, objPtr runtime.Object, ignoreNotFound bool) error {
_, _, err := h.bodyAndExtractObj(key, objPtr, ignoreNotFound)
return err
}
func (h *EtcdHelper) bodyAndExtractObj(key string, objPtr interface{}, ignoreNotFound bool) (body string, modifiedIndex uint64, err error) {
func (h *EtcdHelper) bodyAndExtractObj(key string, objPtr runtime.Object, ignoreNotFound bool) (body string, modifiedIndex uint64, err error) {
response, err := h.Client.Get(key, false, false)
if err != nil && !IsEtcdNotFound(err) {
@@ -198,7 +186,7 @@ func (h *EtcdHelper) bodyAndExtractObj(key string, objPtr interface{}, ignoreNot
}
// CreateObj adds a new object at a key unless it already exists.
func (h *EtcdHelper) CreateObj(key string, obj interface{}) error {
func (h *EtcdHelper) CreateObj(key string, obj runtime.Object) error {
data, err := h.Codec.Encode(obj)
if err != nil {
return err
@@ -221,7 +209,7 @@ func (h *EtcdHelper) Delete(key string, recursive bool) error {
// SetObj marshals obj via json, and stores under key. Will do an
// atomic update if obj's ResourceVersion field is set.
func (h *EtcdHelper) SetObj(key string, obj interface{}) error {
func (h *EtcdHelper) SetObj(key string, obj runtime.Object) error {
data, err := h.Codec.Encode(obj)
if err != nil {
return err
@@ -240,7 +228,7 @@ func (h *EtcdHelper) SetObj(key string, obj interface{}) error {
// Pass an EtcdUpdateFunc to EtcdHelper.AtomicUpdate to make an atomic etcd update.
// See the comment for AtomicUpdate for more detail.
type EtcdUpdateFunc func(input interface{}) (output interface{}, err error)
type EtcdUpdateFunc func(input runtime.Object) (output runtime.Object, err error)
// AtomicUpdate generalizes the pattern that allows for making atomic updates to etcd objects.
// Note, tryUpdate may be called more than once.
@@ -248,7 +236,7 @@ type EtcdUpdateFunc func(input interface{}) (output interface{}, err error)
// Example:
//
// h := &util.EtcdHelper{client, encoding, versioning}
// err := h.AtomicUpdate("myKey", &MyType{}, func(input interface{}) (interface{}, error) {
// err := h.AtomicUpdate("myKey", &MyType{}, func(input runtime.Object) (runtime.Object, error) {
// // Before this function is called, currentObj has been reset to etcd's current
// // contents for "myKey".
//
@@ -261,14 +249,14 @@ type EtcdUpdateFunc func(input interface{}) (output interface{}, err error)
// return cur, nil
// })
//
func (h *EtcdHelper) AtomicUpdate(key string, ptrToType interface{}, tryUpdate EtcdUpdateFunc) error {
func (h *EtcdHelper) AtomicUpdate(key string, ptrToType runtime.Object, tryUpdate EtcdUpdateFunc) error {
pt := reflect.TypeOf(ptrToType)
if pt.Kind() != reflect.Ptr {
// Panic is appropriate, because this is a programming error.
panic("need ptr to type")
}
for {
obj := reflect.New(pt.Elem()).Interface()
obj := reflect.New(pt.Elem()).Interface().(runtime.Object)
origBody, index, err := h.bodyAndExtractObj(key, obj, true)
if err != nil {
return err

View File

@@ -24,7 +24,6 @@ import (
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
@@ -40,15 +39,16 @@ type TestResource struct {
Value int `json:"value" yaml:"value,omitempty"`
}
var scheme *conversion.Scheme
var codec = runtime.Codec
var versioner = runtime.ResourceVersioner
func (*TestResource) IsAnAPIObject() {}
var scheme *runtime.Scheme
var codec = runtime.DefaultCodec
var versioner = runtime.DefaultResourceVersioner
func init() {
scheme = conversion.NewScheme()
scheme.ExternalVersion = "v1beta1"
scheme.AddKnownTypes("", TestResource{})
scheme.AddKnownTypes("v1beta1", TestResource{})
scheme = runtime.NewScheme("", "v1beta1")
scheme.AddKnownTypes("", &TestResource{})
scheme.AddKnownTypes("v1beta1", &TestResource{})
}
func TestIsEtcdNotFound(t *testing.T) {
@@ -166,7 +166,7 @@ func TestExtractObjNotFoundErr(t *testing.T) {
}
func TestSetObj(t *testing.T) {
obj := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
obj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
fakeClient := NewFakeEtcdClient(t)
helper := EtcdHelper{fakeClient, codec, versioner}
err := helper.SetObj("/some/key", obj)
@@ -191,7 +191,7 @@ func TestSetObjWithVersion(t *testing.T) {
fakeClient.Data["/some/key"] = EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(obj),
Value: runtime.DefaultScheme.EncodeOrDie(obj),
ModifiedIndex: 1,
},
},
@@ -214,7 +214,7 @@ func TestSetObjWithVersion(t *testing.T) {
}
func TestSetObjWithoutResourceVersioner(t *testing.T) {
obj := api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
obj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
fakeClient := NewFakeEtcdClient(t)
helper := EtcdHelper{fakeClient, codec, nil}
err := helper.SetObj("/some/key", obj)
@@ -241,7 +241,7 @@ func TestAtomicUpdate(t *testing.T) {
// Create a new node.
fakeClient.ExpectNotFoundGet("/some/key")
obj := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 1}
err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) {
err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in runtime.Object) (runtime.Object, error) {
return obj, nil
})
if err != nil {
@@ -260,7 +260,7 @@ func TestAtomicUpdate(t *testing.T) {
// Update an existing node.
callbackCalled := false
objUpdate := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 2}
err = helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) {
err = helper.AtomicUpdate("/some/key", &TestResource{}, func(in runtime.Object) (runtime.Object, error) {
callbackCalled = true
if in.(*TestResource).Value != 1 {
@@ -295,7 +295,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
// Create a new node.
fakeClient.ExpectNotFoundGet("/some/key")
obj := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 1}
err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) {
err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in runtime.Object) (runtime.Object, error) {
return obj, nil
})
if err != nil {
@@ -306,7 +306,7 @@ func TestAtomicUpdateNoChange(t *testing.T) {
callbackCalled := false
objUpdate := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 1}
fakeClient.Err = errors.New("should not be called")
err = helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) {
err = helper.AtomicUpdate("/some/key", &TestResource{}, func(in runtime.Object) (runtime.Object, error) {
callbackCalled = true
return objUpdate, nil
})
@@ -338,7 +338,7 @@ func TestAtomicUpdate_CreateCollision(t *testing.T) {
defer wgDone.Done()
firstCall := true
err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) {
err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in runtime.Object) (runtime.Object, error) {
defer func() { firstCall = false }()
if firstCall {
@@ -348,7 +348,7 @@ func TestAtomicUpdate_CreateCollision(t *testing.T) {
}
currValue := in.(*TestResource).Value
obj := TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: currValue + 1}
obj := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: currValue + 1}
return obj, nil
})
if err != nil {

View File

@@ -19,6 +19,7 @@ package tools
import (
"sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
"github.com/coreos/go-etcd/etcd"
@@ -27,10 +28,10 @@ import (
// FilterFunc is a predicate which takes an API object and returns true
// iff the object should remain in the set.
type FilterFunc func(obj interface{}) bool
type FilterFunc func(obj runtime.Object) bool
// Everything is a FilterFunc which accepts all objects.
func Everything(interface{}) bool {
func Everything(runtime.Object) bool {
return true
}
@@ -59,7 +60,7 @@ func (h *EtcdHelper) Watch(key string, resourceVersion uint64) (watch.Interface,
// change or wrap the serialized etcd object.
//
// startTime := time.Now()
// helper.WatchAndTransform(key, version, func(input interface{}) (interface{}, error) {
// helper.WatchAndTransform(key, version, func(input runtime.Object) (runtime.Object, error) {
// value := input.(TimeAwareValue)
// value.Since = startTime
// return value, nil
@@ -72,12 +73,12 @@ func (h *EtcdHelper) WatchAndTransform(key string, resourceVersion uint64, trans
}
// TransformFunc attempts to convert an object to another object for use with a watcher.
type TransformFunc func(interface{}) (interface{}, error)
type TransformFunc func(runtime.Object) (runtime.Object, error)
// etcdWatcher converts a native etcd watch to a watch.Interface.
type etcdWatcher struct {
encoding Codec
versioner ResourceVersioner
encoding runtime.Codec
versioner runtime.ResourceVersioner
transform TransformFunc
list bool // If we're doing a recursive watch, should be true.
@@ -98,7 +99,7 @@ type etcdWatcher struct {
// newEtcdWatcher returns a new etcdWatcher; if list is true, watch sub-nodes. If you provide a transform
// and a versioner, the versioner must be able to handle the objects that transform creates.
func newEtcdWatcher(list bool, filter FilterFunc, encoding Codec, versioner ResourceVersioner, transform TransformFunc) *etcdWatcher {
func newEtcdWatcher(list bool, filter FilterFunc, encoding runtime.Codec, versioner runtime.ResourceVersioner, transform TransformFunc) *etcdWatcher {
w := &etcdWatcher{
encoding: encoding,
versioner: versioner,
@@ -192,7 +193,7 @@ func (w *etcdWatcher) translate() {
}
}
func (w *etcdWatcher) decodeObject(data []byte, index uint64) (interface{}, error) {
func (w *etcdWatcher) decodeObject(data []byte, index uint64) (runtime.Object, error) {
obj, err := w.encoding.Decode(data)
if err != nil {
return nil, err
@@ -260,7 +261,7 @@ func (w *etcdWatcher) sendModify(res *etcd.Response) {
}
curObjPasses := w.filter(curObj)
oldObjPasses := false
var oldObj interface{}
var oldObj runtime.Object
if res.PrevNode != nil && res.PrevNode.Value != "" {
// Ignore problems reading the old object.
if oldObj, err = w.decodeObject([]byte(res.PrevNode.Value), res.PrevNode.ModifiedIndex); err == nil {

View File

@@ -33,7 +33,7 @@ func TestWatchInterpretations(t *testing.T) {
podFoo := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
podBar := &api.Pod{JSONBase: api.JSONBase{ID: "bar"}}
podBaz := &api.Pod{JSONBase: api.JSONBase{ID: "baz"}}
firstLetterIsB := func(obj interface{}) bool {
firstLetterIsB := func(obj runtime.Object) bool {
return obj.(*api.Pod).ID[0] == 'b'
}
@@ -44,66 +44,66 @@ func TestWatchInterpretations(t *testing.T) {
nodeValue string
expectEmit bool
expectType watch.EventType
expectObject interface{}
expectObject runtime.Object
}{
"create": {
actions: []string{"create", "get"},
nodeValue: runtime.EncodeOrDie(podBar),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true,
expectType: watch.Added,
expectObject: podBar,
},
"create but filter blocks": {
actions: []string{"create", "get"},
nodeValue: runtime.EncodeOrDie(podFoo),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: false,
},
"delete": {
actions: []string{"delete"},
prevNodeValue: runtime.EncodeOrDie(podBar),
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true,
expectType: watch.Deleted,
expectObject: podBar,
},
"delete but filter blocks": {
actions: []string{"delete"},
nodeValue: runtime.EncodeOrDie(podFoo),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: false,
},
"modify appears to create 1": {
actions: []string{"set", "compareAndSwap"},
nodeValue: runtime.EncodeOrDie(podBar),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true,
expectType: watch.Added,
expectObject: podBar,
},
"modify appears to create 2": {
actions: []string{"set", "compareAndSwap"},
prevNodeValue: runtime.EncodeOrDie(podFoo),
nodeValue: runtime.EncodeOrDie(podBar),
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true,
expectType: watch.Added,
expectObject: podBar,
},
"modify appears to delete": {
actions: []string{"set", "compareAndSwap"},
prevNodeValue: runtime.EncodeOrDie(podBar),
nodeValue: runtime.EncodeOrDie(podFoo),
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: true,
expectType: watch.Deleted,
expectObject: podBar, // Should return last state that passed the filter!
},
"modify modifies": {
actions: []string{"set", "compareAndSwap"},
prevNodeValue: runtime.EncodeOrDie(podBar),
nodeValue: runtime.EncodeOrDie(podBaz),
prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podBaz),
expectEmit: true,
expectType: watch.Modified,
expectObject: podBaz,
},
"modify ignores": {
actions: []string{"set", "compareAndSwap"},
nodeValue: runtime.EncodeOrDie(podFoo),
nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: false,
},
}
@@ -259,7 +259,7 @@ func TestWatchEtcdState(t *testing.T) {
{
Action: "create",
Node: &etcd.Node{
Value: string(runtime.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
},
},
},
@@ -273,12 +273,12 @@ func TestWatchEtcdState(t *testing.T) {
{
Action: "compareAndSwap",
Node: &etcd.Node{
Value: string(runtime.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
CreatedIndex: 1,
ModifiedIndex: 2,
},
PrevNode: &etcd.Node{
Value: string(runtime.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
CreatedIndex: 1,
ModifiedIndex: 1,
},
@@ -295,7 +295,7 @@ func TestWatchEtcdState(t *testing.T) {
R: &etcd.Response{
Action: "get",
Node: &etcd.Node{
Value: string(runtime.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
CreatedIndex: 1,
ModifiedIndex: 1,
},
@@ -308,12 +308,12 @@ func TestWatchEtcdState(t *testing.T) {
{
Action: "compareAndSwap",
Node: &etcd.Node{
Value: string(runtime.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{"127.0.0.1:9000"}})),
CreatedIndex: 1,
ModifiedIndex: 2,
},
PrevNode: &etcd.Node{
Value: string(runtime.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
Value: string(runtime.DefaultScheme.EncodeOrDie(&api.Endpoints{JSONBase: api.JSONBase{ID: "foo"}, Endpoints: []string{}})),
CreatedIndex: 1,
ModifiedIndex: 1,
},
@@ -370,7 +370,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(pod),
Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 1,
ModifiedIndex: 1,
},
@@ -385,7 +385,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(pod),
Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 1,
ModifiedIndex: 2,
},
@@ -443,13 +443,13 @@ func TestWatchListFromZeroIndex(t *testing.T) {
Dir: true,
Nodes: etcd.Nodes{
&etcd.Node{
Value: runtime.EncodeOrDie(pod),
Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 1,
ModifiedIndex: 1,
Nodes: etcd.Nodes{},
},
&etcd.Node{
Value: runtime.EncodeOrDie(pod),
Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 2,
ModifiedIndex: 2,
Nodes: etcd.Nodes{},

View File

@@ -24,6 +24,11 @@ type FilterFunc func(in Event) (out Event, keep bool)
// Putting a filter on a watch, as an unavoidable side-effect due to the way
// go channels work, effectively causes the watch's event channel to have its
// queue length increased by one.
//
// WARNING: filter has a fatal flaw, in that it can't properly update the
// Type field (Add/Modified/Deleted) to reflect items beginning to pass the
// filter when they previously didn't.
//
func Filter(w Interface, f FilterFunc) Interface {
fw := &filteredWatch{
incoming: w,

View File

@@ -23,16 +23,16 @@ import (
func TestFilter(t *testing.T) {
table := []Event{
{Added, "foo"},
{Added, "bar"},
{Added, "baz"},
{Added, "qux"},
{Added, "zoo"},
{Added, testType("foo")},
{Added, testType("bar")},
{Added, testType("baz")},
{Added, testType("qux")},
{Added, testType("zoo")},
}
source := NewFake()
filtered := Filter(source, func(e Event) (Event, bool) {
return e, e.Object.(string)[0] != 'b'
return e, e.Object.(testType)[0] != 'b'
})
go func() {
@@ -48,7 +48,7 @@ func TestFilter(t *testing.T) {
if !ok {
break
}
got = append(got, event.Object.(string))
got = append(got, string(event.Object.(testType)))
}
if e, a := []string{"foo", "qux", "zoo"}, got; !reflect.DeepEqual(e, a) {
@@ -59,11 +59,11 @@ func TestFilter(t *testing.T) {
func TestFilterStop(t *testing.T) {
source := NewFake()
filtered := Filter(source, func(e Event) (Event, bool) {
return e, e.Object.(string)[0] != 'b'
return e, e.Object.(testType)[0] != 'b'
})
go func() {
source.Add("foo")
source.Add(testType("foo"))
filtered.Stop()
}()
@@ -73,7 +73,7 @@ func TestFilterStop(t *testing.T) {
if !ok {
break
}
got = append(got, event.Object.(string))
got = append(got, string(event.Object.(testType)))
}
if e, a := []string{"foo"}, got; !reflect.DeepEqual(e, a) {

View File

@@ -19,6 +19,7 @@ package watch
import (
"sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
@@ -27,7 +28,7 @@ type Decoder interface {
// Decode should return the type of event, the decoded object, or an error.
// An error will cause StreamWatcher to call Close(). Decode should block until
// it has data or an error occurs.
Decode() (action EventType, object interface{}, err error)
Decode() (action EventType, object runtime.Object, err error)
// Close should close the underlying io.Reader, signalling to the source of
// the stream that it is no longer being watched. Close() must cause any

View File

@@ -20,13 +20,15 @@ import (
"io"
"reflect"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
type fakeDecoder struct {
items chan Event
}
func (f fakeDecoder) Decode() (action EventType, object interface{}, err error) {
func (f fakeDecoder) Decode() (action EventType, object runtime.Object, err error) {
item, open := <-f.items
if !open {
return action, nil, io.EOF
@@ -40,7 +42,7 @@ func (f fakeDecoder) Close() {
func TestStreamWatcher(t *testing.T) {
table := []Event{
{Added, "foo"},
{Added, testType("foo")},
}
fd := fakeDecoder{make(chan Event, 5)}

View File

@@ -18,6 +18,8 @@ package watch
import (
"sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
// Mux distributes event notifications among any number of watchers. Every event
@@ -88,7 +90,7 @@ func (m *Mux) closeAll() {
}
// Action distributes the given event among all watchers.
func (m *Mux) Action(action EventType, obj interface{}) {
func (m *Mux) Action(action EventType, obj runtime.Object) {
m.incoming <- Event{action, obj}
}

View File

@@ -22,16 +22,19 @@ import (
"testing"
)
type myType struct {
ID string
Value string
}
func (*myType) IsAnAPIObject() {}
func TestMux(t *testing.T) {
type myType struct {
ID string
Value string
}
table := []Event{
{Added, myType{"foo", "hello world 1"}},
{Added, myType{"bar", "hello world 2"}},
{Modified, myType{"foo", "goodbye world 3"}},
{Deleted, myType{"bar", "hello world 4"}},
{Added, &myType{"foo", "hello world 1"}},
{Added, &myType{"bar", "hello world 2"}},
{Modified, &myType{"foo", "goodbye world 3"}},
{Deleted, &myType{"bar", "hello world 4"}},
}
// The mux we're testing

View File

@@ -18,6 +18,8 @@ package watch
import (
"sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
// Interface can be implemented by anything that knows how to watch and report changes.
@@ -47,7 +49,7 @@ type Event struct {
// If Type == Deleted, then this is the state of the object
// immediately before deletion.
Object interface{}
Object runtime.Object
}
// FakeWatcher lets you test anything that consumes a watch.Interface; threadsafe.
@@ -78,21 +80,21 @@ func (f *FakeWatcher) ResultChan() <-chan Event {
}
// Add sends an add event.
func (f *FakeWatcher) Add(obj interface{}) {
func (f *FakeWatcher) Add(obj runtime.Object) {
f.result <- Event{Added, obj}
}
// Modify sends a modify event.
func (f *FakeWatcher) Modify(obj interface{}) {
func (f *FakeWatcher) Modify(obj runtime.Object) {
f.result <- Event{Modified, obj}
}
// Delete sends a delete event.
func (f *FakeWatcher) Delete(lastValue interface{}) {
func (f *FakeWatcher) Delete(lastValue runtime.Object) {
f.result <- Event{Deleted, lastValue}
}
// Action sends an event of the requested type, for table-based testing.
func (f *FakeWatcher) Action(action EventType, obj interface{}) {
func (f *FakeWatcher) Action(action EventType, obj runtime.Object) {
f.result <- Event{action, obj}
}

View File

@@ -20,17 +20,21 @@ import (
"testing"
)
type testType string
func (testType) IsAnAPIObject() {}
func TestFake(t *testing.T) {
f := NewFake()
table := []struct {
t EventType
s string
s testType
}{
{Added, "foo"},
{Modified, "qux"},
{Modified, "bar"},
{Deleted, "bar"},
{Added, testType("foo")},
{Modified, testType("qux")},
{Modified, testType("bar")},
{Deleted, testType("bar")},
}
// Prove that f implements Interface by phrasing this as a function.
@@ -43,7 +47,7 @@ func TestFake(t *testing.T) {
if e, a := expect.t, got.Type; e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
if a, ok := got.Object.(string); !ok || a != expect.s {
if a, ok := got.Object.(testType); !ok || a != expect.s {
t.Fatalf("Expected %v, got %v", expect.s, a)
}
}
@@ -54,10 +58,10 @@ func TestFake(t *testing.T) {
}
sender := func() {
f.Add("foo")
f.Action(Modified, "qux")
f.Modify("bar")
f.Delete("bar")
f.Add(testType("foo"))
f.Action(Modified, testType("qux"))
f.Modify(testType("bar"))
f.Delete(testType("bar"))
f.Stop()
}

View File

@@ -113,7 +113,7 @@ func TestPollMinions(t *testing.T) {
ml := &api.MinionList{Items: item.minions}
handler := util.FakeHandler{
StatusCode: 200,
ResponseBody: runtime.EncodeOrDie(ml),
ResponseBody: runtime.DefaultScheme.EncodeOrDie(ml),
T: t,
}
mux := http.NewServeMux()
@@ -140,7 +140,7 @@ func TestDefaultErrorFunc(t *testing.T) {
testPod := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
handler := util.FakeHandler{
StatusCode: 200,
ResponseBody: runtime.EncodeOrDie(testPod),
ResponseBody: runtime.DefaultScheme.EncodeOrDie(testPod),
T: t,
}
mux := http.NewServeMux()
@@ -259,7 +259,7 @@ func TestBind(t *testing.T) {
t.Errorf("Unexpected error: %v", err)
continue
}
expectedBody := runtime.EncodeOrDie(item.binding)
expectedBody := runtime.DefaultScheme.EncodeOrDie(item.binding)
handler.ValidateRequest(t, "/api/v1beta1/bindings", "POST", &expectedBody)
}
}

View File

@@ -62,7 +62,7 @@ func TestClient(t *testing.T) {
}
// get a validation error
pod := api.Pod{
pod := &api.Pod{
DesiredState: api.PodState{
Manifest: api.ContainerManifest{
Version: "v1beta2",

View File

@@ -33,17 +33,22 @@ func init() {
type stringCodec struct{}
func (c stringCodec) Encode(obj interface{}) ([]byte, error) {
return []byte(obj.(string)), nil
type fakeAPIObject string
func (*fakeAPIObject) IsAnAPIObject() {}
func (c stringCodec) Encode(obj runtime.Object) ([]byte, error) {
return []byte(*obj.(*fakeAPIObject)), nil
}
func (c stringCodec) Decode(data []byte) (interface{}, error) {
return string(data), nil
func (c stringCodec) Decode(data []byte) (runtime.Object, error) {
o := fakeAPIObject(data)
return &o, nil
}
func (c stringCodec) DecodeInto(data []byte, obj interface{}) error {
o := obj.(*string)
*o = string(data)
func (c stringCodec) DecodeInto(data []byte, obj runtime.Object) error {
o := obj.(*fakeAPIObject)
*o = fakeAPIObject(data)
return nil
}
@@ -51,7 +56,8 @@ func TestSetObj(t *testing.T) {
client := newEtcdClient()
helper := tools.EtcdHelper{Client: client, Codec: stringCodec{}}
withEtcdKey(func(key string) {
if err := helper.SetObj(key, "object"); err != nil {
fakeObject := fakeAPIObject("object")
if err := helper.SetObj(key, &fakeObject); err != nil {
t.Fatalf("unexpected error: %v", err)
}
resp, err := client.Get(key, false, false)
@@ -72,7 +78,7 @@ func TestExtractObj(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
s := ""
s := fakeAPIObject("")
if err := helper.ExtractObj(key, &s, false); err != nil {
t.Fatalf("unexpected error: %v", err)
}
@@ -84,9 +90,9 @@ func TestExtractObj(t *testing.T) {
func TestWatch(t *testing.T) {
client := newEtcdClient()
helper := tools.EtcdHelper{Client: client, Codec: runtime.Codec, ResourceVersioner: runtime.ResourceVersioner}
helper := tools.EtcdHelper{Client: client, Codec: runtime.DefaultCodec, ResourceVersioner: runtime.DefaultResourceVersioner}
withEtcdKey(func(key string) {
resp, err := client.Set(key, runtime.EncodeOrDie(api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
resp, err := client.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}