Merge pull request #6871 from ironcladlou/rolling-update-refactor

Use narrowly scoped interfaces for client access
This commit is contained in:
Tim Hockin 2015-04-15 17:01:58 -07:00
commit 5e30997aeb
7 changed files with 89 additions and 25 deletions

View File

@ -111,7 +111,7 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
return err return err
} }
updater := kubectl.NewRollingUpdater(newRc.Namespace, client) updater := kubectl.NewRollingUpdater(newRc.Namespace, kubectl.NewRollingUpdaterClient(client))
// fetch rc // fetch rc
oldRc, err := client.ReplicationControllers(newRc.Namespace).Get(oldName) oldRc, err := client.ReplicationControllers(newRc.Namespace).Get(oldName)

View File

@ -197,7 +197,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return kubectl.ResizerFor(mapping.Kind, client) return kubectl.ResizerFor(mapping.Kind, kubectl.NewResizerClient(client))
}, },
Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) { Reaper: func(mapping *meta.RESTMapping) (kubectl.Reaper, error) {
client, err := clients.ClientForVersion(mapping.APIVersion) client, err := clients.ClientForVersion(mapping.APIVersion)

View File

@ -89,7 +89,7 @@ type Resizer interface {
ResizeSimple(namespace, name string, preconditions *ResizePrecondition, newSize uint) (string, error) ResizeSimple(namespace, name string, preconditions *ResizePrecondition, newSize uint) (string, error)
} }
func ResizerFor(kind string, c client.Interface) (Resizer, error) { func ResizerFor(kind string, c ResizerClient) (Resizer, error) {
switch kind { switch kind {
case "ReplicationController": case "ReplicationController":
return &ReplicationControllerResizer{c}, nil return &ReplicationControllerResizer{c}, nil
@ -98,7 +98,7 @@ func ResizerFor(kind string, c client.Interface) (Resizer, error) {
} }
type ReplicationControllerResizer struct { type ReplicationControllerResizer struct {
client.Interface c ResizerClient
} }
type RetryParams struct { type RetryParams struct {
@ -122,8 +122,7 @@ func ResizeCondition(r Resizer, precondition *ResizePrecondition, namespace, nam
} }
func (resizer *ReplicationControllerResizer) ResizeSimple(namespace, name string, preconditions *ResizePrecondition, newSize uint) (string, error) { func (resizer *ReplicationControllerResizer) ResizeSimple(namespace, name string, preconditions *ResizePrecondition, newSize uint) (string, error) {
rc := resizer.ReplicationControllers(namespace) controller, err := resizer.c.GetReplicationController(namespace, name)
controller, err := rc.Get(name)
if err != nil { if err != nil {
return "", ControllerResizeError{ControllerResizeGetFailure, "Unknown", err} return "", ControllerResizeError{ControllerResizeGetFailure, "Unknown", err}
} }
@ -134,7 +133,7 @@ func (resizer *ReplicationControllerResizer) ResizeSimple(namespace, name string
} }
controller.Spec.Replicas = int(newSize) controller.Spec.Replicas = int(newSize)
// TODO: do retry on 409 errors here? // TODO: do retry on 409 errors here?
if _, err := rc.Update(controller); err != nil { if _, err := resizer.c.UpdateReplicationController(namespace, controller); err != nil {
return "", ControllerResizeError{ControllerResizeUpdateFailure, controller.ResourceVersion, err} return "", ControllerResizeError{ControllerResizeUpdateFailure, controller.ResourceVersion, err}
} }
// TODO: do a better job of printing objects here. // TODO: do a better job of printing objects here.
@ -159,9 +158,37 @@ func (resizer *ReplicationControllerResizer) Resize(namespace, name string, newS
if waitForReplicas != nil { if waitForReplicas != nil {
rc := &api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: namespace, Name: name}} rc := &api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: namespace, Name: name}}
if err := wait.Poll(waitForReplicas.interval, waitForReplicas.timeout, if err := wait.Poll(waitForReplicas.interval, waitForReplicas.timeout,
client.ControllerHasDesiredReplicas(resizer, rc)); err != nil { resizer.c.ControllerHasDesiredReplicas(rc)); err != nil {
return err return err
} }
} }
return nil return nil
} }
// ResizerClient abstracts access to ReplicationControllers.
type ResizerClient interface {
GetReplicationController(namespace, name string) (*api.ReplicationController, error)
UpdateReplicationController(namespace string, rc *api.ReplicationController) (*api.ReplicationController, error)
ControllerHasDesiredReplicas(rc *api.ReplicationController) wait.ConditionFunc
}
func NewResizerClient(c client.Interface) ResizerClient {
return &realResizerClient{c}
}
// realResizerClient is a ResizerClient which uses a Kube client.
type realResizerClient struct {
client client.Interface
}
func (c *realResizerClient) GetReplicationController(namespace, name string) (*api.ReplicationController, error) {
return c.client.ReplicationControllers(namespace).Get(name)
}
func (c *realResizerClient) UpdateReplicationController(namespace string, rc *api.ReplicationController) (*api.ReplicationController, error) {
return c.client.ReplicationControllers(namespace).Update(rc)
}
func (c *realResizerClient) ControllerHasDesiredReplicas(rc *api.ReplicationController) wait.ConditionFunc {
return client.ControllerHasDesiredReplicas(c.client, rc)
}

View File

@ -43,7 +43,7 @@ func (c *ErrorReplicationControllerClient) ReplicationControllers(namespace stri
func TestReplicationControllerResizeRetry(t *testing.T) { func TestReplicationControllerResizeRetry(t *testing.T) {
fake := &ErrorReplicationControllerClient{Fake: testclient.Fake{}} fake := &ErrorReplicationControllerClient{Fake: testclient.Fake{}}
resizer := ReplicationControllerResizer{fake} resizer := ReplicationControllerResizer{NewResizerClient(fake)}
preconditions := ResizePrecondition{-1, ""} preconditions := ResizePrecondition{-1, ""}
count := uint(3) count := uint(3)
name := "foo" name := "foo"
@ -67,7 +67,7 @@ func TestReplicationControllerResizeRetry(t *testing.T) {
func TestReplicationControllerResize(t *testing.T) { func TestReplicationControllerResize(t *testing.T) {
fake := &testclient.Fake{} fake := &testclient.Fake{}
resizer := ReplicationControllerResizer{fake} resizer := ReplicationControllerResizer{NewResizerClient(fake)}
preconditions := ResizePrecondition{-1, ""} preconditions := ResizePrecondition{-1, ""}
count := uint(3) count := uint(3)
name := "foo" name := "foo"
@ -90,7 +90,7 @@ func TestReplicationControllerResizeFailsPreconditions(t *testing.T) {
Replicas: 10, Replicas: 10,
}, },
}) })
resizer := ReplicationControllerResizer{fake} resizer := ReplicationControllerResizer{NewResizerClient(fake)}
preconditions := ResizePrecondition{2, ""} preconditions := ResizePrecondition{2, ""}
count := uint(3) count := uint(3)
name := "foo" name := "foo"

View File

@ -31,13 +31,13 @@ import (
// fault-tolerant way. // fault-tolerant way.
type RollingUpdater struct { type RollingUpdater struct {
// Client interface for creating and updating controllers // Client interface for creating and updating controllers
c client.Interface c RollingUpdaterClient
// Namespace for resources // Namespace for resources
ns string ns string
} }
// NewRollingUpdater creates a RollingUpdater from a client // NewRollingUpdater creates a RollingUpdater from a client
func NewRollingUpdater(namespace string, c client.Interface) *RollingUpdater { func NewRollingUpdater(namespace string, c RollingUpdaterClient) *RollingUpdater {
return &RollingUpdater{ return &RollingUpdater{
c, c,
namespace, namespace,
@ -95,7 +95,7 @@ func (r *RollingUpdater) Update(out io.Writer, oldRc, newRc *api.ReplicationCont
newRc.ObjectMeta.Annotations[desiredReplicasAnnotation] = fmt.Sprintf("%d", desired) newRc.ObjectMeta.Annotations[desiredReplicasAnnotation] = fmt.Sprintf("%d", desired)
newRc.ObjectMeta.Annotations[sourceIdAnnotation] = sourceId newRc.ObjectMeta.Annotations[sourceIdAnnotation] = sourceId
newRc.Spec.Replicas = 0 newRc.Spec.Replicas = 0
newRc, err = r.c.ReplicationControllers(r.ns).Create(newRc) newRc, err = r.c.CreateReplicationController(r.ns, newRc)
if err != nil { if err != nil {
return err return err
} }
@ -147,7 +147,7 @@ func (r *RollingUpdater) Update(out io.Writer, oldRc, newRc *api.ReplicationCont
} }
} }
// Clean up annotations // Clean up annotations
if newRc, err = r.c.ReplicationControllers(r.ns).Get(newName); err != nil { if newRc, err = r.c.GetReplicationController(r.ns, newName); err != nil {
return err return err
} }
delete(newRc.ObjectMeta.Annotations, sourceIdAnnotation) delete(newRc.ObjectMeta.Annotations, sourceIdAnnotation)
@ -158,11 +158,11 @@ func (r *RollingUpdater) Update(out io.Writer, oldRc, newRc *api.ReplicationCont
} }
// delete old rc // delete old rc
fmt.Fprintf(out, "Update succeeded. Deleting %s\n", oldName) fmt.Fprintf(out, "Update succeeded. Deleting %s\n", oldName)
return r.c.ReplicationControllers(r.ns).Delete(oldName) return r.c.DeleteReplicationController(r.ns, oldName)
} }
func (r *RollingUpdater) getExistingNewRc(sourceId, name string) (rc *api.ReplicationController, existing bool, err error) { func (r *RollingUpdater) getExistingNewRc(sourceId, name string) (rc *api.ReplicationController, existing bool, err error) {
if rc, err = r.c.ReplicationControllers(r.ns).Get(name); err == nil { if rc, err = r.c.GetReplicationController(r.ns, name); err == nil {
existing = true existing = true
annotations := rc.ObjectMeta.Annotations annotations := rc.ObjectMeta.Annotations
source := annotations[sourceIdAnnotation] source := annotations[sourceIdAnnotation]
@ -184,17 +184,54 @@ func (r *RollingUpdater) resizeAndWait(rc *api.ReplicationController, retry *Ret
if err := resizer.Resize(rc.Namespace, rc.Name, uint(rc.Spec.Replicas), &ResizePrecondition{-1, ""}, retry, wait); err != nil { if err := resizer.Resize(rc.Namespace, rc.Name, uint(rc.Spec.Replicas), &ResizePrecondition{-1, ""}, retry, wait); err != nil {
return nil, err return nil, err
} }
return r.c.ReplicationControllers(r.ns).Get(rc.ObjectMeta.Name) return r.c.GetReplicationController(r.ns, rc.ObjectMeta.Name)
} }
func (r *RollingUpdater) updateAndWait(rc *api.ReplicationController, interval, timeout time.Duration) (*api.ReplicationController, error) { func (r *RollingUpdater) updateAndWait(rc *api.ReplicationController, interval, timeout time.Duration) (*api.ReplicationController, error) {
rc, err := r.c.ReplicationControllers(r.ns).Update(rc) rc, err := r.c.UpdateReplicationController(r.ns, rc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = wait.Poll(interval, timeout, if err = wait.Poll(interval, timeout, r.c.ControllerHasDesiredReplicas(rc)); err != nil {
client.ControllerHasDesiredReplicas(r.c, rc)); err != nil {
return nil, err return nil, err
} }
return r.c.ReplicationControllers(r.ns).Get(rc.ObjectMeta.Name) return r.c.GetReplicationController(r.ns, rc.ObjectMeta.Name)
}
// RollingUpdaterClient abstracts access to ReplicationControllers.
type RollingUpdaterClient interface {
GetReplicationController(namespace, name string) (*api.ReplicationController, error)
UpdateReplicationController(namespace string, rc *api.ReplicationController) (*api.ReplicationController, error)
CreateReplicationController(namespace string, rc *api.ReplicationController) (*api.ReplicationController, error)
DeleteReplicationController(namespace, name string) error
ControllerHasDesiredReplicas(rc *api.ReplicationController) wait.ConditionFunc
}
func NewRollingUpdaterClient(c client.Interface) RollingUpdaterClient {
return &realRollingUpdaterClient{c}
}
// realRollingUpdaterClient is a RollingUpdaterClient which uses a Kube client.
type realRollingUpdaterClient struct {
client client.Interface
}
func (c *realRollingUpdaterClient) GetReplicationController(namespace, name string) (*api.ReplicationController, error) {
return c.client.ReplicationControllers(namespace).Get(name)
}
func (c *realRollingUpdaterClient) UpdateReplicationController(namespace string, rc *api.ReplicationController) (*api.ReplicationController, error) {
return c.client.ReplicationControllers(namespace).Update(rc)
}
func (c *realRollingUpdaterClient) CreateReplicationController(namespace string, rc *api.ReplicationController) (*api.ReplicationController, error) {
return c.client.ReplicationControllers(namespace).Create(rc)
}
func (c *realRollingUpdaterClient) DeleteReplicationController(namespace, name string) error {
return c.client.ReplicationControllers(namespace).Delete(name)
}
func (c *realRollingUpdaterClient) ControllerHasDesiredReplicas(rc *api.ReplicationController) wait.ConditionFunc {
return client.ControllerHasDesiredReplicas(c.client, rc)
} }

View File

@ -253,7 +253,7 @@ Update succeeded. Deleting foo-v1
for _, test := range tests { for _, test := range tests {
updater := RollingUpdater{ updater := RollingUpdater{
fakeClientFor("default", test.responses), NewRollingUpdaterClient(fakeClientFor("default", test.responses)),
"default", "default",
} }
var buffer bytes.Buffer var buffer bytes.Buffer
@ -296,7 +296,7 @@ Update succeeded. Deleting foo-v1
{newRc(3, 3), nil}, {newRc(3, 3), nil},
{newRc(3, 3), nil}, {newRc(3, 3), nil},
} }
updater := RollingUpdater{fakeClientFor("default", responses), "default"} updater := RollingUpdater{NewRollingUpdaterClient(fakeClientFor("default", responses)), "default"}
var buffer bytes.Buffer var buffer bytes.Buffer
if err := updater.Update(&buffer, rc, rcExisting, 0, time.Millisecond, time.Millisecond); err != nil { if err := updater.Update(&buffer, rc, rcExisting, 0, time.Millisecond, time.Millisecond); err != nil {

View File

@ -65,7 +65,7 @@ type objInterface interface {
func (reaper *ReplicationControllerReaper) Stop(namespace, name string) (string, error) { func (reaper *ReplicationControllerReaper) Stop(namespace, name string) (string, error) {
rc := reaper.ReplicationControllers(namespace) rc := reaper.ReplicationControllers(namespace)
resizer, err := ResizerFor("ReplicationController", *reaper) resizer, err := ResizerFor("ReplicationController", NewResizerClient(*reaper))
if err != nil { if err != nil {
return "", err return "", err
} }