Make updates atomic from the client side.

pull/6/head
Brendan Burns 2014-08-01 14:14:33 -07:00
parent 5b589cf115
commit 1101c00014
3 changed files with 42 additions and 18 deletions

View File

@ -29,6 +29,7 @@ import (
"text/template"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
kube_client "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubecfg"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@ -202,6 +203,7 @@ func executeAPIRequest(method string, s *kube_client.Client) bool {
validStorage := checkStorage(storage)
verb := ""
setBody := false
var version uint64
switch method {
case "get":
verb = "GET"
@ -225,6 +227,15 @@ func executeAPIRequest(method string, s *kube_client.Client) bool {
glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>", method, prettyWireStorage())
}
case "update":
obj, err := s.Verb("GET").Path(path).Do().Get()
if err != nil {
glog.Fatalf("error obtaining resource version for update: %v", err)
}
jsonBase, err := api.FindJSONBase(obj)
if err != nil {
glog.Fatalf("error finding json base for update: %v", err)
}
version = jsonBase.ResourceVersion()
verb = "PUT"
setBody = true
if !validStorage || !hasSuffix {
@ -238,7 +249,25 @@ func executeAPIRequest(method string, s *kube_client.Client) bool {
Path(path).
ParseSelector(*selector)
if setBody {
r.Body(readConfig(storage))
if version != 0 {
data := readConfig(storage)
obj, err := api.Decode(data)
if err != nil {
glog.Fatalf("error setting resource version: %v", err)
}
jsonBase, err := api.FindJSONBase(obj)
if err != nil {
glog.Fatalf("error setting resource version: %v", err)
}
jsonBase.SetResourceVersion(version)
data, err = api.Encode(obj)
if err != nil {
glog.Fatalf("error setting resource version: %v", err)
}
r.Body(data)
} else {
r.Body(readConfig(storage))
}
}
result := r.Do()
obj, err := result.Get()

View File

@ -192,12 +192,10 @@ func (c *Client) CreatePod(pod api.Pod) (result api.Pod, err error) {
// 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) {
var prev api.Pod
err = c.Get().Path("pod").Path(pod.ID).Do().Into(&prev)
if err != nil {
if pod.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", pod)
return
}
pod.ResourceVersion = prev.ResourceVersion
err = c.Put().Path("pods").Path(pod.ID).Body(pod).Do().Into(&result)
return
}
@ -222,12 +220,10 @@ func (c *Client) CreateReplicationController(controller api.ReplicationControlle
// UpdateReplicationController updates an existing replication controller
func (c *Client) UpdateReplicationController(controller api.ReplicationController) (result api.ReplicationController, err error) {
var prev api.ReplicationController
err = c.Get().Path("replicationControllers").Path(controller.ID).Do().Into(&prev)
if err != nil {
if controller.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", controller)
return
}
controller.ResourceVersion = prev.ResourceVersion
err = c.Put().Path("replicationControllers").Path(controller.ID).Body(controller).Do().Into(&result)
return
}
@ -251,12 +247,10 @@ func (c *Client) CreateService(svc api.Service) (result api.Service, err error)
// UpdateService updates an existing service.
func (c *Client) UpdateService(svc api.Service) (result api.Service, err error) {
var prev api.Service
err = c.Get().Path("services").Path(svc.ID).Do().Into(&prev)
if err != nil {
if svc.ResourceVersion == 0 {
err = fmt.Errorf("invalid update object, missing resource version: %v", svc)
return
}
svc.ResourceVersion = prev.ResourceVersion
err = c.Put().Path("services").Path(svc.ID).Body(svc).Do().Into(&result)
return
}

View File

@ -154,7 +154,7 @@ func TestCreatePod(t *testing.T) {
func TestUpdatePod(t *testing.T) {
requestPod := api.Pod{
JSONBase: api.JSONBase{ID: "foo"},
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1},
CurrentState: api.PodState{
Status: "Foobar",
},
@ -219,7 +219,7 @@ func TestGetController(t *testing.T) {
func TestUpdateController(t *testing.T) {
requestController := api.ReplicationController{
JSONBase: api.JSONBase{ID: "foo"},
JSONBase: api.JSONBase{ID: "foo", ResourceVersion: 1},
}
c := &testClient{
Request: testRequest{Method: "PUT", Path: "/replicationControllers/foo"},
@ -388,11 +388,12 @@ func TestCreateService(t *testing.T) {
}
func TestUpdateService(t *testing.T) {
svc := api.Service{JSONBase: api.JSONBase{ID: "service-1", ResourceVersion: 1}}
c := &testClient{
Request: testRequest{Method: "PUT", Path: "/services/service-1", Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
Response: Response{StatusCode: 200, Body: &api.Service{JSONBase: api.JSONBase{ID: "service-1"}}},
Request: testRequest{Method: "PUT", Path: "/services/service-1", Body: &svc},
Response: Response{StatusCode: 200, Body: &svc},
}
response, err := c.Setup().UpdateService(api.Service{JSONBase: api.JSONBase{ID: "service-1"}})
response, err := c.Setup().UpdateService(svc)
c.Validate(t, &response, err)
}