diff --git a/pkg/api/helper.go b/pkg/api/helper.go index cd882110a5..4c92fd1944 100644 --- a/pkg/api/helper.go +++ b/pkg/api/helper.go @@ -49,6 +49,13 @@ func AddKnownTypes(types ...interface{}) { } } +// Takes an arbitary api type, returns pointer to its JSONBase field. +// obj must be a pointer to an api type. +func FindJSONBase(obj interface{}) (*JSONBase, error) { + _, jsonBase, err := nameAndJSONBase(obj) + return jsonBase, err +} + // Encode turns the given api object into an appropriate JSON string. // Will return an error if the object doesn't have an embedded JSONBase. // Obj may be a pointer to a struct, or a struct. If a struct, a copy diff --git a/pkg/api/types.go b/pkg/api/types.go index 8e67b20fab..5104d60f06 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -150,6 +150,7 @@ type JSONBase struct { ID string `json:"id,omitempty" yaml:"id,omitempty"` CreationTimestamp string `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"` SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` } type PodStatus string diff --git a/pkg/controller/replication_controller.go b/pkg/controller/replication_controller.go index 6847a63cbb..90a366797d 100644 --- a/pkg/controller/replication_controller.go +++ b/pkg/controller/replication_controller.go @@ -25,6 +25,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" + "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/coreos/go-etcd/etcd" "github.com/golang/glog" @@ -34,7 +35,7 @@ import ( // with actual running pods. // TODO: Remove the etcd dependency and re-factor in terms of a generic watch interface type ReplicationManager struct { - etcdClient util.EtcdClient + etcdClient tools.EtcdClient kubeClient client.ClientInterface podControl PodControlInterface syncTime <-chan time.Time @@ -76,7 +77,7 @@ func (r RealPodControl) deletePod(podID string) error { return r.kubeClient.DeletePod(podID) } -func MakeReplicationManager(etcdClient util.EtcdClient, kubeClient client.ClientInterface) *ReplicationManager { +func MakeReplicationManager(etcdClient tools.EtcdClient, kubeClient client.ClientInterface) *ReplicationManager { rm := &ReplicationManager{ kubeClient: kubeClient, etcdClient: etcdClient, @@ -201,7 +202,7 @@ func (rm *ReplicationManager) syncReplicationController(controllerSpec api.Repli func (rm *ReplicationManager) synchronize() { var controllerSpecs []api.ReplicationController - helper := util.EtcdHelper{rm.etcdClient} + helper := tools.EtcdHelper{rm.etcdClient} err := helper.ExtractList("/registry/controllers", &controllerSpecs) if err != nil { glog.Errorf("Synchronization error: %v (%#v)", err, err) diff --git a/pkg/controller/replication_controller_test.go b/pkg/controller/replication_controller_test.go index e83cf695ee..bda55a82bc 100644 --- a/pkg/controller/replication_controller_test.go +++ b/pkg/controller/replication_controller_test.go @@ -26,6 +26,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" + "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/coreos/go-etcd/etcd" ) @@ -377,8 +378,8 @@ func TestSyncronize(t *testing.T) { }, } - fakeEtcd := util.MakeFakeEtcdClient(t) - fakeEtcd.Data["/registry/controllers"] = util.EtcdResponseWithError{ + fakeEtcd := tools.MakeFakeEtcdClient(t) + fakeEtcd.Data["/registry/controllers"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{ @@ -432,7 +433,7 @@ func (a *asyncTimeout) done() { func TestWatchControllers(t *testing.T) { defer beginTimeout(20 * time.Second).done() - fakeEtcd := util.MakeFakeEtcdClient(t) + fakeEtcd := tools.MakeFakeEtcdClient(t) manager := MakeReplicationManager(fakeEtcd, nil) var testControllerSpec api.ReplicationController received := make(chan bool) diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 7b1efcf4fc..71a99a8886 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -34,6 +34,7 @@ import ( "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/coreos/go-etcd/etcd" "github.com/fsouza/go-dockerclient" @@ -81,7 +82,7 @@ func New() *Kubelet { // The main kubelet implementation type Kubelet struct { Hostname string - EtcdClient util.EtcdClient + EtcdClient tools.EtcdClient DockerClient DockerInterface DockerPuller DockerPuller CadvisorClient CadvisorInterface @@ -520,7 +521,7 @@ func (kl *Kubelet) ResponseToManifests(response *etcd.Response) ([]api.Container func (kl *Kubelet) getKubeletStateFromEtcd(key string, updateChannel chan<- manifestUpdate) error { response, err := kl.EtcdClient.Get(key, true, false) if err != nil { - if util.IsEtcdNotFound(err) { + if tools.IsEtcdNotFound(err) { return nil } glog.Errorf("Error on etcd get of %s: %v", key, err) diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 9c0ea52db0..d9fe97a588 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -26,6 +26,7 @@ import ( "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/coreos/go-etcd/etcd" "github.com/fsouza/go-dockerclient" @@ -75,8 +76,8 @@ func verifyError(t *testing.T, e error) { } } -func makeTestKubelet(t *testing.T) (*Kubelet, *util.FakeEtcdClient, *FakeDockerClient) { - fakeEtcdClient := util.MakeFakeEtcdClient(t) +func makeTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *FakeDockerClient) { + fakeEtcdClient := tools.MakeFakeEtcdClient(t) fakeDocker := &FakeDockerClient{ err: nil, } @@ -279,7 +280,7 @@ func TestGetKubeletStateFromEtcdNoData(t *testing.T) { kubelet, fakeClient, _ := makeTestKubelet(t) channel := make(chan manifestUpdate) reader := startReading(channel) - fakeClient.Data["/registry/hosts/machine/kubelet"] = util.EtcdResponseWithError{ + fakeClient.Data["/registry/hosts/machine/kubelet"] = tools.EtcdResponseWithError{ R: &etcd.Response{}, E: nil, } @@ -298,7 +299,7 @@ func TestGetKubeletStateFromEtcd(t *testing.T) { kubelet, fakeClient, _ := makeTestKubelet(t) channel := make(chan manifestUpdate) reader := startReading(channel) - fakeClient.Data["/registry/hosts/machine/kubelet"] = util.EtcdResponseWithError{ + fakeClient.Data["/registry/hosts/machine/kubelet"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: util.MakeJSONString([]api.Container{}), @@ -319,7 +320,7 @@ func TestGetKubeletStateFromEtcdNotFound(t *testing.T) { kubelet, fakeClient, _ := makeTestKubelet(t) channel := make(chan manifestUpdate) reader := startReading(channel) - fakeClient.Data["/registry/hosts/machine/kubelet"] = util.EtcdResponseWithError{ + fakeClient.Data["/registry/hosts/machine/kubelet"] = tools.EtcdResponseWithError{ R: &etcd.Response{}, E: &etcd.EtcdError{ ErrorCode: 100, @@ -338,7 +339,7 @@ func TestGetKubeletStateFromEtcdError(t *testing.T) { kubelet, fakeClient, _ := makeTestKubelet(t) channel := make(chan manifestUpdate) reader := startReading(channel) - fakeClient.Data["/registry/hosts/machine/kubelet"] = util.EtcdResponseWithError{ + fakeClient.Data["/registry/hosts/machine/kubelet"] = tools.EtcdResponseWithError{ R: &etcd.Response{}, E: &etcd.EtcdError{ ErrorCode: 200, // non not found error diff --git a/pkg/registry/etcd_registry.go b/pkg/registry/etcd_registry.go index 9f8c95aa82..1f171e0d24 100644 --- a/pkg/registry/etcd_registry.go +++ b/pkg/registry/etcd_registry.go @@ -21,7 +21,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" - "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/golang/glog" ) @@ -30,7 +30,7 @@ import ( // EtcdRegistry is an implementation of both ControllerRegistry and PodRegistry which is backed with etcd. type EtcdRegistry struct { - etcdClient util.EtcdClient + etcdClient tools.EtcdClient machines MinionRegistry manifestFactory ManifestFactory } @@ -39,7 +39,7 @@ type EtcdRegistry struct { // 'client' is the connection to etcd // 'machines' is the list of machines // 'scheduler' is the scheduling algorithm to use. -func MakeEtcdRegistry(client util.EtcdClient, machines MinionRegistry) *EtcdRegistry { +func MakeEtcdRegistry(client tools.EtcdClient, machines MinionRegistry) *EtcdRegistry { registry := &EtcdRegistry{ etcdClient: client, machines: machines, @@ -54,8 +54,8 @@ func makePodKey(machine, podID string) string { return "/registry/hosts/" + machine + "/pods/" + podID } -func (registry *EtcdRegistry) helper() *util.EtcdHelper { - return &util.EtcdHelper{registry.etcdClient} +func (registry *EtcdRegistry) helper() *tools.EtcdHelper { + return &tools.EtcdHelper{registry.etcdClient} } func (registry *EtcdRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) { diff --git a/pkg/registry/etcd_registry_test.go b/pkg/registry/etcd_registry_test.go index 1ea19adf51..caa5c08bce 100644 --- a/pkg/registry/etcd_registry_test.go +++ b/pkg/registry/etcd_registry_test.go @@ -23,11 +23,12 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" + "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/coreos/go-etcd/etcd" ) -func MakeTestEtcdRegistry(client util.EtcdClient, machines []string) *EtcdRegistry { +func MakeTestEtcdRegistry(client tools.EtcdClient, machines []string) *EtcdRegistry { registry := MakeEtcdRegistry(client, MakeMinionRegistry(machines)) registry.manifestFactory = &BasicManifestFactory{ serviceRegistry: &MockServiceRegistry{}, @@ -36,7 +37,7 @@ func MakeTestEtcdRegistry(client util.EtcdClient, machines []string) *EtcdRegist } func TestEtcdGetPod(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) fakeClient.Set("/registry/hosts/machine/pods/foo", util.MakeJSONString(api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) pod, err := registry.GetPod("foo") @@ -47,8 +48,8 @@ func TestEtcdGetPod(t *testing.T) { } func TestEtcdGetPodNotFound(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/hosts/machine/pods/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/hosts/machine/pods/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -64,8 +65,8 @@ func TestEtcdGetPodNotFound(t *testing.T) { } func TestEtcdCreatePod(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/hosts/machine/pods/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/hosts/machine/pods/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -106,8 +107,8 @@ func TestEtcdCreatePod(t *testing.T) { } func TestEtcdCreatePodAlreadyExisting(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/hosts/machine/pods/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/hosts/machine/pods/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: util.MakeJSONString(api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), @@ -127,14 +128,14 @@ func TestEtcdCreatePodAlreadyExisting(t *testing.T) { } func TestEtcdCreatePodWithContainersError(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/hosts/machine/pods/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/hosts/machine/pods/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, E: &etcd.EtcdError{ErrorCode: 100}, } - fakeClient.Data["/registry/hosts/machine/kubelet"] = util.EtcdResponseWithError{ + fakeClient.Data["/registry/hosts/machine/kubelet"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -159,14 +160,14 @@ func TestEtcdCreatePodWithContainersError(t *testing.T) { } func TestEtcdCreatePodWithContainersNotFound(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/hosts/machine/pods/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/hosts/machine/pods/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, E: &etcd.EtcdError{ErrorCode: 100}, } - fakeClient.Data["/registry/hosts/machine/kubelet"] = util.EtcdResponseWithError{ + fakeClient.Data["/registry/hosts/machine/kubelet"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -207,8 +208,8 @@ func TestEtcdCreatePodWithContainersNotFound(t *testing.T) { } func TestEtcdCreatePodWithExistingContainers(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/hosts/machine/pods/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/hosts/machine/pods/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -254,7 +255,7 @@ func TestEtcdCreatePodWithExistingContainers(t *testing.T) { } func TestEtcdDeletePod(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/hosts/machine/pods/foo" fakeClient.Set(key, util.MakeJSONString(api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0) fakeClient.Set("/registry/hosts/machine/kubelet", util.MakeJSONString([]api.ContainerManifest{ @@ -277,7 +278,7 @@ func TestEtcdDeletePod(t *testing.T) { } func TestEtcdDeletePodMultipleContainers(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/hosts/machine/pods/foo" fakeClient.Set(key, util.MakeJSONString(api.Pod{JSONBase: api.JSONBase{ID: "foo"}}), 0) fakeClient.Set("/registry/hosts/machine/kubelet", util.MakeJSONString([]api.ContainerManifest{ @@ -305,9 +306,9 @@ func TestEtcdDeletePodMultipleContainers(t *testing.T) { } func TestEtcdEmptyListPods(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/hosts/machine/pods" - fakeClient.Data[key] = util.EtcdResponseWithError{ + fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{}, @@ -324,9 +325,9 @@ func TestEtcdEmptyListPods(t *testing.T) { } func TestEtcdListPodsNotFound(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/hosts/machine/pods" - fakeClient.Data[key] = util.EtcdResponseWithError{ + fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{}, E: &etcd.EtcdError{ErrorCode: 100}, } @@ -339,9 +340,9 @@ func TestEtcdListPodsNotFound(t *testing.T) { } func TestEtcdListPods(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/hosts/machine/pods" - fakeClient.Data[key] = util.EtcdResponseWithError{ + fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{ @@ -369,9 +370,9 @@ func TestEtcdListPods(t *testing.T) { } func TestEtcdListControllersNotFound(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/controllers" - fakeClient.Data[key] = util.EtcdResponseWithError{ + fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{}, E: &etcd.EtcdError{ErrorCode: 100}, } @@ -384,9 +385,9 @@ func TestEtcdListControllersNotFound(t *testing.T) { } func TestEtcdListServicesNotFound(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/services/specs" - fakeClient.Data[key] = util.EtcdResponseWithError{ + fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{}, E: &etcd.EtcdError{ErrorCode: 100}, } @@ -399,9 +400,9 @@ func TestEtcdListServicesNotFound(t *testing.T) { } func TestEtcdListControllers(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/controllers" - fakeClient.Data[key] = util.EtcdResponseWithError{ + fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{ @@ -425,7 +426,7 @@ func TestEtcdListControllers(t *testing.T) { } func TestEtcdGetController(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) fakeClient.Set("/registry/controllers/foo", util.MakeJSONString(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) ctrl, err := registry.GetController("foo") @@ -436,8 +437,8 @@ func TestEtcdGetController(t *testing.T) { } func TestEtcdGetControllerNotFound(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/controllers/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/controllers/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -456,7 +457,7 @@ func TestEtcdGetControllerNotFound(t *testing.T) { } func TestEtcdDeleteController(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) err := registry.DeleteController("foo") expectNoError(t, err) @@ -470,7 +471,7 @@ func TestEtcdDeleteController(t *testing.T) { } func TestEtcdCreateController(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) err := registry.CreateController(api.ReplicationController{ JSONBase: api.JSONBase{ @@ -489,7 +490,7 @@ func TestEtcdCreateController(t *testing.T) { } func TestEtcdUpdateController(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) fakeClient.Set("/registry/controllers/foo", util.MakeJSONString(api.ReplicationController{JSONBase: api.JSONBase{ID: "foo"}}), 0) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) err := registry.UpdateController(api.ReplicationController{ @@ -506,9 +507,9 @@ func TestEtcdUpdateController(t *testing.T) { } func TestEtcdListServices(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) key := "/registry/services/specs" - fakeClient.Data[key] = util.EtcdResponseWithError{ + fakeClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Nodes: []*etcd.Node{ @@ -532,8 +533,8 @@ func TestEtcdListServices(t *testing.T) { } func TestEtcdCreateService(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/services/specs/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/services/specs/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -555,7 +556,7 @@ func TestEtcdCreateService(t *testing.T) { } func TestEtcdGetService(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) fakeClient.Set("/registry/services/specs/foo", util.MakeJSONString(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) service, err := registry.GetService("foo") @@ -566,8 +567,8 @@ func TestEtcdGetService(t *testing.T) { } func TestEtcdGetServiceNotFound(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) - fakeClient.Data["/registry/services/specs/foo"] = util.EtcdResponseWithError{ + fakeClient := tools.MakeFakeEtcdClient(t) + fakeClient.Data["/registry/services/specs/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, @@ -583,7 +584,7 @@ func TestEtcdGetServiceNotFound(t *testing.T) { } func TestEtcdDeleteService(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) err := registry.DeleteService("foo") expectNoError(t, err) @@ -601,7 +602,7 @@ func TestEtcdDeleteService(t *testing.T) { } func TestEtcdUpdateService(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) fakeClient.Set("/registry/services/specs/foo", util.MakeJSONString(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) testService := api.Service{ @@ -623,7 +624,7 @@ func TestEtcdUpdateService(t *testing.T) { } func TestEtcdUpdateEndpoints(t *testing.T) { - fakeClient := util.MakeFakeEtcdClient(t) + fakeClient := tools.MakeFakeEtcdClient(t) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) endpoints := api.Endpoints{ Name: "foo", diff --git a/pkg/tools/doc.go b/pkg/tools/doc.go new file mode 100644 index 0000000000..d1d8014cda --- /dev/null +++ b/pkg/tools/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package tools implements general tools which depend on the api package. +package tools diff --git a/pkg/util/etcd_tools.go b/pkg/tools/etcd_tools.go similarity index 92% rename from pkg/util/etcd_tools.go rename to pkg/tools/etcd_tools.go index 39f4b37a3f..631c925d0b 100644 --- a/pkg/util/etcd_tools.go +++ b/pkg/tools/etcd_tools.go @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package tools import ( "encoding/json" "fmt" "reflect" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/coreos/go-etcd/etcd" ) @@ -117,8 +118,14 @@ func (h *EtcdHelper) ExtractList(key string, slicePtr interface{}) error { // a zero object of the requested type, or an error, depending on ignoreNotFound. Treats // empty responses and nil response nodes exactly like a not found error. func (h *EtcdHelper) ExtractObj(key string, objPtr interface{}, ignoreNotFound bool) error { - _, _, err := h.bodyAndExtractObj(key, objPtr, ignoreNotFound) - return err + _, index, err := h.bodyAndExtractObj(key, objPtr, ignoreNotFound) + if err != nil { + return err + } + if jsonBase, err := api.FindJSONBase(objPtr); err == nil { + jsonBase.ResourceVersion = index + } + return nil } func (h *EtcdHelper) bodyAndExtractObj(key string, objPtr interface{}, ignoreNotFound bool) (body string, modifiedIndex uint64, err error) { @@ -147,7 +154,11 @@ func (h *EtcdHelper) SetObj(key string, obj interface{}) error { if err != nil { return err } - _, err = h.Client.Set(key, string(data), 0) + if jsonBase, err := api.FindJSONBase(obj); err == nil && jsonBase.ResourceVersion != 0 { + _, err = h.Client.CompareAndSwap(key, string(data), 0, "", jsonBase.ResourceVersion) + } else { + _, err = h.Client.Set(key, string(data), 0) + } return err } diff --git a/pkg/util/etcd_tools_test.go b/pkg/tools/etcd_tools_test.go similarity index 95% rename from pkg/util/etcd_tools_test.go rename to pkg/tools/etcd_tools_test.go index 30c4c6243b..3b38287748 100644 --- a/pkg/util/etcd_tools_test.go +++ b/pkg/tools/etcd_tools_test.go @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package tools import ( "fmt" "reflect" "testing" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/coreos/go-etcd/etcd" ) @@ -83,7 +84,7 @@ func TestExtractList(t *testing.T) { func TestExtractObj(t *testing.T) { fakeClient := MakeFakeEtcdClient(t) expect := testMarshalType{ID: "foo"} - fakeClient.Set("/some/key", MakeJSONString(expect), 0) + fakeClient.Set("/some/key", util.MakeJSONString(expect), 0) helper := EtcdHelper{fakeClient} var got testMarshalType err := helper.ExtractObj("/some/key", &got, false) @@ -143,7 +144,7 @@ func TestSetObj(t *testing.T) { if err != nil { t.Errorf("Unexpected error %#v", err) } - expect := MakeJSONString(obj) + expect := util.MakeJSONString(obj) got := fakeClient.Data["/some/key"].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) diff --git a/pkg/util/fake_etcd_client.go b/pkg/tools/fake_etcd_client.go similarity index 99% rename from pkg/util/fake_etcd_client.go rename to pkg/tools/fake_etcd_client.go index 36a00752ad..47509bdff8 100644 --- a/pkg/util/fake_etcd_client.go +++ b/pkg/tools/fake_etcd_client.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package tools import ( "fmt" diff --git a/pkg/util/doc.go b/pkg/util/doc.go index 316eedb31d..dac5f137bf 100644 --- a/pkg/util/doc.go +++ b/pkg/util/doc.go @@ -15,5 +15,6 @@ limitations under the License. */ // Package util implements various utility functions used in both testing and implementation -// of Kubernetes +// of Kubernetes. Package util may not depend on any other package in the Kubernetes +// package tree. package util