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") 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.Fatalf("Unexpected error: %#v", err)
} }
glog.Infof("Done creating replication controllers") glog.Infof("Done creating replication controllers")
@@ -194,7 +194,7 @@ func runReplicationControllerTest(c *client.Client) {
if err != nil { if err != nil {
glog.Fatalf("FAILED: unable to get pods to list: %v", err) 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) glog.Fatalf("FAILED: pods never started running %v", err)
} }
@@ -204,7 +204,7 @@ func runReplicationControllerTest(c *client.Client) {
func runAtomicPutTest(c *client.Client) { func runAtomicPutTest(c *client.Client) {
var svc api.Service var svc api.Service
err := c.Post().Path("services").Body( err := c.Post().Path("services").Body(
api.Service{ &api.Service{
JSONBase: api.JSONBase{ID: "atomicservice", APIVersion: "v1beta1"}, JSONBase: api.JSONBase{ID: "atomicservice", APIVersion: "v1beta1"},
Port: 12345, Port: 12345,
Labels: map[string]string{ 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.") 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{}{ var parser = kubecfg.NewParser(map[string]runtime.Object{
"pods": api.Pod{}, "pods": &api.Pod{},
"services": api.Service{}, "services": &api.Service{},
"replicationControllers": api.ReplicationController{}, "replicationControllers": &api.ReplicationController{},
"minions": api.Minion{}, "minions": &api.Minion{},
}) })
func usage() { func usage() {
@@ -266,7 +266,7 @@ func executeAPIRequest(method string, c *client.Client) bool {
if setBody { if setBody {
if version != 0 { if version != 0 {
data := readConfig(storage) data := readConfig(storage)
obj, err := runtime.Decode(data) obj, err := runtime.DefaultCodec.Decode(data)
if err != nil { if err != nil {
glog.Fatalf("error setting resource version: %v", err) 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) glog.Fatalf("error setting resource version: %v", err)
} }
jsonBase.SetResourceVersion(version) jsonBase.SetResourceVersion(version)
data, err = runtime.Encode(obj) data, err = runtime.DefaultCodec.Encode(obj)
if err != nil { if err != nil {
glog.Fatalf("error setting resource version: %v", err) glog.Fatalf("error setting resource version: %v", err)
} }

View File

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

View File

@@ -21,21 +21,21 @@ import (
) )
func init() { func init() {
runtime.AddKnownTypes("", runtime.DefaultScheme.AddKnownTypes("",
PodList{}, &PodList{},
Pod{}, &Pod{},
ReplicationControllerList{}, &ReplicationControllerList{},
ReplicationController{}, &ReplicationController{},
ServiceList{}, &ServiceList{},
Service{}, &Service{},
MinionList{}, &MinionList{},
Minion{}, &Minion{},
Status{}, &Status{},
ServerOpList{}, &ServerOpList{},
ServerOp{}, &ServerOp{},
ContainerManifestList{}, &ContainerManifestList{},
Endpoints{}, &Endpoints{},
EndpointsList{}, &EndpointsList{},
Binding{}, &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) ab, err := json.Marshal(a)
if err != nil { if err != nil {
panic("a") 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() name := reflect.TypeOf(source).Elem().Name()
apiObjectFuzzer.Fuzz(source) apiObjectFuzzer.Fuzz(source)
j, err := runtime.FindJSONBase(source) j, err := runtime.FindJSONBase(source)
@@ -115,13 +115,13 @@ func runTest(t *testing.T, source interface{}) {
j.SetKind("") j.SetKind("")
j.SetAPIVersion("") j.SetAPIVersion("")
data, err := runtime.Encode(source) data, err := runtime.DefaultCodec.Encode(source)
if err != nil { if err != nil {
t.Errorf("%v: %v (%#v)", name, err, source) t.Errorf("%v: %v (%#v)", name, err, source)
return return
} }
obj2, err := runtime.Decode(data) obj2, err := runtime.DefaultCodec.Decode(data)
if err != nil { if err != nil {
t.Errorf("%v: %v", name, err) t.Errorf("%v: %v", name, err)
return return
@@ -131,8 +131,8 @@ func runTest(t *testing.T, source interface{}) {
return return
} }
} }
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface() obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface().(runtime.Object)
err = runtime.DecodeInto(data, obj3) err = runtime.DefaultCodec.DecodeInto(data, obj3)
if err != nil { if err != nil {
t.Errorf("2: %v: %v", name, err) t.Errorf("2: %v: %v", name, err)
return return
@@ -145,7 +145,7 @@ func runTest(t *testing.T, source interface{}) {
} }
func TestTypes(t *testing.T) { func TestTypes(t *testing.T) {
table := []interface{}{ table := []runtime.Object{
&api.PodList{}, &api.PodList{},
&api.Pod{}, &api.Pod{},
&api.ServiceList{}, &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) { func TestEncode_Ptr(t *testing.T) {
pod := &api.Pod{ pod := &api.Pod{
Labels: map[string]string{"name": "foo"}, Labels: map[string]string{"name": "foo"},
} }
obj := interface{}(pod) obj := runtime.Object(pod)
data, err := runtime.Encode(obj) data, err := runtime.DefaultCodec.Encode(obj)
obj2, err2 := runtime.Decode(data) obj2, err2 := runtime.DefaultCodec.Decode(data)
if err != nil || err2 != nil { if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2) t.Fatalf("Failure: '%v' '%v'", err, err2)
} }
@@ -207,11 +189,11 @@ func TestEncode_Ptr(t *testing.T) {
func TestBadJSONRejection(t *testing.T) { func TestBadJSONRejection(t *testing.T) {
badJSONMissingKind := []byte(`{ }`) 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) t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
} }
badJSONUnknownType := []byte(`{"kind": "bar"}`) 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) t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
} }
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`) /*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)

View File

@@ -65,6 +65,8 @@ type ContainerManifestList struct {
Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"` 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. // Volume represents a named volume in a pod that may be accessed by any containers in the pod.
type Volume struct { type Volume struct {
// Required: This must be a DNS_LABEL. Each volume in a pod must have // 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"` 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). // Pod is a collection of containers, used as either input (create, update) or as output (list, get).
type Pod struct { type Pod struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
@@ -295,6 +299,8 @@ type Pod struct {
CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"` CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"`
} }
func (*Pod) IsAnAPIObject() {}
// ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get). // ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get).
type ReplicationControllerState struct { type ReplicationControllerState struct {
Replicas int `json:"replicas" yaml:"replicas"` Replicas int `json:"replicas" yaml:"replicas"`
@@ -308,6 +314,8 @@ type ReplicationControllerList struct {
Items []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"` Items []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"`
} }
func (*ReplicationControllerList) IsAnAPIObject() {}
// ReplicationController represents the configuration of a replication controller. // ReplicationController represents the configuration of a replication controller.
type ReplicationController struct { type ReplicationController struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
@@ -315,6 +323,8 @@ type ReplicationController struct {
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
} }
func (*ReplicationController) IsAnAPIObject() {}
// PodTemplate holds the information used for creating pods. // PodTemplate holds the information used for creating pods.
type PodTemplate struct { type PodTemplate struct {
DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
@@ -327,6 +337,8 @@ type ServiceList struct {
Items []Service `json:"items" yaml:"items"` Items []Service `json:"items" yaml:"items"`
} }
func (*ServiceList) IsAnAPIObject() {}
// Service is a named abstraction of software service (for example, mysql) consisting of local port // 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 // (for example 3306) that the proxy listens on, and the selector that determines which pods
// will answer requests sent through the proxy. // will answer requests sent through the proxy.
@@ -346,6 +358,8 @@ type Service struct {
ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"` 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: // 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"] // Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"]
type Endpoints struct { type Endpoints struct {
@@ -353,12 +367,16 @@ type Endpoints struct {
Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty"` Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty"`
} }
func (*Endpoints) IsAnAPIObject() {}
// EndpointsList is a list of endpoints. // EndpointsList is a list of endpoints.
type EndpointsList struct { type EndpointsList struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
Items []Endpoints `json:"items,omitempty" yaml:"items,omitempty"` Items []Endpoints `json:"items,omitempty" yaml:"items,omitempty"`
} }
func (*EndpointsList) IsAnAPIObject() {}
// Minion is a worker node in Kubernetenes. // Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID. // The name of the minion according to etcd is in JSONBase.ID.
type Minion struct { type Minion struct {
@@ -367,12 +385,16 @@ type Minion struct {
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
} }
func (*Minion) IsAnAPIObject() {}
// MinionList is a list of minions. // MinionList is a list of minions.
type MinionList struct { type MinionList struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
Items []Minion `json:"items,omitempty" yaml:"items,omitempty"` Items []Minion `json:"items,omitempty" yaml:"items,omitempty"`
} }
func (*MinionList) IsAnAPIObject() {}
// Binding is written by a scheduler to cause a pod to be bound to a host. // Binding is written by a scheduler to cause a pod to be bound to a host.
type Binding struct { type Binding struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
@@ -380,6 +402,8 @@ type Binding struct {
Host string `json:"host" yaml:"host"` Host string `json:"host" yaml:"host"`
} }
func (*Binding) IsAnAPIObject() {}
// Status is a return value for calls that don't return other objects. // 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 // TODO: this could go in apiserver, but I'm including it here so clients needn't
// import both. // import both.
@@ -403,6 +427,8 @@ type Status struct {
Code int `json:"code,omitempty" yaml:"code,omitempty"` Code int `json:"code,omitempty" yaml:"code,omitempty"`
} }
func (*Status) IsAnAPIObject() {}
// StatusDetails is a set of additional properties that MAY be set by the // StatusDetails is a set of additional properties that MAY be set by the
// server to provide additional information about a response. The Reason // server to provide additional information about a response. The Reason
// field of a Status object defines what attributes will be set. Clients // field of a Status object defines what attributes will be set. Clients
@@ -539,12 +565,16 @@ type ServerOp struct {
JSONBase `yaml:",inline" json:",inline"` JSONBase `yaml:",inline" json:",inline"`
} }
func (*ServerOp) IsAnAPIObject() {}
// ServerOpList is a list of operations, as delivered to API clients. // ServerOpList is a list of operations, as delivered to API clients.
type ServerOpList struct { type ServerOpList struct {
JSONBase `yaml:",inline" json:",inline"` JSONBase `yaml:",inline" json:",inline"`
Items []ServerOp `yaml:"items,omitempty" json:"items,omitempty"` 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. // WatchEvent objects are streamed from the api server in response to a watch request.
type WatchEvent struct { type WatchEvent struct {
// The type of the watch event; added, modified, or deleted. // The type of the watch event; added, modified, or deleted.

View File

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

View File

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

View File

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

View File

@@ -65,6 +65,8 @@ type ContainerManifestList struct {
Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"` 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. // Volume represents a named volume in a pod that may be accessed by any containers in the pod.
type Volume struct { type Volume struct {
// Required: This must be a DNS_LABEL. Each volume in a pod must have // 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"` APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
} }
func (*JSONBase) IsAnAPIObject() {}
// PodStatus represents a status of a pod. // PodStatus represents a status of a pod.
type PodStatus string type PodStatus string
@@ -298,6 +302,8 @@ type PodList struct {
Items []Pod `json:"items" yaml:"items,omitempty"` 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). // Pod is a collection of containers, used as either input (create, update) or as output (list, get).
type Pod struct { type Pod struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
@@ -306,6 +312,8 @@ type Pod struct {
CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"` CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"`
} }
func (*Pod) IsAnAPIObject() {}
// ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get). // ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get).
type ReplicationControllerState struct { type ReplicationControllerState struct {
Replicas int `json:"replicas" yaml:"replicas"` Replicas int `json:"replicas" yaml:"replicas"`
@@ -319,6 +327,8 @@ type ReplicationControllerList struct {
Items []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"` Items []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"`
} }
func (*ReplicationControllerList) IsAnAPIObject() {}
// ReplicationController represents the configuration of a replication controller. // ReplicationController represents the configuration of a replication controller.
type ReplicationController struct { type ReplicationController struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
@@ -326,6 +336,8 @@ type ReplicationController struct {
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
} }
func (*ReplicationController) IsAnAPIObject() {}
// PodTemplate holds the information used for creating pods. // PodTemplate holds the information used for creating pods.
type PodTemplate struct { type PodTemplate struct {
DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
@@ -338,6 +350,8 @@ type ServiceList struct {
Items []Service `json:"items" yaml:"items"` Items []Service `json:"items" yaml:"items"`
} }
func (*ServiceList) IsAnAPIObject() {}
// Service is a named abstraction of software service (for example, mysql) consisting of local port // 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 // (for example 3306) that the proxy listens on, and the selector that determines which pods
// will answer requests sent through the proxy. // will answer requests sent through the proxy.
@@ -357,6 +371,8 @@ type Service struct {
ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"` 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: // 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"] // Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"]
type Endpoints struct { type Endpoints struct {
@@ -364,12 +380,16 @@ type Endpoints struct {
Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty"` Endpoints []string `json:"endpoints,omitempty" yaml:"endpoints,omitempty"`
} }
func (*Endpoints) IsAnAPIObject() {}
// EndpointsList is a list of endpoints. // EndpointsList is a list of endpoints.
type EndpointsList struct { type EndpointsList struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
Items []Endpoints `json:"items,omitempty" yaml:"items,omitempty"` Items []Endpoints `json:"items,omitempty" yaml:"items,omitempty"`
} }
func (*EndpointsList) IsAnAPIObject() {}
// Minion is a worker node in Kubernetenes. // Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID. // The name of the minion according to etcd is in JSONBase.ID.
type Minion struct { type Minion struct {
@@ -378,6 +398,8 @@ type Minion struct {
HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"` HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
} }
func (*Minion) IsAnAPIObject() {}
// MinionList is a list of minions. // MinionList is a list of minions.
type MinionList struct { type MinionList struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
@@ -387,6 +409,8 @@ type MinionList struct {
Items []Minion `json:"items,omitempty" yaml:"items,omitempty"` Items []Minion `json:"items,omitempty" yaml:"items,omitempty"`
} }
func (*MinionList) IsAnAPIObject() {}
// Binding is written by a scheduler to cause a pod to be bound to a host. // Binding is written by a scheduler to cause a pod to be bound to a host.
type Binding struct { type Binding struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
@@ -394,6 +418,8 @@ type Binding struct {
Host string `json:"host" yaml:"host"` Host string `json:"host" yaml:"host"`
} }
func (*Binding) IsAnAPIObject() {}
// Status is a return value for calls that don't return other objects. // 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 // TODO: this could go in apiserver, but I'm including it here so clients needn't
// import both. // import both.
@@ -417,6 +443,8 @@ type Status struct {
Code int `json:"code,omitempty" yaml:"code,omitempty"` Code int `json:"code,omitempty" yaml:"code,omitempty"`
} }
func (*Status) IsAnAPIObject() {}
// StatusDetails is a set of additional properties that MAY be set by the // StatusDetails is a set of additional properties that MAY be set by the
// server to provide additional information about a response. The Reason // server to provide additional information about a response. The Reason
// field of a Status object defines what attributes will be set. Clients // field of a Status object defines what attributes will be set. Clients
@@ -540,12 +568,16 @@ type ServerOp struct {
JSONBase `yaml:",inline" json:",inline"` JSONBase `yaml:",inline" json:",inline"`
} }
func (*ServerOp) IsAnAPIObject() {}
// ServerOpList is a list of operations, as delivered to API clients. // ServerOpList is a list of operations, as delivered to API clients.
type ServerOpList struct { type ServerOpList struct {
JSONBase `yaml:",inline" json:",inline"` JSONBase `yaml:",inline" json:",inline"`
Items []ServerOp `yaml:"items,omitempty" json:"items,omitempty"` 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. // WatchEvent objects are streamed from the api server in response to a watch request.
type WatchEvent struct { type WatchEvent struct {
// The type of the watch event; added, modified, or deleted. // 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/healthz"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version" "github.com/GoogleCloudPlatform/kubernetes/pkg/version"
"github.com/golang/glog" "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. // mux is an object that can register http handlers.
type mux interface { type mux interface {
Handle(pattern string, handler http.Handler) Handle(pattern string, handler http.Handler)
@@ -53,7 +47,7 @@ type defaultAPIServer struct {
// Handle returns a Handler function that expose the provided storage interfaces // Handle returns a Handler function that expose the provided storage interfaces
// as RESTful resources at prefix, serialized by codec, and also includes the support // as RESTful resources at prefix, serialized by codec, and also includes the support
// http resources. // 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) group := NewAPIGroup(storage, codec)
mux := http.NewServeMux() mux := http.NewServeMux()
@@ -78,7 +72,7 @@ type APIGroup struct {
// This is a helper method for registering multiple sets of REST handlers under different // This is a helper method for registering multiple sets of REST handlers under different
// prefixes onto a server. // prefixes onto a server.
// TODO: add multitype codec serialization // 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{ return &APIGroup{RESTHandler{
storage: storage, storage: storage,
codec: codec, codec: codec,
@@ -147,7 +141,7 @@ func handleVersion(w http.ResponseWriter, req *http.Request) {
} }
// writeJSON renders an object as JSON to the response. // 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) output, err := codec.Encode(object)
if err != nil { if err != nil {
errorJSON(err, codec, w) 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. // 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) status := errToAPIStatus(err)
writeJSON(status.Code, codec, status, w) writeJSON(status.Code, codec, status, w)
} }

View File

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

View File

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

View File

@@ -18,6 +18,7 @@ package apiserver
import ( import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "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. // Resources which are exported to the RESTful API of apiserver need to implement this interface.
type RESTStorage 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. // 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{}) // This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
New() interface{} New() runtime.Object
// List selects resources in the storage which match to the selector. // List selects resources in the storage which match to the selector.
// TODO: add field selector in addition to label 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. // 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 // 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. // 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. // Delete finds a resource in the storage and deletes it.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the // 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. // 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) Create(runtime.Object) (<-chan runtime.Object, error)
Update(interface{}) (<-chan interface{}, error) Update(runtime.Object) (<-chan runtime.Object, error)
} }
// ResourceWatcher should be implemented by all RESTStorage objects that // ResourceWatcher should be implemented by all RESTStorage objects that

View File

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

View File

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

View File

@@ -20,11 +20,12 @@ import (
"net/http" "net/http"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
) )
type RedirectHandler struct { type RedirectHandler struct {
storage map[string]RESTStorage storage map[string]RESTStorage
codec Codec codec runtime.Codec
} }
func (r *RedirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 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/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
) )
type RESTHandler struct { type RESTHandler struct {
storage map[string]RESTStorage storage map[string]RESTStorage
codec Codec codec runtime.Codec
ops *Operations ops *Operations
asyncOpWait time.Duration 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. // 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) op := h.ops.NewOperation(out)
if sync { if sync {
op.WaitFor(timeout) op.WaitFor(timeout)
@@ -175,11 +176,6 @@ func (h *RESTHandler) finishReq(op *Operation, w http.ResponseWriter) {
if complete { if complete {
status := http.StatusOK status := http.StatusOK
switch stat := obj.(type) { 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: case *api.Status:
if stat.Code != 0 { if stat.Code != 0 {
status = stat.Code status = stat.Code

View File

@@ -32,7 +32,7 @@ import (
type WatchHandler struct { type WatchHandler struct {
storage map[string]RESTStorage storage map[string]RESTStorage
codec Codec codec runtime.Codec
} }
func getWatchParams(query url.Values) (label, field labels.Selector, resourceVersion uint64) { 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" "code.google.com/p/go.net/websocket"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
) )
var watchTestTable = []struct { var watchTestTable = []struct {
t watch.EventType t watch.EventType
obj interface{} obj runtime.Object
}{ }{
{watch.Added, &Simple{Name: "A Name"}}, {watch.Added, &Simple{Name: "A Name"}},
{watch.Modified, &Simple{Name: "Another Name"}}, {watch.Modified, &Simple{Name: "Another Name"}},
@@ -56,7 +57,7 @@ func TestWatchWebsocket(t *testing.T) {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
try := func(action watch.EventType, object interface{}) { try := func(action watch.EventType, object runtime.Object) {
// Send // Send
simpleStorage.fakeWatch.Action(action, object) simpleStorage.fakeWatch.Action(action, object)
// Test receive // Test receive
@@ -113,7 +114,7 @@ func TestWatchHTTP(t *testing.T) {
decoder := json.NewDecoder(response.Body) decoder := json.NewDecoder(response.Body)
try := func(action watch.EventType, object interface{}) { try := func(action watch.EventType, object runtime.Object) {
// Send // Send
simpleStorage.fakeWatch.Action(action, object) simpleStorage.fakeWatch.Action(action, object)
// Test receive // Test receive

View File

@@ -46,36 +46,36 @@ type Interface interface {
// PodInterface has methods to work with Pod resources. // PodInterface has methods to work with Pod resources.
type PodInterface interface { type PodInterface interface {
ListPods(selector labels.Selector) (api.PodList, error) ListPods(selector labels.Selector) (*api.PodList, error)
GetPod(id string) (api.Pod, error) GetPod(id string) (*api.Pod, error)
DeletePod(id string) error DeletePod(id string) error
CreatePod(api.Pod) (api.Pod, error) CreatePod(*api.Pod) (*api.Pod, error)
UpdatePod(api.Pod) (api.Pod, error) UpdatePod(*api.Pod) (*api.Pod, error)
} }
// ReplicationControllerInterface has methods to work with ReplicationController resources. // ReplicationControllerInterface has methods to work with ReplicationController resources.
type ReplicationControllerInterface interface { type ReplicationControllerInterface interface {
ListReplicationControllers(selector labels.Selector) (api.ReplicationControllerList, error) ListReplicationControllers(selector labels.Selector) (*api.ReplicationControllerList, error)
GetReplicationController(id string) (api.ReplicationController, error) GetReplicationController(id string) (*api.ReplicationController, error)
CreateReplicationController(api.ReplicationController) (api.ReplicationController, error) CreateReplicationController(*api.ReplicationController) (*api.ReplicationController, error)
UpdateReplicationController(api.ReplicationController) (api.ReplicationController, error) UpdateReplicationController(*api.ReplicationController) (*api.ReplicationController, error)
DeleteReplicationController(string) error DeleteReplicationController(string) error
WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
} }
// ServiceInterface has methods to work with Service resources. // ServiceInterface has methods to work with Service resources.
type ServiceInterface interface { type ServiceInterface interface {
ListServices(selector labels.Selector) (api.ServiceList, error) ListServices(selector labels.Selector) (*api.ServiceList, error)
GetService(id string) (api.Service, error) GetService(id string) (*api.Service, error)
CreateService(api.Service) (api.Service, error) CreateService(*api.Service) (*api.Service, error)
UpdateService(api.Service) (api.Service, error) UpdateService(*api.Service) (*api.Service, error)
DeleteService(string) error DeleteService(string) error
WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
} }
// EndpointsInterface has methods to work with Endpoints resources // EndpointsInterface has methods to work with Endpoints resources
type EndpointsInterface interface { 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) WatchEndpoints(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
} }
@@ -85,7 +85,7 @@ type VersionInterface interface {
} }
type MinionInterface interface { type MinionInterface interface {
ListMinions() (api.MinionList, error) ListMinions() (*api.MinionList, error)
} }
// Client is the actual implementation of a Kubernetes client. // 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? // Did the server give us a status response?
isStatusResponse := false isStatusResponse := false
var status api.Status 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 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. // 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) { func (c *Client) ListPods(selector labels.Selector) (result *api.PodList, err error) {
err = c.Get().Path("pods").SelectorParam("labels", selector).Do().Into(&result) result = &api.PodList{}
err = c.Get().Path("pods").SelectorParam("labels", selector).Do().Into(result)
return return
} }
// GetPod takes the id of the pod, and returns the corresponding Pod object, and an error if it occurs // 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) { func (c *Client) GetPod(id string) (result *api.Pod, err error) {
err = c.Get().Path("pods").Path(id).Do().Into(&result) result = &api.Pod{}
err = c.Get().Path("pods").Path(id).Do().Into(result)
return 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. // 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) { func (c *Client) CreatePod(pod *api.Pod) (result *api.Pod, err error) {
err = c.Post().Path("pods").Body(pod).Do().Into(&result) result = &api.Pod{}
err = c.Post().Path("pods").Body(pod).Do().Into(result)
return return
} }
// UpdatePod takes the representation of a pod to update. Returns the server's representation of the pod, and an error, if it occurs. // 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 { if pod.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", pod) err = fmt.Errorf("invalid update object, missing resource version: %v", pod)
return 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 return
} }
// ListReplicationControllers takes a selector, and returns the list of replication controllers that match that selector. // 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) { func (c *Client) ListReplicationControllers(selector labels.Selector) (result *api.ReplicationControllerList, err error) {
err = c.Get().Path("replicationControllers").SelectorParam("labels", selector).Do().Into(&result) result = &api.ReplicationControllerList{}
err = c.Get().Path("replicationControllers").SelectorParam("labels", selector).Do().Into(result)
return return
} }
// GetReplicationController returns information about a particular replication controller. // GetReplicationController returns information about a particular replication controller.
func (c *Client) GetReplicationController(id string) (result api.ReplicationController, err error) { func (c *Client) GetReplicationController(id string) (result *api.ReplicationController, err error) {
err = c.Get().Path("replicationControllers").Path(id).Do().Into(&result) result = &api.ReplicationController{}
err = c.Get().Path("replicationControllers").Path(id).Do().Into(result)
return return
} }
// CreateReplicationController creates a new replication controller. // CreateReplicationController creates a new replication controller.
func (c *Client) CreateReplicationController(controller api.ReplicationController) (result api.ReplicationController, err error) { func (c *Client) CreateReplicationController(controller *api.ReplicationController) (result *api.ReplicationController, err error) {
err = c.Post().Path("replicationControllers").Body(controller).Do().Into(&result) result = &api.ReplicationController{}
err = c.Post().Path("replicationControllers").Body(controller).Do().Into(result)
return return
} }
// UpdateReplicationController updates an existing replication controller. // 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 { if controller.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", controller) err = fmt.Errorf("invalid update object, missing resource version: %v", controller)
return 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 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 // 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) { func (c *Client) ListServices(selector labels.Selector) (result *api.ServiceList, err error) {
err = c.Get().Path("services").SelectorParam("labels", selector).Do().Into(&result) result = &api.ServiceList{}
err = c.Get().Path("services").SelectorParam("labels", selector).Do().Into(result)
return return
} }
// GetService returns information about a particular service. // GetService returns information about a particular service.
func (c *Client) GetService(id string) (result api.Service, err error) { func (c *Client) GetService(id string) (result *api.Service, err error) {
err = c.Get().Path("services").Path(id).Do().Into(&result) result = &api.Service{}
err = c.Get().Path("services").Path(id).Do().Into(result)
return return
} }
// CreateService creates a new service. // CreateService creates a new service.
func (c *Client) CreateService(svc api.Service) (result api.Service, err error) { func (c *Client) CreateService(svc *api.Service) (result *api.Service, err error) {
err = c.Post().Path("services").Body(svc).Do().Into(&result) result = &api.Service{}
err = c.Post().Path("services").Body(svc).Do().Into(result)
return return
} }
// UpdateService updates an existing service. // 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 { if svc.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", svc) err = fmt.Errorf("invalid update object, missing resource version: %v", svc)
return 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 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 // 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) { func (c *Client) ListEndpoints(selector labels.Selector) (result *api.EndpointsList, err error) {
err = c.Get().Path("endpoints").SelectorParam("labels", selector).Do().Into(&result) result = &api.EndpointsList{}
err = c.Get().Path("endpoints").SelectorParam("labels", selector).Do().Into(result)
return return
} }
@@ -399,7 +412,8 @@ func (c *Client) ServerVersion() (*version.Info, error) {
} }
// ListMinions lists all the minions in the cluster. // ListMinions lists all the minions in the cluster.
func (c *Client) ListMinions() (minionList api.MinionList, err error) { func (c *Client) ListMinions() (result *api.MinionList, err error) {
err = c.Get().Path("minions").Do().Into(&minionList) result = &api.MinionList{}
err = c.Get().Path("minions").Do().Into(result)
return return
} }

View File

@@ -73,7 +73,7 @@ func TestValidatesHostParameter(t *testing.T) {
func TestListEmptyPods(t *testing.T) { func TestListEmptyPods(t *testing.T) {
c := &testClient{ c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods"}, 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()) podList, err := c.Setup().ListPods(labels.Everything())
c.Validate(t, podList, err) c.Validate(t, podList, err)
@@ -83,7 +83,7 @@ func TestListPods(t *testing.T) {
c := &testClient{ c := &testClient{
Request: testRequest{Method: "GET", Path: "/pods"}, Request: testRequest{Method: "GET", Path: "/pods"},
Response: Response{StatusCode: 200, Response: Response{StatusCode: 200,
Body: api.PodList{ Body: &api.PodList{
Items: []api.Pod{ Items: []api.Pod{
{ {
CurrentState: api.PodState{ 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"}}}, Request: testRequest{Method: "GET", Path: "/pods", Query: url.Values{"labels": []string{"foo=bar,name=baz"}}},
Response: Response{ Response: Response{
StatusCode: 200, StatusCode: 200,
Body: api.PodList{ Body: &api.PodList{
Items: []api.Pod{ Items: []api.Pod{
{ {
CurrentState: api.PodState{ CurrentState: api.PodState{
@@ -140,7 +140,7 @@ func TestGetPod(t *testing.T) {
Request: testRequest{Method: "GET", Path: "/pods/foo"}, Request: testRequest{Method: "GET", Path: "/pods/foo"},
Response: Response{ Response: Response{
StatusCode: 200, StatusCode: 200,
Body: api.Pod{ Body: &api.Pod{
CurrentState: api.PodState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
}, },
@@ -165,7 +165,7 @@ func TestDeletePod(t *testing.T) {
} }
func TestCreatePod(t *testing.T) { func TestCreatePod(t *testing.T) {
requestPod := api.Pod{ requestPod := &api.Pod{
CurrentState: api.PodState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
}, },
@@ -186,7 +186,7 @@ func TestCreatePod(t *testing.T) {
} }
func TestUpdatePod(t *testing.T) { func TestUpdatePod(t *testing.T) {
requestPod := api.Pod{ requestPod := &api.Pod{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1}, JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1},
CurrentState: api.PodState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
@@ -208,7 +208,7 @@ func TestListControllers(t *testing.T) {
c := &testClient{ c := &testClient{
Request: testRequest{Method: "GET", Path: "/replicationControllers"}, Request: testRequest{Method: "GET", Path: "/replicationControllers"},
Response: Response{StatusCode: 200, Response: Response{StatusCode: 200,
Body: api.ReplicationControllerList{ Body: &api.ReplicationControllerList{
Items: []api.ReplicationController{ Items: []api.ReplicationController{
{ {
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
@@ -234,7 +234,7 @@ func TestGetController(t *testing.T) {
Request: testRequest{Method: "GET", Path: "/replicationControllers/foo"}, Request: testRequest{Method: "GET", Path: "/replicationControllers/foo"},
Response: Response{ Response: Response{
StatusCode: 200, StatusCode: 200,
Body: api.ReplicationController{ Body: &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.ReplicationControllerState{ DesiredState: api.ReplicationControllerState{
Replicas: 2, Replicas: 2,
@@ -251,14 +251,14 @@ func TestGetController(t *testing.T) {
} }
func TestUpdateController(t *testing.T) { func TestUpdateController(t *testing.T) {
requestController := api.ReplicationController{ requestController := &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1}, JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1},
} }
c := &testClient{ c := &testClient{
Request: testRequest{Method: "PUT", Path: "/replicationControllers/foo"}, Request: testRequest{Method: "PUT", Path: "/replicationControllers/foo"},
Response: Response{ Response: Response{
StatusCode: 200, StatusCode: 200,
Body: api.ReplicationController{ Body: &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.ReplicationControllerState{ DesiredState: api.ReplicationControllerState{
Replicas: 2, Replicas: 2,
@@ -284,14 +284,14 @@ func TestDeleteController(t *testing.T) {
} }
func TestCreateController(t *testing.T) { func TestCreateController(t *testing.T) {
requestController := api.ReplicationController{ requestController := &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
} }
c := &testClient{ c := &testClient{
Request: testRequest{Method: "POST", Path: "/replicationControllers", Body: requestController}, Request: testRequest{Method: "POST", Path: "/replicationControllers", Body: requestController},
Response: Response{ Response: Response{
StatusCode: 200, StatusCode: 200,
Body: api.ReplicationController{ Body: &api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.ReplicationControllerState{ DesiredState: api.ReplicationControllerState{
Replicas: 2, Replicas: 2,
@@ -307,9 +307,9 @@ func TestCreateController(t *testing.T) {
c.Validate(t, receivedController, err) c.Validate(t, receivedController, err)
} }
func body(obj interface{}, raw *string) *string { func body(obj runtime.Object, raw *string) *string {
if obj != nil { if obj != nil {
bs, _ := runtime.Encode(obj) bs, _ := runtime.DefaultCodec.Encode(obj)
body := string(bs) body := string(bs)
return &body return &body
} }
@@ -321,13 +321,13 @@ type testRequest struct {
Path string Path string
Header string Header string
Query url.Values Query url.Values
Body interface{} Body runtime.Object
RawBody *string RawBody *string
} }
type Response struct { type Response struct {
StatusCode int StatusCode int
Body interface{} Body runtime.Object
RawBody *string RawBody *string
} }
@@ -338,7 +338,6 @@ type testClient struct {
Error bool Error bool
server *httptest.Server server *httptest.Server
handler *util.FakeHandler handler *util.FakeHandler
Target interface{}
// For query args, an optional function to validate the contents // For query args, an optional function to validate the contents
// useful when the contents can change but still be correct. // useful when the contents can change but still be correct.
// Maps from query arg key to validator. // Maps from query arg key to validator.
@@ -363,7 +362,23 @@ func (c *testClient) Setup() *testClient {
return c 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() defer c.server.Close()
if c.Error { 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 { 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) 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) { func TestListServices(t *testing.T) {
c := &testClient{ c := &testClient{
Request: testRequest{Method: "GET", Path: "/services"}, Request: testRequest{Method: "GET", Path: "/services"},
Response: Response{StatusCode: 200, Response: Response{StatusCode: 200,
Body: api.ServiceList{ Body: &api.ServiceList{
Items: []api.Service{ Items: []api.Service{
{ {
JSONBase: api.JSONBase{ID: "name"}, JSONBase: api.JSONBase{ID: "name"},
@@ -435,7 +446,7 @@ func TestListServicesLabels(t *testing.T) {
c := &testClient{ c := &testClient{
Request: testRequest{Method: "GET", Path: "/services", Query: url.Values{"labels": []string{"foo=bar,name=baz"}}}, Request: testRequest{Method: "GET", Path: "/services", Query: url.Values{"labels": []string{"foo=bar,name=baz"}}},
Response: Response{StatusCode: 200, Response: Response{StatusCode: 200,
Body: api.ServiceList{ Body: &api.ServiceList{
Items: []api.Service{ Items: []api.Service{
{ {
JSONBase: api.JSONBase{ID: "name"}, 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: Response{StatusCode: 200, Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
} }
response, err := c.Setup().GetService("1") response, err := c.Setup().GetService("1")
c.Validate(t, &response, err) c.Validate(t, response, err)
} }
func TestCreateService(t *testing.T) { 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"}}}, 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"}}}, Response: Response{StatusCode: 200, Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
}).Setup() }).Setup()
response, err := c.Setup().CreateService(api.Service{JSONBase: api.JSONBase{ID: "service-1"}}) response, err := c.Setup().CreateService(&api.Service{JSONBase: api.JSONBase{ID: "service-1"}})
c.Validate(t, &response, err) c.Validate(t, response, err)
} }
func TestUpdateService(t *testing.T) { 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{ c := &testClient{
Request: testRequest{Method: "PUT", Path: "/services/service-1", Body: &svc}, Request: testRequest{Method: "PUT", Path: "/services/service-1", Body: svc},
Response: Response{StatusCode: 200, Body: &svc}, Response: Response{StatusCode: 200, Body: svc},
} }
response, err := c.Setup().UpdateService(svc) response, err := c.Setup().UpdateService(svc)
c.Validate(t, &response, err) c.Validate(t, response, err)
} }
func TestDeleteService(t *testing.T) { 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: 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}, {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: "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: "POST", Path: "faildecode"}, Response: Response{StatusCode: 200, RawBody: &invalid}},
{Request: testRequest{Method: "GET", Path: "failread"}, Response: Response{StatusCode: 200, RawBody: &invalid}, Target: &struct{}{}}, {Request: testRequest{Method: "GET", Path: "failread"}, Response: Response{StatusCode: 200, RawBody: &invalid}},
} }
for _, c := range testClients { for _, c := range testClients {
client := c.Setup() client := c.Setup()
@@ -516,13 +527,13 @@ func TestDoRequest(t *testing.T) {
URL: prefix, URL: prefix,
} }
response, err := client.doRequest(request) response, err := client.doRequest(request)
c.Validate(t, response, err) c.ValidateRaw(t, response, err)
} }
} }
func TestDoRequestAccepted(t *testing.T) { func TestDoRequestAccepted(t *testing.T) {
status := api.Status{Status: api.StatusWorking} status := &api.Status{Status: api.StatusWorking}
expectedBody, _ := runtime.Encode(status) expectedBody, _ := runtime.DefaultCodec.Encode(status)
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 202, StatusCode: 202,
ResponseBody: string(expectedBody), ResponseBody: string(expectedBody),
@@ -548,7 +559,7 @@ func TestDoRequestAccepted(t *testing.T) {
t.Errorf("Unexpected kind of error: %#v", err) t.Errorf("Unexpected kind of error: %#v", err)
return return
} }
if !reflect.DeepEqual(se.Status, status) { if !reflect.DeepEqual(&se.Status, status) {
t.Errorf("Unexpected status: %#v", se.Status) t.Errorf("Unexpected status: %#v", se.Status)
} }
if body != nil { if body != nil {
@@ -558,8 +569,8 @@ func TestDoRequestAccepted(t *testing.T) {
} }
func TestDoRequestAcceptedSuccess(t *testing.T) { func TestDoRequestAcceptedSuccess(t *testing.T) {
status := api.Status{Status: api.StatusSuccess} status := &api.Status{Status: api.StatusSuccess}
expectedBody, _ := runtime.Encode(status) expectedBody, _ := runtime.DefaultCodec.Encode(status)
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 202, StatusCode: 202,
ResponseBody: string(expectedBody), ResponseBody: string(expectedBody),
@@ -579,11 +590,11 @@ func TestDoRequestAcceptedSuccess(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Unexpected error %#v", err) t.Errorf("Unexpected error %#v", err)
} }
statusOut, err := runtime.Decode(body) statusOut, err := runtime.DefaultCodec.Decode(body)
if err != nil { if err != nil {
t.Errorf("Unexpected error %#v", err) 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) t.Errorf("Unexpected mis-match. Expected %#v. Saw %#v", status, statusOut)
} }
fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil) 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: Response{StatusCode: 200, Body: &api.MinionList{JSONBase: api.JSONBase{ID: "minion-1"}}},
} }
response, err := c.Setup().ListMinions() 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 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"}) 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}) 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 { func (c *Fake) DeletePod(name string) error {
@@ -57,34 +57,34 @@ func (c *Fake) DeletePod(name string) error {
return nil 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"}) 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}) 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"}) 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}) 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}) 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}) 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 { func (c *Fake) DeleteReplicationController(controller string) error {
@@ -97,24 +97,24 @@ func (c *Fake) WatchReplicationControllers(label, field labels.Selector, resourc
return c.Watch, nil 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"}) 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}) 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}) 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}) 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 { 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 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"}) 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) { 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 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}) 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 string, try to read a file of that name.
// If obj is a []byte, send it directly. // If obj is a []byte, send it directly.
// If obj is an io.Reader, use 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 { func (r *Request) Body(obj interface{}) *Request {
if r.err != nil { if r.err != nil {
return r return r
@@ -204,13 +205,15 @@ func (r *Request) Body(obj interface{}) *Request {
r.body = bytes.NewBuffer(t) r.body = bytes.NewBuffer(t)
case io.Reader: case io.Reader:
r.body = t r.body = t
default: case runtime.Object:
data, err := runtime.Encode(obj) data, err := runtime.DefaultCodec.Encode(t)
if err != nil { if err != nil {
r.err = err r.err = err
return r return r
} }
r.body = bytes.NewBuffer(data) r.body = bytes.NewBuffer(data)
default:
r.err = fmt.Errorf("Unknown type used for body: %#v", obj)
} }
return r return r
} }
@@ -314,19 +317,19 @@ func (r Result) Raw() ([]byte, error) {
} }
// Get returns the result as an object. // Get returns the result as an object.
func (r Result) Get() (interface{}, error) { func (r Result) Get() (runtime.Object, error) {
if r.err != nil { if r.err != nil {
return nil, r.err return nil, r.err
} }
return runtime.Decode(r.body) return runtime.DefaultCodec.Decode(r.body)
} }
// Into stores the result into obj, if possible. // 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 { if r.err != nil {
return r.err 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. // Error returns the error executing the request, nil if no error occurred.

View File

@@ -38,7 +38,7 @@ import (
func TestDoRequestNewWay(t *testing.T) { func TestDoRequestNewWay(t *testing.T) {
reqBody := "request body" reqBody := "request body"
expectedObj := &api.Service{Port: 12345} expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj) expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(expectedBody), ResponseBody: string(expectedBody),
@@ -71,9 +71,9 @@ func TestDoRequestNewWay(t *testing.T) {
func TestDoRequestNewWayReader(t *testing.T) { func TestDoRequestNewWayReader(t *testing.T) {
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}} reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
reqBodyExpected, _ := runtime.Encode(reqObj) reqBodyExpected, _ := runtime.DefaultCodec.Encode(reqObj)
expectedObj := &api.Service{Port: 12345} expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj) expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(expectedBody), ResponseBody: string(expectedBody),
@@ -108,9 +108,9 @@ func TestDoRequestNewWayReader(t *testing.T) {
func TestDoRequestNewWayObj(t *testing.T) { func TestDoRequestNewWayObj(t *testing.T) {
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}} reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
reqBodyExpected, _ := runtime.Encode(reqObj) reqBodyExpected, _ := runtime.DefaultCodec.Encode(reqObj)
expectedObj := &api.Service{Port: 12345} expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj) expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(expectedBody), ResponseBody: string(expectedBody),
@@ -144,7 +144,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
func TestDoRequestNewWayFile(t *testing.T) { func TestDoRequestNewWayFile(t *testing.T) {
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}} reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
reqBodyExpected, err := runtime.Encode(reqObj) reqBodyExpected, err := runtime.DefaultCodec.Encode(reqObj)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -160,7 +160,7 @@ func TestDoRequestNewWayFile(t *testing.T) {
} }
expectedObj := &api.Service{Port: 12345} expectedObj := &api.Service{Port: 12345}
expectedBody, _ := runtime.Encode(expectedObj) expectedBody, _ := runtime.DefaultCodec.Encode(expectedObj)
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(expectedBody), ResponseBody: string(expectedBody),
@@ -285,7 +285,7 @@ func TestSetPollPeriod(t *testing.T) {
} }
func TestPolling(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"}}, &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 callNumber := 0
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 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 { if err != nil {
t.Errorf("Unexpected encode error") t.Errorf("Unexpected encode error")
} }
@@ -380,7 +380,7 @@ func checkAuth(t *testing.T, expect AuthInfo, r *http.Request) {
func TestWatch(t *testing.T) { func TestWatch(t *testing.T) {
var table = []struct { var table = []struct {
t watch.EventType t watch.EventType
obj interface{} obj runtime.Object
}{ }{
{watch.Added, &api.Pod{JSONBase: api.JSONBase{ID: "first"}}}, {watch.Added, &api.Pod{JSONBase: api.JSONBase{ID: "first"}}},
{watch.Modified, &api.Pod{JSONBase: api.JSONBase{ID: "second"}}}, {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 { if labels != nil {
labels["replicationController"] = controllerSpec.ID labels["replicationController"] = controllerSpec.ID
} }
pod := api.Pod{ pod := &api.Pod{
DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState, DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState,
Labels: controllerSpec.DesiredState.PodTemplate.Labels, 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{} pods := []api.Pod{}
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
pods = append(pods, api.Pod{ pods = append(pods, api.Pod{
@@ -94,7 +94,7 @@ func newPodList(count int) api.PodList {
}, },
}) })
} }
return api.PodList{ return &api.PodList{
Items: pods, Items: pods,
} }
} }
@@ -109,7 +109,7 @@ func validateSyncReplication(t *testing.T, fakePodControl *FakePodControl, expec
} }
func TestSyncReplicationControllerDoesNothing(t *testing.T) { func TestSyncReplicationControllerDoesNothing(t *testing.T) {
body, _ := runtime.Encode(newPodList(2)) body, _ := runtime.DefaultCodec.Encode(newPodList(2))
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(body), ResponseBody: string(body),
@@ -129,7 +129,7 @@ func TestSyncReplicationControllerDoesNothing(t *testing.T) {
} }
func TestSyncReplicationControllerDeletes(t *testing.T) { func TestSyncReplicationControllerDeletes(t *testing.T) {
body, _ := runtime.Encode(newPodList(2)) body, _ := runtime.DefaultCodec.Encode(newPodList(2))
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(body), ResponseBody: string(body),
@@ -149,7 +149,7 @@ func TestSyncReplicationControllerDeletes(t *testing.T) {
} }
func TestSyncReplicationControllerCreates(t *testing.T) { func TestSyncReplicationControllerCreates(t *testing.T) {
body, _ := runtime.Encode(newPodList(0)) body, _ := runtime.DefaultCodec.Encode(newPodList(0))
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(body), ResponseBody: string(body),
@@ -169,7 +169,7 @@ func TestSyncReplicationControllerCreates(t *testing.T) {
} }
func TestCreateReplica(t *testing.T) { func TestCreateReplica(t *testing.T) {
body, _ := runtime.Encode(api.Pod{}) body, _ := runtime.DefaultCodec.Encode(&api.Pod{})
fakeHandler := util.FakeHandler{ fakeHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: string(body), ResponseBody: string(body),
@@ -292,7 +292,7 @@ func TestSyncronize(t *testing.T) {
} }
fakeControllerHandler := util.FakeHandler{ fakeControllerHandler := util.FakeHandler{
StatusCode: 200, StatusCode: 200,
ResponseBody: runtime.EncodeOrDie(&api.ReplicationControllerList{ ResponseBody: runtime.DefaultScheme.EncodeOrDie(&api.ReplicationControllerList{
Items: []api.ReplicationController{ Items: []api.ReplicationController{
controllerSpec1, controllerSpec1,
controllerSpec2, controllerSpec2,

View File

@@ -37,7 +37,7 @@ type Converter struct {
// do the conversion. // do the conversion.
funcs map[typePair]reflect.Value 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 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 // 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 // three parameters: a pointer to the input type, a pointer to the output type, and
// return an error. // a conversion.Scope (which should be used if recursive conversion calls are desired).
// It must return an error.
// //
// Example: // 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 { func (c *Converter) Register(conversionFunc interface{}) error {
fv := reflect.ValueOf(conversionFunc) fv := reflect.ValueOf(conversionFunc)
ft := fv.Type() ft := fv.Type()
if ft.Kind() != reflect.Func { if ft.Kind() != reflect.Func {
return fmt.Errorf("expected func, got: %v", ft) return fmt.Errorf("expected func, got: %v", ft)
} }
if ft.NumIn() != 2 { if ft.NumIn() != 3 {
return fmt.Errorf("expected two in params, got: %v", ft) return fmt.Errorf("expected three 'in' params, got: %v", ft)
} }
if ft.NumOut() != 1 { 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 { 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 { 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 var forErrorType error
// This convolution is necessary, otherwise TypeOf picks up on the fact // 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 { if c.Debug != nil {
c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt) 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 // This convolution is necssary because nil interfaces won't convert
// to errors. // to errors.
if ret == nil { if ret == nil {

View File

@@ -27,28 +27,30 @@ import (
func TestConverter_CallsRegisteredFunctions(t *testing.T) { func TestConverter_CallsRegisteredFunctions(t *testing.T) {
type A struct { type A struct {
Foo string Foo string
Baz int
} }
type B struct { type B struct {
Bar string Bar string
Baz int
} }
type C struct{} type C struct{}
c := NewConverter() 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 out.Bar = in.Foo
return nil return s.Convert(&in.Baz, &out.Baz, 0)
}) })
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) 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 out.Foo = in.Bar
return nil return s.Convert(&in.Baz, &out.Baz, 0)
}) })
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
x := A{"hello, intrepid test reader!"} x := A{"hello, intrepid test reader!", 3}
y := B{} y := B{}
err = c.Convert(&x, &y, 0) 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 { if e, a := x.Foo, y.Bar; e != a {
t.Errorf("expected %v, got %v", 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{} w := A{}
err = c.Convert(&z, &w, 0) 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 { if e, a := z.Bar, w.Foo; e != a {
t.Errorf("expected %v, got %v", 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") return fmt.Errorf("C can't store an A, silly")
}) })
if err != nil { if err != nil {
@@ -85,7 +93,7 @@ func TestConverter_CallsRegisteredFunctions(t *testing.T) {
func TestConverter_fuzz(t *testing.T) { func TestConverter_fuzz(t *testing.T) {
newAnonType := func() interface{} { 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. // Use the same types from the scheme test.
table := []struct { table := []struct {

View File

@@ -85,8 +85,8 @@ func NewScheme() *Scheme {
// AddKnownTypes registers all types passed in 'types' as being members of version 'version. // 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. // 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 // All objects passed to types should be pointers to structs. The name that go reports for
// reports for the struct becomes the "kind" field when encoding. // the struct becomes the "kind" field when encoding.
func (s *Scheme) AddKnownTypes(version string, types ...interface{}) { func (s *Scheme) AddKnownTypes(version string, types ...interface{}) {
knownTypes, found := s.versionMap[version] knownTypes, found := s.versionMap[version]
if !found { if !found {
@@ -95,8 +95,12 @@ func (s *Scheme) AddKnownTypes(version string, types ...interface{}) {
} }
for _, obj := range types { for _, obj := range types {
t := reflect.TypeOf(obj) 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 { if t.Kind() != reflect.Struct {
panic("All types must be structs.") panic("All types must be pointers to structs.")
} }
knownTypes[t.Name()] = t knownTypes[t.Name()] = t
s.typeToVersion[t] = version s.typeToVersion[t] = version

View File

@@ -90,7 +90,7 @@ func externalTypeReturn() interface{} {
O *TestType2 `yaml:"O,omitempty" json:"O,omitempty"` O *TestType2 `yaml:"O,omitempty" json:"O,omitempty"`
P []TestType2 `yaml:"Q,omitempty" json:"Q,omitempty"` P []TestType2 `yaml:"Q,omitempty" json:"Q,omitempty"`
} }
return TestType1{} return &TestType1{}
} }
type ExternalInternalSame struct { 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. // Returns a new Scheme set up with the test objects.
func GetTestScheme() *Scheme { func GetTestScheme() *Scheme {
s := NewScheme() s := NewScheme()
s.AddKnownTypes("", TestType1{}, ExternalInternalSame{}) s.AddKnownTypes("", &TestType1{}, &ExternalInternalSame{})
s.AddKnownTypes("v1", externalTypeReturn(), ExternalInternalSame{}) s.AddKnownTypes("v1", externalTypeReturn(), &ExternalInternalSame{})
s.ExternalVersion = "v1" s.ExternalVersion = "v1"
s.InternalVersion = "" s.InternalVersion = ""
s.MetaInsertionFactory = testMetaInsertionFactory{} s.MetaInsertionFactory = testMetaInsertionFactory{}

View File

@@ -27,6 +27,15 @@ import (
"github.com/golang/glog" "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. // NewEtcdMasterElector returns an implementation of election.MasterElector backed by etcd.
func NewEtcdMasterElector(h tools.EtcdGetSet) MasterElector { func NewEtcdMasterElector(h tools.EtcdGetSet) MasterElector {
return &etcdMasterElector{etcd: h} return &etcdMasterElector{etcd: h}
@@ -58,7 +67,7 @@ func (e *etcdMasterElector) run(path, id string) {
case m := <-masters: case m := <-masters:
e.events <- watch.Event{ e.events <- watch.Event{
Type: watch.Modified, Type: watch.Modified,
Object: m, Object: Master(m),
} }
case e := <-errors: case e := <-errors:
glog.Errorf("error in election: %v", e) glog.Errorf("error in election: %v", e)

View File

@@ -31,7 +31,7 @@ func TestEtcdMasterOther(t *testing.T) {
master := NewEtcdMasterElector(etcd) master := NewEtcdMasterElector(etcd)
w := master.Elect(path, "bar") w := master.Elect(path, "bar")
result := <-w.ResultChan() 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) t.Errorf("unexpected event: %#v", result)
} }
w.Stop() w.Stop()
@@ -52,7 +52,7 @@ func TestEtcdMasterNoOther(t *testing.T) {
master := NewEtcdMasterElector(e) master := NewEtcdMasterElector(e)
w := master.Elect(path, "bar") w := master.Elect(path, "bar")
result := <-w.ResultChan() 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) t.Errorf("unexpected event: %#v", result)
} }
w.Stop() w.Stop()
@@ -91,7 +91,7 @@ func TestEtcdMasterNoOtherThenConflict(t *testing.T) {
master := NewEtcdMasterElector(e) master := NewEtcdMasterElector(e)
w := master.Elect(path, "bar") w := master.Elect(path, "bar")
result := <-w.ResultChan() 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) t.Errorf("unexpected event: %#v", result)
} }
w.Stop() 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'. // 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 { func RunController(image, name string, replicas int, client client.Interface, portSpec string, servicePort int) error {
controller := api.ReplicationController{ controller := &api.ReplicationController{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: name, ID: name,
}, },
@@ -227,8 +227,8 @@ func RunController(image, name string, replicas int, client client.Interface, po
return nil return nil
} }
func createService(name string, port int, client client.Interface) (api.Service, error) { func createService(name string, port int, client client.Interface) (*api.Service, error) {
svc := api.Service{ svc := &api.Service{
JSONBase: api.JSONBase{ID: name}, JSONBase: api.JSONBase{ID: name},
Port: port, Port: port,
Labels: map[string]string{ Labels: map[string]string{

View File

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

View File

@@ -27,10 +27,11 @@ type Parser struct {
storageToType map[string]reflect.Type 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) typeMap := make(map[string]reflect.Type)
for name, obj := range objectMap { for name, obj := range objectMap {
typeMap[name] = reflect.TypeOf(obj) typeMap[name] = reflect.TypeOf(obj).Elem()
} }
return &Parser{typeMap} 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) return nil, fmt.Errorf("unknown storage type: %v", storage)
} }
obj := reflect.New(prototypeType).Interface() obj := reflect.New(prototypeType).Interface().(runtime.Object)
err := runtime.DecodeInto(data, obj) err := runtime.DefaultCodec.DecodeInto(data, obj)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return runtime.Encode(obj) return runtime.DefaultCodec.Encode(obj)
} }
func (p *Parser) SupportedWireStorage() []string { func (p *Parser) SupportedWireStorage() []string {

View File

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

View File

@@ -53,7 +53,7 @@ func (s *ProxyServer) Serve() error {
func (s *ProxyServer) doError(w http.ResponseWriter, err error) { func (s *ProxyServer) doError(w http.ResponseWriter, err error) {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Header().Add("Content-type", "application/json") w.Header().Add("Content-type", "application/json")
data, _ := runtime.Encode(api.Status{ data, _ := runtime.DefaultCodec.Encode(&api.Status{
Status: api.StatusFailure, Status: api.StatusFailure,
Message: fmt.Sprintf("internal error: %#v", err), Message: fmt.Sprintf("internal error: %#v", err),
}) })

View File

@@ -36,7 +36,7 @@ import (
type ResourcePrinter interface { type ResourcePrinter interface {
// Print receives an arbitrary JSON body, formats it and prints it to a writer. // Print receives an arbitrary JSON body, formats it and prints it to a writer.
Print([]byte, io.Writer) error 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. // 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. // 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 { func (i *IdentityPrinter) PrintObj(obj runtime.Object, output io.Writer) error {
data, err := runtime.Encode(obj) data, err := runtime.DefaultCodec.Encode(obj)
if err != nil { if err != nil {
return err return err
} }
@@ -75,7 +75,7 @@ func (y *YAMLPrinter) Print(data []byte, w io.Writer) error {
} }
// PrintObj prints the data as YAML. // 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) output, err := yaml.Marshal(obj)
if err != nil { if err != nil {
return err 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 // Print parses the data as JSON, then prints the parsed data in a human-friendly
// format according to the type of the data. // format according to the type of the data.
func (h *HumanReadablePrinter) Print(data []byte, output io.Writer) error { 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 { if err := json.Unmarshal([]byte(data), &mapObj); err != nil {
return err 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) 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 { if err != nil {
return err 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. // 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) w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0)
defer w.Flush() defer w.Flush()
if handler := h.handlerMap[reflect.TypeOf(obj)]; handler != nil { 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. // Print parses the data as JSON, and re-formats it with the Go Template.
func (t *TemplatePrinter) Print(data []byte, w io.Writer) error { func (t *TemplatePrinter) Print(data []byte, w io.Writer) error {
obj, err := runtime.Decode(data) obj, err := runtime.DefaultCodec.Decode(data)
if err != nil { if err != nil {
return err return err
} }
@@ -300,6 +300,6 @@ func (t *TemplatePrinter) Print(data []byte, w io.Writer) error {
} }
// PrintObj formats the obj with the Go Template. // 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) 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) 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"}, JSONBase: api.JSONBase{ID: "foo"},
} }
buf.Reset() buf.Reset()
@@ -77,8 +77,8 @@ func TestYAMLPrinterPrint(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Unexpeted error: %#v", err) 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) 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()) t.Errorf("Bytes are not equal: %s vs %s", str, buff.String())
} }
obj := api.Pod{ obj := &api.Pod{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
} }
buff.Reset() buff.Reset()
printer.PrintObj(obj, buff) printer.PrintObj(obj, buff)
objOut, err := runtime.Decode([]byte(buff.String())) objOut, err := runtime.DefaultCodec.Decode([]byte(buff.String()))
if err != nil { if err != nil {
t.Errorf("Unexpeted error: %#v", err) 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) t.Errorf("Unexpected inequality: %#v vs %#v", obj, objOut)
} }
} }
@@ -109,8 +109,12 @@ type TestPrintType struct {
Data string Data string
} }
func (*TestPrintType) IsAnAPIObject() {}
type TestUnknownType struct{} type TestUnknownType struct{}
func (*TestUnknownType) IsAnAPIObject() {}
func PrintCustomType(obj *TestPrintType, w io.Writer) error { func PrintCustomType(obj *TestPrintType, w io.Writer) error {
_, err := fmt.Fprintf(w, "%s", obj.Data) _, err := fmt.Fprintf(w, "%s", obj.Data)
return err return err

View File

@@ -47,8 +47,8 @@ type SourceEtcd struct {
func NewSourceEtcd(key string, client tools.EtcdClient, updates chan<- interface{}) *SourceEtcd { func NewSourceEtcd(key string, client tools.EtcdClient, updates chan<- interface{}) *SourceEtcd {
helper := tools.EtcdHelper{ helper := tools.EtcdHelper{
client, client,
runtime.Codec, runtime.DefaultCodec,
runtime.ResourceVersioner, runtime.DefaultResourceVersioner,
} }
source := &SourceEtcd{ source := &SourceEtcd{
key: key, 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. // 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) storage := make(map[string]apiserver.RESTStorage)
for k, v := range m.storage { for k, v := range m.storage {
storage[k] = v 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. // Watcher is the interface needed to receive changes to services and endpoints.
type Watcher interface { type Watcher interface {
ListServices(label labels.Selector) (api.ServiceList, error) ListServices(label labels.Selector) (*api.ServiceList, error)
ListEndpoints(label labels.Selector) (api.EndpointsList, error) ListEndpoints(label labels.Selector) (*api.EndpointsList, error)
WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error) WatchServices(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
WatchEndpoints(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. // and create a Service entry for it.
for i, node := range response.Node.Nodes { for i, node := range response.Node.Nodes {
var svc api.Service var svc api.Service
err = runtime.DecodeInto([]byte(node.Value), &svc) err = runtime.DefaultCodec.DecodeInto([]byte(node.Value), &svc)
if err != nil { if err != nil {
glog.Errorf("Failed to load Service: %s (%#v)", node.Value, err) glog.Errorf("Failed to load Service: %s (%#v)", node.Value, err)
continue continue
@@ -166,7 +166,7 @@ func (s ConfigSourceEtcd) GetEndpoints(service string) (api.Endpoints, error) {
} }
// Parse all the endpoint specifications in this value. // Parse all the endpoint specifications in this value.
var e api.Endpoints var e api.Endpoints
err = runtime.DecodeInto([]byte(response.Node.Value), &e) err = runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &e)
return e, err 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) return nil, fmt.Errorf("invalid response from etcd: %#v", response)
} }
var svc api.Service var svc api.Service
err := runtime.DecodeInto([]byte(response.Node.Value), &svc) err := runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &svc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -230,7 +230,7 @@ func (s ConfigSourceEtcd) ProcessChange(response *etcd.Response) {
func (s ConfigSourceEtcd) ProcessEndpointResponse(response *etcd.Response) { func (s ConfigSourceEtcd) ProcessEndpointResponse(response *etcd.Response) {
glog.Infof("Processing a change in endpoint configuration... %s", *response) glog.Infof("Processing a change in endpoint configuration... %s", *response)
var endpoints api.Endpoints var endpoints api.Endpoints
err := runtime.DecodeInto([]byte(response.Node.Value), &endpoints) err := runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &endpoints)
if err != nil { if err != nil {
glog.Errorf("Failed to parse service out of etcd key: %v : %+v", response.Node.Value, err) glog.Errorf("Failed to parse service out of etcd key: %v : %+v", response.Node.Value, err)
return return

View File

@@ -23,6 +23,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
) )
// BindingStorage implements the RESTStorage interface. When bindings are written, it // 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. // 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") return nil, errors.NewNotFound("binding", "list")
} }
// Get returns an error because bindings are write-only objects. // 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) return nil, errors.NewNotFound("binding", id)
} }
// Delete returns an error because bindings are write-only objects. // 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) return nil, errors.NewNotFound("binding", id)
} }
// New returns a new binding object fit for having data unmarshalled into it. // 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{} return &api.Binding{}
} }
// Create attempts to make the assignment indicated by the binding it recieves. // 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) binding, ok := obj.(*api.Binding)
if !ok { if !ok {
return nil, fmt.Errorf("incorrect type: %#v", obj) 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 { if err := b.registry.ApplyBinding(binding); err != nil {
return nil, err 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. // 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.") return nil, fmt.Errorf("Bindings may not be changed.")
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -27,5 +27,5 @@ type Registry interface {
ListEndpoints() (*api.EndpointsList, error) ListEndpoints() (*api.EndpointsList, error)
GetEndpoints(name string) (*api.Endpoints, error) GetEndpoints(name string) (*api.Endpoints, error)
WatchEndpoints(labels, fields labels.Selector, resourceVersion uint64) (watch.Interface, 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/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
) )
@@ -38,12 +39,12 @@ func NewStorage(registry Registry) apiserver.RESTStorage {
} }
// Get satisfies the RESTStorage interface. // 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) return rs.registry.GetEndpoints(id)
} }
// List satisfies the RESTStorage interface. // 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() { if !selector.Empty() {
return nil, errors.New("label selectors are not supported on endpoints") 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. // 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") return nil, errors.New("unimplemented")
} }
// Update satisfies the RESTStorage interface but is 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") return nil, errors.New("unimplemented")
} }
// Delete satisfies the RESTStorage interface but is 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") return nil, errors.New("unimplemented")
} }
// New implements the RESTStorage interface. // New implements the RESTStorage interface.
func (rs Storage) New() interface{} { func (rs Storage) New() runtime.Object {
return &api.Endpoints{} return &api.Endpoints{}
} }

View File

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

View File

@@ -41,7 +41,7 @@ func NewTestEtcdRegistry(client tools.EtcdClient) *Registry {
func TestEtcdGetPod(t *testing.T) { func TestEtcdGetPod(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(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) registry := NewTestEtcdRegistry(fakeClient)
pod, err := registry.GetPod("foo") pod, err := registry.GetPod("foo")
if err != nil { if err != nil {
@@ -77,9 +77,9 @@ func TestEtcdCreatePod(t *testing.T) {
}, },
E: tools.EtcdErrorNotFound, 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) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{ err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: "foo", ID: "foo",
}, },
@@ -108,7 +108,7 @@ func TestEtcdCreatePod(t *testing.T) {
t.Fatalf("Unexpected error %v", err) t.Fatalf("Unexpected error %v", err)
} }
var pod api.Pod var pod api.Pod
err = runtime.DecodeInto([]byte(resp.Node.Value), &pod) err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &pod)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -122,7 +122,7 @@ func TestEtcdCreatePod(t *testing.T) {
t.Errorf("unexpected error: %v", err) 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" { if len(manifests.Items) != 1 || manifests.Items[0].ID != "foo" {
t.Errorf("Unexpected manifest list: %#v", manifests) t.Errorf("Unexpected manifest list: %#v", manifests)
} }
@@ -133,13 +133,13 @@ func TestEtcdCreatePodAlreadyExisting(t *testing.T) {
fakeClient.Data["/registry/pods/foo"] = tools.EtcdResponseWithError{ fakeClient.Data["/registry/pods/foo"] = tools.EtcdResponseWithError{
R: &etcd.Response{ R: &etcd.Response{
Node: &etcd.Node{ 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, E: nil,
} }
registry := NewTestEtcdRegistry(fakeClient) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{ err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: "foo", ID: "foo",
}, },
@@ -165,7 +165,7 @@ func TestEtcdCreatePodWithContainersError(t *testing.T) {
E: tools.EtcdErrorValueRequired, E: tools.EtcdErrorValueRequired,
} }
registry := NewTestEtcdRegistry(fakeClient) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{ err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: "foo", ID: "foo",
}, },
@@ -205,7 +205,7 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
E: tools.EtcdErrorNotFound, E: tools.EtcdErrorNotFound,
} }
registry := NewTestEtcdRegistry(fakeClient) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{ err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: "foo", ID: "foo",
}, },
@@ -235,7 +235,7 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
t.Fatalf("Unexpected error %v", err) t.Fatalf("Unexpected error %v", err)
} }
var pod api.Pod var pod api.Pod
err = runtime.DecodeInto([]byte(resp.Node.Value), &pod) err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &pod)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -249,7 +249,7 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) {
t.Errorf("unexpected error: %v", err) 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" { if len(manifests.Items) != 1 || manifests.Items[0].ID != "foo" {
t.Errorf("Unexpected manifest list: %#v", manifests) t.Errorf("Unexpected manifest list: %#v", manifests)
} }
@@ -264,13 +264,13 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
}, },
E: tools.EtcdErrorNotFound, 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{ Items: []api.ContainerManifest{
{ID: "bar"}, {ID: "bar"},
}, },
}), 0) }), 0)
registry := NewTestEtcdRegistry(fakeClient) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreatePod(api.Pod{ err := registry.CreatePod(&api.Pod{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: "foo", ID: "foo",
}, },
@@ -300,7 +300,7 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
t.Fatalf("Unexpected error %v", err) t.Fatalf("Unexpected error %v", err)
} }
var pod api.Pod var pod api.Pod
err = runtime.DecodeInto([]byte(resp.Node.Value), &pod) err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &pod)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -314,7 +314,7 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) {
t.Errorf("unexpected error: %v", err) 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" { if len(manifests.Items) != 2 || manifests.Items[1].ID != "foo" {
t.Errorf("Unexpected manifest list: %#v", manifests) t.Errorf("Unexpected manifest list: %#v", manifests)
} }
@@ -325,11 +325,11 @@ func TestEtcdDeletePod(t *testing.T) {
fakeClient.TestIndex = true fakeClient.TestIndex = true
key := "/registry/pods/foo" key := "/registry/pods/foo"
fakeClient.Set(key, runtime.EncodeOrDie(api.Pod{ fakeClient.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.PodState{Host: "machine"}, DesiredState: api.PodState{Host: "machine"},
}), 0) }), 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{ Items: []api.ContainerManifest{
{ID: "foo"}, {ID: "foo"},
}, },
@@ -350,7 +350,7 @@ func TestEtcdDeletePod(t *testing.T) {
t.Fatalf("Unexpected error %v", err) t.Fatalf("Unexpected error %v", err)
} }
var manifests api.ContainerManifestList var manifests api.ContainerManifestList
runtime.DecodeInto([]byte(response.Node.Value), &manifests) runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &manifests)
if len(manifests.Items) != 0 { if len(manifests.Items) != 0 {
t.Errorf("Unexpected container set: %s, expected empty", response.Node.Value) t.Errorf("Unexpected container set: %s, expected empty", response.Node.Value)
} }
@@ -361,11 +361,11 @@ func TestEtcdDeletePodMultipleContainers(t *testing.T) {
fakeClient.TestIndex = true fakeClient.TestIndex = true
key := "/registry/pods/foo" key := "/registry/pods/foo"
fakeClient.Set(key, runtime.EncodeOrDie(api.Pod{ fakeClient.Set(key, runtime.DefaultScheme.EncodeOrDie(&api.Pod{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.PodState{Host: "machine"}, DesiredState: api.PodState{Host: "machine"},
}), 0) }), 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{ Items: []api.ContainerManifest{
{ID: "foo"}, {ID: "foo"},
{ID: "bar"}, {ID: "bar"},
@@ -388,7 +388,7 @@ func TestEtcdDeletePodMultipleContainers(t *testing.T) {
t.Fatalf("Unexpected error %v", err) t.Fatalf("Unexpected error %v", err)
} }
var manifests api.ContainerManifestList var manifests api.ContainerManifestList
runtime.DecodeInto([]byte(response.Node.Value), &manifests) runtime.DefaultCodec.DecodeInto([]byte(response.Node.Value), &manifests)
if len(manifests.Items) != 1 { if len(manifests.Items) != 1 {
t.Fatalf("Unexpected manifest set: %#v, expected empty", manifests) t.Fatalf("Unexpected manifest set: %#v, expected empty", manifests)
} }
@@ -445,13 +445,13 @@ func TestEtcdListPods(t *testing.T) {
Node: &etcd.Node{ Node: &etcd.Node{
Nodes: []*etcd.Node{ Nodes: []*etcd.Node{
{ {
Value: runtime.EncodeOrDie(api.Pod{ Value: runtime.DefaultScheme.EncodeOrDie(&api.Pod{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
DesiredState: api.PodState{Host: "machine"}, DesiredState: api.PodState{Host: "machine"},
}), }),
}, },
{ {
Value: runtime.EncodeOrDie(api.Pod{ Value: runtime.DefaultScheme.EncodeOrDie(&api.Pod{
JSONBase: api.JSONBase{ID: "bar"}, JSONBase: api.JSONBase{ID: "bar"},
DesiredState: api.PodState{Host: "machine"}, DesiredState: api.PodState{Host: "machine"},
}), }),
@@ -520,10 +520,10 @@ func TestEtcdListControllers(t *testing.T) {
Node: &etcd.Node{ Node: &etcd.Node{
Nodes: []*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) { func TestEtcdGetController(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(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) registry := NewTestEtcdRegistry(fakeClient)
ctrl, err := registry.GetController("foo") ctrl, err := registry.GetController("foo")
if err != nil { if err != nil {
@@ -593,7 +593,7 @@ func TestEtcdDeleteController(t *testing.T) {
func TestEtcdCreateController(t *testing.T) { func TestEtcdCreateController(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t) fakeClient := tools.NewFakeEtcdClient(t)
registry := NewTestEtcdRegistry(fakeClient) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateController(api.ReplicationController{ err := registry.CreateController(&api.ReplicationController{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: "foo", ID: "foo",
}, },
@@ -607,7 +607,7 @@ func TestEtcdCreateController(t *testing.T) {
t.Fatalf("Unexpected error %v", err) t.Fatalf("Unexpected error %v", err)
} }
var ctrl api.ReplicationController var ctrl api.ReplicationController
err = runtime.DecodeInto([]byte(resp.Node.Value), &ctrl) err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &ctrl)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -619,10 +619,10 @@ func TestEtcdCreateController(t *testing.T) {
func TestEtcdCreateControllerAlreadyExisting(t *testing.T) { func TestEtcdCreateControllerAlreadyExisting(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(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) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateController(api.ReplicationController{ err := registry.CreateController(&api.ReplicationController{
JSONBase: api.JSONBase{ JSONBase: api.JSONBase{
ID: "foo", ID: "foo",
}, },
@@ -636,9 +636,9 @@ func TestEtcdUpdateController(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t) fakeClient := tools.NewFakeEtcdClient(t)
fakeClient.TestIndex = true 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) registry := NewTestEtcdRegistry(fakeClient)
err := registry.UpdateController(api.ReplicationController{ err := registry.UpdateController(&api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex}, JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex},
DesiredState: api.ReplicationControllerState{ DesiredState: api.ReplicationControllerState{
Replicas: 2, Replicas: 2,
@@ -662,10 +662,10 @@ func TestEtcdListServices(t *testing.T) {
Node: &etcd.Node{ Node: &etcd.Node{
Nodes: []*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) { func TestEtcdCreateService(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t) fakeClient := tools.NewFakeEtcdClient(t)
registry := NewTestEtcdRegistry(fakeClient) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateService(api.Service{ err := registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
}) })
if err != nil { if err != nil {
@@ -699,7 +699,7 @@ func TestEtcdCreateService(t *testing.T) {
} }
var service api.Service var service api.Service
err = runtime.DecodeInto([]byte(resp.Node.Value), &service) err = runtime.DefaultCodec.DecodeInto([]byte(resp.Node.Value), &service)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -711,9 +711,9 @@ func TestEtcdCreateService(t *testing.T) {
func TestEtcdCreateServiceAlreadyExisting(t *testing.T) { func TestEtcdCreateServiceAlreadyExisting(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(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) registry := NewTestEtcdRegistry(fakeClient)
err := registry.CreateService(api.Service{ err := registry.CreateService(&api.Service{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
}) })
if !errors.IsAlreadyExists(err) { if !errors.IsAlreadyExists(err) {
@@ -723,7 +723,7 @@ func TestEtcdCreateServiceAlreadyExisting(t *testing.T) {
func TestEtcdGetService(t *testing.T) { func TestEtcdGetService(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(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) registry := NewTestEtcdRegistry(fakeClient)
service, err := registry.GetService("foo") service, err := registry.GetService("foo")
if err != nil { if err != nil {
@@ -775,7 +775,7 @@ func TestEtcdUpdateService(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t) fakeClient := tools.NewFakeEtcdClient(t)
fakeClient.TestIndex = true 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) registry := NewTestEtcdRegistry(fakeClient)
testService := api.Service{ testService := api.Service{
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex}, JSONBase: api.JSONBase{ID: "foo", ResourceVersion: resp.Node.ModifiedIndex},
@@ -786,7 +786,7 @@ func TestEtcdUpdateService(t *testing.T) {
"baz": "bar", "baz": "bar",
}, },
} }
err := registry.UpdateService(testService) err := registry.UpdateService(&testService)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -812,10 +812,10 @@ func TestEtcdListEndpoints(t *testing.T) {
Node: &etcd.Node{ Node: &etcd.Node{
Nodes: []*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"}, 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") got, err := registry.GetEndpoints("foo")
if err != nil { if err != nil {
@@ -862,9 +862,9 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
Endpoints: []string{"baz", "bar"}, 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 { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
@@ -874,7 +874,7 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
t.Fatalf("Unexpected error %v", err) t.Fatalf("Unexpected error %v", err)
} }
var endpointsOut api.Endpoints 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) { if !reflect.DeepEqual(endpoints, endpointsOut) {
t.Errorf("Unexpected endpoints: %#v, expected %#v", endpointsOut, endpoints) 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/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "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) minion, ok := obj.(*api.Minion)
if !ok { if !ok {
return nil, fmt.Errorf("not a minion: %#v", obj) 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() minion.CreationTimestamp = util.Now()
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (runtime.Object, error) {
err := rs.registry.Insert(minion.ID) err := rs.registry.Insert(minion.ID)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -64,7 +65,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
}), nil }), 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) exists, err := rs.registry.Contains(id)
if !exists { if !exists {
return nil, ErrDoesNotExist return nil, ErrDoesNotExist
@@ -72,12 +73,12 @@ func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) {
if err != nil { if err != nil {
return nil, err 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) return &api.Status{Status: api.StatusSuccess}, rs.registry.Delete(id)
}), nil }), nil
} }
func (rs *RegistryStorage) Get(id string) (interface{}, error) { func (rs *RegistryStorage) Get(id string) (runtime.Object, error) {
exists, err := rs.registry.Contains(id) exists, err := rs.registry.Contains(id)
if !exists { if !exists {
return nil, ErrDoesNotExist return nil, ErrDoesNotExist
@@ -85,26 +86,26 @@ func (rs *RegistryStorage) Get(id string) (interface{}, error) {
return rs.toApiMinion(id), err 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() nameList, err := rs.registry.List()
if err != nil { if err != nil {
return nil, err return nil, err
} }
var list api.MinionList var list api.MinionList
for _, name := range nameList { 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{} 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.") return nil, fmt.Errorf("Minions can only be created (inserted) and deleted.")
} }
func (rs *RegistryStorage) toApiMinion(name string) api.Minion { func (rs *RegistryStorage) toApiMinion(name string) *api.Minion {
return api.Minion{JSONBase: api.JSONBase{ID: name}} return &api.Minion{JSONBase: api.JSONBase{ID: name}}
} }

View File

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

View File

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

View File

@@ -29,6 +29,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "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) pod := obj.(*api.Pod)
if len(pod.ID) == 0 { if len(pod.ID) == 0 {
pod.ID = uuid.NewUUID().String() pod.ID = uuid.NewUUID().String()
@@ -76,21 +77,21 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
pod.CreationTimestamp = util.Now() pod.CreationTimestamp = util.Now()
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (runtime.Object, error) {
if err := rs.registry.CreatePod(*pod); err != nil { if err := rs.registry.CreatePod(pod); err != nil {
return nil, err return nil, err
} }
return rs.registry.GetPod(pod.ID) return rs.registry.GetPod(pod.ID)
}), nil }), nil
} }
func (rs *RegistryStorage) Delete(id string) (<-chan interface{}, error) { func (rs *RegistryStorage) Delete(id string) (<-chan runtime.Object, error) {
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (runtime.Object, error) {
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeletePod(id) return &api.Status{Status: api.StatusSuccess}, rs.registry.DeletePod(id)
}), nil }), nil
} }
func (rs *RegistryStorage) Get(id string) (interface{}, error) { func (rs *RegistryStorage) Get(id string) (runtime.Object, error) {
pod, err := rs.registry.GetPod(id) pod, err := rs.registry.GetPod(id)
if err != nil { if err != nil {
return pod, err return pod, err
@@ -106,7 +107,7 @@ func (rs *RegistryStorage) Get(id string) (interface{}, error) {
return pod, err 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) pods, err := rs.registry.ListPods(selector)
if err == nil { if err == nil {
for i := range pods.Items { 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{} 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) pod := obj.(*api.Pod)
if errs := validation.ValidatePod(pod); len(errs) > 0 { if errs := validation.ValidatePod(pod); len(errs) > 0 {
return nil, errors.NewInvalid("pod", pod.ID, errs) return nil, errors.NewInvalid("pod", pod.ID, errs)
} }
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (runtime.Object, error) {
if err := rs.registry.UpdatePod(*pod); err != nil { if err := rs.registry.UpdatePod(pod); err != nil {
return nil, err return nil, err
} }
return rs.registry.GetPod(pod.ID) 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 { for {
podObj, err := rs.Get(pod.ID) podObj, err := rs.Get(pod.ID)
if err != nil || podObj == nil { if err != nil || podObj == nil {

View File

@@ -32,7 +32,7 @@ import (
"github.com/fsouza/go-dockerclient" "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 out := <-ch
status, ok := out.(*api.Status) status, ok := out.(*api.Status)
if !ok { 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 out := <-ch
pod, ok := out.(*api.Pod) pod, ok := out.(*api.Pod)
if !ok || pod == nil { if !ok || pod == nil {
@@ -178,13 +178,13 @@ func TestPodDecode(t *testing.T) {
ID: "foo", ID: "foo",
}, },
} }
body, err := runtime.Encode(expected) body, err := runtime.DefaultCodec.Encode(expected)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
actual := storage.New() 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) 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 return &api.ReplicationController{}, r.Err
} }
func (r *ControllerRegistry) CreateController(controller api.ReplicationController) error { func (r *ControllerRegistry) CreateController(controller *api.ReplicationController) error {
return r.Err return r.Err
} }
func (r *ControllerRegistry) UpdateController(controller api.ReplicationController) error { func (r *ControllerRegistry) UpdateController(controller *api.ReplicationController) error {
return r.Err return r.Err
} }

View File

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

View File

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

View File

@@ -26,10 +26,10 @@ import (
// Registry is an interface for things that know how to store services. // Registry is an interface for things that know how to store services.
type Registry interface { type Registry interface {
ListServices() (*api.ServiceList, error) ListServices() (*api.ServiceList, error)
CreateService(svc api.Service) error CreateService(svc *api.Service) error
GetService(name string) (*api.Service, error) GetService(name string) (*api.Service, error)
DeleteService(name string) 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) WatchServices(labels, fields labels.Selector, resourceVersion uint64) (watch.Interface, error)
// TODO: endpoints and their implementation should be separated, setting endpoints should be // 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/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/minion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "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) srv := obj.(*api.Service)
if errs := validation.ValidateService(srv); len(errs) > 0 { if errs := validation.ValidateService(srv); len(errs) > 0 {
return nil, errors.NewInvalid("service", srv.ID, errs) 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() 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 // TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers
// correctly no matter what http operations happen. // correctly no matter what http operations happen.
if srv.CreateExternalLoadBalancer { if srv.CreateExternalLoadBalancer {
@@ -85,7 +86,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
return nil, err return nil, err
} }
} }
err := rs.registry.CreateService(*srv) err := rs.registry.CreateService(srv)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -93,18 +94,18 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
}), nil }), 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) service, err := rs.registry.GetService(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (runtime.Object, error) {
rs.deleteExternalLoadBalancer(service) rs.deleteExternalLoadBalancer(service)
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(id) return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(id)
}), nil }), nil
} }
func (rs *RegistryStorage) Get(id string) (interface{}, error) { func (rs *RegistryStorage) Get(id string) (runtime.Object, error) {
s, err := rs.registry.GetService(id) s, err := rs.registry.GetService(id)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -112,7 +113,7 @@ func (rs *RegistryStorage) Get(id string) (interface{}, error) {
return s, err 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() list, err := rs.registry.ListServices()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -133,7 +134,7 @@ func (rs *RegistryStorage) Watch(label, field labels.Selector, resourceVersion u
return rs.registry.WatchServices(label, field, resourceVersion) return rs.registry.WatchServices(label, field, resourceVersion)
} }
func (rs RegistryStorage) New() interface{} { func (rs RegistryStorage) New() runtime.Object {
return &api.Service{} return &api.Service{}
} }
@@ -155,14 +156,14 @@ func GetServiceEnvironmentVariables(registry Registry, machine string) ([]api.En
return result, nil 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) srv := obj.(*api.Service)
if errs := validation.ValidateService(srv); len(errs) > 0 { if errs := validation.ValidateService(srv); len(errs) > 0 {
return nil, errors.NewInvalid("service", srv.ID, errs) 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 // TODO: check to see if external load balancer status changed
err := rs.registry.UpdateService(*srv) err := rs.registry.UpdateService(srv)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,31 +25,13 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
) )
func TestEncode_NonPtr(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)
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{ pod := &api.Pod{
Labels: map[string]string{"name": "foo"}, Labels: map[string]string{"name": "foo"},
} }
obj := interface{}(pod) obj := runtime.Object(pod)
data, err := runtime.Encode(obj) data, err := runtime.DefaultScheme.Encode(obj)
obj2, err2 := runtime.Decode(data) obj2, err2 := runtime.DefaultScheme.Decode(data)
if err != nil || err2 != nil { if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2) t.Fatalf("Failure: '%v' '%v'", err, err2)
} }
@@ -63,11 +45,11 @@ func TestEncode_Ptr(t *testing.T) {
func TestBadJSONRejection(t *testing.T) { func TestBadJSONRejection(t *testing.T) {
badJSONMissingKind := []byte(`{ }`) 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) t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
} }
badJSONUnknownType := []byte(`{"kind": "bar"}`) 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) t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
} }
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`) /*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 // NewJSONBaseResourceVersioner returns a resourceVersioner that can set or
// retrieve ResourceVersion on objects derived from JSONBase. // retrieve ResourceVersion on objects derived from JSONBase.
func NewJSONBaseResourceVersioner() resourceVersioner { func NewJSONBaseResourceVersioner() ResourceVersioner {
return &jsonBaseResourceVersioner{} return &jsonBaseResourceVersioner{}
} }
type jsonBaseResourceVersioner struct{} type jsonBaseResourceVersioner struct{}
func (v jsonBaseResourceVersioner) ResourceVersion(obj interface{}) (uint64, error) { func (v jsonBaseResourceVersioner) ResourceVersion(obj Object) (uint64, error) {
json, err := FindJSONBase(obj) json, err := FindJSONBase(obj)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -37,7 +37,7 @@ func (v jsonBaseResourceVersioner) ResourceVersion(obj interface{}) (uint64, err
return json.ResourceVersion(), nil 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) json, err := FindJSONBase(obj)
if err != nil { if err != nil {
return err 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) { 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 { type T struct {
Object interface{} Object
Expected uint64 Expected uint64
} }
testCases := map[string]T{ testCases := map[string]T{
@@ -110,10 +110,10 @@ func TestResourceVersionerOfAPI(t *testing.T) {
} }
failingCases := map[string]struct { failingCases := map[string]struct {
Object interface{} Object
Expected uint64 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 { for key, testCase := range failingCases {
_, err := versioning.ResourceVersion(testCase.Object) _, err := versioning.ResourceVersion(testCase.Object)
@@ -123,7 +123,7 @@ func TestResourceVersionerOfAPI(t *testing.T) {
} }
setCases := map[string]struct { setCases := map[string]struct {
Object interface{} Object
Expected uint64 Expected uint64
}{ }{
"pointer to api object with version": {&MyAPIObject{JSONBase: JSONBase{ResourceVersion: 1}}, 1}, "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) 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"` // runtime.JSONBase `yaml:",inline" json:",inline"`
// ... // other fields // ... // 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. // your own with the same fields.
// //
type JSONBase struct { type JSONBase struct {
@@ -43,17 +44,16 @@ type JSONBase struct {
} }
// EmbeddedObject has appropriate encoder and decoder functions, such that on the wire, it's // 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{} // stored as a []byte, but in memory, the contained object is accessable as an Object
// via the Get() function. Only objects having a JSONBase may be stored via 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 // The purpose of this is to allow an API object of type known only at runtime to be
// embedded within other API objects. // embedded within other API objects.
// //
// Note that object assumes that you've registered all of your api types with the api package. // 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; // TODO(dbsmith): Stop using runtime.Codec, use the codec appropriate for the conversion (I have a plan).
// this should be fixed in the future to use the version of the current Codec instead.
type EmbeddedObject struct { type EmbeddedObject struct {
Object interface{} Object
} }
// Extension allows api objects with unknown types to be passed-through. This can be used // 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. // JSONBase features-- kind, version, resourceVersion, etc.
// TODO: Not implemented yet // TODO: Not implemented yet
type Extension struct { 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)) 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. // 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}, JSONBase: api.JSONBase{ID: service.ID},
Endpoints: endpoints, Endpoints: endpoints,
}) })

View File

@@ -22,6 +22,7 @@ import (
"io" "io"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "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 // 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. // 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 var got api.WatchEvent
err = d.decoder.Decode(&got) err = d.decoder.Decode(&got)
if err != nil { if err != nil {

View File

@@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/coreos/go-etcd/etcd" "github.com/coreos/go-etcd/etcd"
) )
@@ -38,19 +39,6 @@ var (
EtcdErrorValueRequired = &etcd.EtcdError{ErrorCode: EtcdErrorCodeValueRequired} 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. // EtcdClient is an injectable interface for testing.
type EtcdClient interface { type EtcdClient interface {
AddChild(key, data string, ttl uint64) (*etcd.Response, error) 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. // EtcdHelper offers common object marshalling/unmarshalling operations on an etcd client.
type EtcdHelper struct { type EtcdHelper struct {
Client EtcdGetSet Client EtcdGetSet
Codec Codec Codec runtime.Codec
// optional, no atomic operations can be performed without this interface // 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. // 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() v := pv.Elem()
for _, node := range nodes { for _, node := range nodes {
obj := reflect.New(v.Type().Elem()) 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 { 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 // being unable to set the version does not prevent the object from being extracted
} }
if err != nil { 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 // 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 // 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. // 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) _, _, err := h.bodyAndExtractObj(key, objPtr, ignoreNotFound)
return err 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) response, err := h.Client.Get(key, false, false)
if err != nil && !IsEtcdNotFound(err) { 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. // 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) data, err := h.Codec.Encode(obj)
if err != nil { if err != nil {
return err 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 // SetObj marshals obj via json, and stores under key. Will do an
// atomic update if obj's ResourceVersion field is set. // 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) data, err := h.Codec.Encode(obj)
if err != nil { if err != nil {
return err 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. // Pass an EtcdUpdateFunc to EtcdHelper.AtomicUpdate to make an atomic etcd update.
// See the comment for AtomicUpdate for more detail. // 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. // AtomicUpdate generalizes the pattern that allows for making atomic updates to etcd objects.
// Note, tryUpdate may be called more than once. // Note, tryUpdate may be called more than once.
@@ -248,7 +236,7 @@ type EtcdUpdateFunc func(input interface{}) (output interface{}, err error)
// Example: // Example:
// //
// h := &util.EtcdHelper{client, encoding, versioning} // 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 // // Before this function is called, currentObj has been reset to etcd's current
// // contents for "myKey". // // contents for "myKey".
// //
@@ -261,14 +249,14 @@ type EtcdUpdateFunc func(input interface{}) (output interface{}, err error)
// return cur, nil // 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) pt := reflect.TypeOf(ptrToType)
if pt.Kind() != reflect.Ptr { if pt.Kind() != reflect.Ptr {
// Panic is appropriate, because this is a programming error. // Panic is appropriate, because this is a programming error.
panic("need ptr to type") panic("need ptr to type")
} }
for { for {
obj := reflect.New(pt.Elem()).Interface() obj := reflect.New(pt.Elem()).Interface().(runtime.Object)
origBody, index, err := h.bodyAndExtractObj(key, obj, true) origBody, index, err := h.bodyAndExtractObj(key, obj, true)
if err != nil { if err != nil {
return err return err

View File

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

View File

@@ -19,6 +19,7 @@ package tools
import ( import (
"sync" "sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
"github.com/coreos/go-etcd/etcd" "github.com/coreos/go-etcd/etcd"
@@ -27,10 +28,10 @@ import (
// FilterFunc is a predicate which takes an API object and returns true // FilterFunc is a predicate which takes an API object and returns true
// iff the object should remain in the set. // 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. // Everything is a FilterFunc which accepts all objects.
func Everything(interface{}) bool { func Everything(runtime.Object) bool {
return true return true
} }
@@ -59,7 +60,7 @@ func (h *EtcdHelper) Watch(key string, resourceVersion uint64) (watch.Interface,
// change or wrap the serialized etcd object. // change or wrap the serialized etcd object.
// //
// startTime := time.Now() // 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 := input.(TimeAwareValue)
// value.Since = startTime // value.Since = startTime
// return value, nil // 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. // 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. // etcdWatcher converts a native etcd watch to a watch.Interface.
type etcdWatcher struct { type etcdWatcher struct {
encoding Codec encoding runtime.Codec
versioner ResourceVersioner versioner runtime.ResourceVersioner
transform TransformFunc transform TransformFunc
list bool // If we're doing a recursive watch, should be true. 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 // 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. // 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{ w := &etcdWatcher{
encoding: encoding, encoding: encoding,
versioner: versioner, 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) obj, err := w.encoding.Decode(data)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -260,7 +261,7 @@ func (w *etcdWatcher) sendModify(res *etcd.Response) {
} }
curObjPasses := w.filter(curObj) curObjPasses := w.filter(curObj)
oldObjPasses := false oldObjPasses := false
var oldObj interface{} var oldObj runtime.Object
if res.PrevNode != nil && res.PrevNode.Value != "" { if res.PrevNode != nil && res.PrevNode.Value != "" {
// Ignore problems reading the old object. // Ignore problems reading the old object.
if oldObj, err = w.decodeObject([]byte(res.PrevNode.Value), res.PrevNode.ModifiedIndex); err == nil { 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"}} podFoo := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
podBar := &api.Pod{JSONBase: api.JSONBase{ID: "bar"}} podBar := &api.Pod{JSONBase: api.JSONBase{ID: "bar"}}
podBaz := &api.Pod{JSONBase: api.JSONBase{ID: "baz"}} 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' return obj.(*api.Pod).ID[0] == 'b'
} }
@@ -44,66 +44,66 @@ func TestWatchInterpretations(t *testing.T) {
nodeValue string nodeValue string
expectEmit bool expectEmit bool
expectType watch.EventType expectType watch.EventType
expectObject interface{} expectObject runtime.Object
}{ }{
"create": { "create": {
actions: []string{"create", "get"}, actions: []string{"create", "get"},
nodeValue: runtime.EncodeOrDie(podBar), nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true, expectEmit: true,
expectType: watch.Added, expectType: watch.Added,
expectObject: podBar, expectObject: podBar,
}, },
"create but filter blocks": { "create but filter blocks": {
actions: []string{"create", "get"}, actions: []string{"create", "get"},
nodeValue: runtime.EncodeOrDie(podFoo), nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: false, expectEmit: false,
}, },
"delete": { "delete": {
actions: []string{"delete"}, actions: []string{"delete"},
prevNodeValue: runtime.EncodeOrDie(podBar), prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true, expectEmit: true,
expectType: watch.Deleted, expectType: watch.Deleted,
expectObject: podBar, expectObject: podBar,
}, },
"delete but filter blocks": { "delete but filter blocks": {
actions: []string{"delete"}, actions: []string{"delete"},
nodeValue: runtime.EncodeOrDie(podFoo), nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: false, expectEmit: false,
}, },
"modify appears to create 1": { "modify appears to create 1": {
actions: []string{"set", "compareAndSwap"}, actions: []string{"set", "compareAndSwap"},
nodeValue: runtime.EncodeOrDie(podBar), nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true, expectEmit: true,
expectType: watch.Added, expectType: watch.Added,
expectObject: podBar, expectObject: podBar,
}, },
"modify appears to create 2": { "modify appears to create 2": {
actions: []string{"set", "compareAndSwap"}, actions: []string{"set", "compareAndSwap"},
prevNodeValue: runtime.EncodeOrDie(podFoo), prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
nodeValue: runtime.EncodeOrDie(podBar), nodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
expectEmit: true, expectEmit: true,
expectType: watch.Added, expectType: watch.Added,
expectObject: podBar, expectObject: podBar,
}, },
"modify appears to delete": { "modify appears to delete": {
actions: []string{"set", "compareAndSwap"}, actions: []string{"set", "compareAndSwap"},
prevNodeValue: runtime.EncodeOrDie(podBar), prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
nodeValue: runtime.EncodeOrDie(podFoo), nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: true, expectEmit: true,
expectType: watch.Deleted, expectType: watch.Deleted,
expectObject: podBar, // Should return last state that passed the filter! expectObject: podBar, // Should return last state that passed the filter!
}, },
"modify modifies": { "modify modifies": {
actions: []string{"set", "compareAndSwap"}, actions: []string{"set", "compareAndSwap"},
prevNodeValue: runtime.EncodeOrDie(podBar), prevNodeValue: runtime.DefaultScheme.EncodeOrDie(podBar),
nodeValue: runtime.EncodeOrDie(podBaz), nodeValue: runtime.DefaultScheme.EncodeOrDie(podBaz),
expectEmit: true, expectEmit: true,
expectType: watch.Modified, expectType: watch.Modified,
expectObject: podBaz, expectObject: podBaz,
}, },
"modify ignores": { "modify ignores": {
actions: []string{"set", "compareAndSwap"}, actions: []string{"set", "compareAndSwap"},
nodeValue: runtime.EncodeOrDie(podFoo), nodeValue: runtime.DefaultScheme.EncodeOrDie(podFoo),
expectEmit: false, expectEmit: false,
}, },
} }
@@ -259,7 +259,7 @@ func TestWatchEtcdState(t *testing.T) {
{ {
Action: "create", Action: "create",
Node: &etcd.Node{ 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", Action: "compareAndSwap",
Node: &etcd.Node{ 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, CreatedIndex: 1,
ModifiedIndex: 2, ModifiedIndex: 2,
}, },
PrevNode: &etcd.Node{ 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, CreatedIndex: 1,
ModifiedIndex: 1, ModifiedIndex: 1,
}, },
@@ -295,7 +295,7 @@ func TestWatchEtcdState(t *testing.T) {
R: &etcd.Response{ R: &etcd.Response{
Action: "get", Action: "get",
Node: &etcd.Node{ 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, CreatedIndex: 1,
ModifiedIndex: 1, ModifiedIndex: 1,
}, },
@@ -308,12 +308,12 @@ func TestWatchEtcdState(t *testing.T) {
{ {
Action: "compareAndSwap", Action: "compareAndSwap",
Node: &etcd.Node{ 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, CreatedIndex: 1,
ModifiedIndex: 2, ModifiedIndex: 2,
}, },
PrevNode: &etcd.Node{ 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, CreatedIndex: 1,
ModifiedIndex: 1, ModifiedIndex: 1,
}, },
@@ -370,7 +370,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
EtcdResponseWithError{ EtcdResponseWithError{
R: &etcd.Response{ R: &etcd.Response{
Node: &etcd.Node{ Node: &etcd.Node{
Value: runtime.EncodeOrDie(pod), Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 1, CreatedIndex: 1,
ModifiedIndex: 1, ModifiedIndex: 1,
}, },
@@ -385,7 +385,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
EtcdResponseWithError{ EtcdResponseWithError{
R: &etcd.Response{ R: &etcd.Response{
Node: &etcd.Node{ Node: &etcd.Node{
Value: runtime.EncodeOrDie(pod), Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 1, CreatedIndex: 1,
ModifiedIndex: 2, ModifiedIndex: 2,
}, },
@@ -443,13 +443,13 @@ func TestWatchListFromZeroIndex(t *testing.T) {
Dir: true, Dir: true,
Nodes: etcd.Nodes{ Nodes: etcd.Nodes{
&etcd.Node{ &etcd.Node{
Value: runtime.EncodeOrDie(pod), Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 1, CreatedIndex: 1,
ModifiedIndex: 1, ModifiedIndex: 1,
Nodes: etcd.Nodes{}, Nodes: etcd.Nodes{},
}, },
&etcd.Node{ &etcd.Node{
Value: runtime.EncodeOrDie(pod), Value: runtime.DefaultScheme.EncodeOrDie(pod),
CreatedIndex: 2, CreatedIndex: 2,
ModifiedIndex: 2, ModifiedIndex: 2,
Nodes: etcd.Nodes{}, 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 // 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 // go channels work, effectively causes the watch's event channel to have its
// queue length increased by one. // 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 { func Filter(w Interface, f FilterFunc) Interface {
fw := &filteredWatch{ fw := &filteredWatch{
incoming: w, incoming: w,

View File

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

View File

@@ -19,6 +19,7 @@ package watch
import ( import (
"sync" "sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "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. // 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 // An error will cause StreamWatcher to call Close(). Decode should block until
// it has data or an error occurs. // 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 // 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 // the stream that it is no longer being watched. Close() must cause any

View File

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

View File

@@ -18,6 +18,8 @@ package watch
import ( import (
"sync" "sync"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
) )
// Mux distributes event notifications among any number of watchers. Every event // 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. // 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} m.incoming <- Event{action, obj}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -33,17 +33,22 @@ func init() {
type stringCodec struct{} type stringCodec struct{}
func (c stringCodec) Encode(obj interface{}) ([]byte, error) { type fakeAPIObject string
return []byte(obj.(string)), nil
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) { func (c stringCodec) Decode(data []byte) (runtime.Object, error) {
return string(data), nil o := fakeAPIObject(data)
return &o, nil
} }
func (c stringCodec) DecodeInto(data []byte, obj interface{}) error { func (c stringCodec) DecodeInto(data []byte, obj runtime.Object) error {
o := obj.(*string) o := obj.(*fakeAPIObject)
*o = string(data) *o = fakeAPIObject(data)
return nil return nil
} }
@@ -51,7 +56,8 @@ func TestSetObj(t *testing.T) {
client := newEtcdClient() client := newEtcdClient()
helper := tools.EtcdHelper{Client: client, Codec: stringCodec{}} helper := tools.EtcdHelper{Client: client, Codec: stringCodec{}}
withEtcdKey(func(key string) { 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) t.Fatalf("unexpected error: %v", err)
} }
resp, err := client.Get(key, false, false) resp, err := client.Get(key, false, false)
@@ -72,7 +78,7 @@ func TestExtractObj(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
s := "" s := fakeAPIObject("")
if err := helper.ExtractObj(key, &s, false); err != nil { if err := helper.ExtractObj(key, &s, false); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
@@ -84,9 +90,9 @@ func TestExtractObj(t *testing.T) {
func TestWatch(t *testing.T) { func TestWatch(t *testing.T) {
client := newEtcdClient() 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) { 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 { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }