diff --git a/_proto/hapi/services/tiller.proto b/_proto/hapi/services/tiller.proto index ed2f3c700..af27dba22 100644 --- a/_proto/hapi/services/tiller.proto +++ b/_proto/hapi/services/tiller.proto @@ -188,6 +188,8 @@ message UpdateReleaseRequest { bool dry_run = 4; // DisableHooks causes the server to skip running any hooks for the upgrade. bool disable_hooks = 5; + // Performs pods restart for resources if applicable + bool restart = 6; } // UpdateReleaseResponse is the response to an update request. @@ -204,6 +206,8 @@ message RollbackReleaseRequest { bool disable_hooks = 3; // Version is the version of the release to deploy. int32 version = 4; + // Performs pods restart for resources if applicable + bool restart = 5; } // RollbackReleaseResponse is the response to an update request. diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 4159db388..bd46d6665 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -35,6 +35,7 @@ type rollbackCmd struct { name string revision int32 dryRun bool + restart bool disableHooks bool out io.Writer client helm.Interface @@ -71,6 +72,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { f := cmd.Flags() f.BoolVar(&rollback.dryRun, "dry-run", false, "simulate a rollback") + f.BoolVar(&rollback.restart, "restart", false, "performs pods restart for the resource if applicable") f.BoolVar(&rollback.disableHooks, "no-hooks", false, "prevent hooks from running during rollback") return cmd @@ -80,6 +82,7 @@ func (r *rollbackCmd) run() error { _, err := r.client.RollbackRelease( r.name, helm.RollbackDryRun(r.dryRun), + helm.RollbackRestart(r.restart), helm.RollbackDisableHooks(r.disableHooks), helm.RollbackVersion(r.revision), ) diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 7fd8a273c..d8627e423 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -54,6 +54,7 @@ type upgradeCmd struct { out io.Writer client helm.Interface dryRun bool + restart bool disableHooks bool valueFiles valueFiles values string @@ -92,6 +93,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f := cmd.Flags() f.VarP(&upgrade.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade") + f.BoolVar(&upgrade.restart, "restart", false, "performs pods restart for the resource if applicable") f.StringVar(&upgrade.values, "set", "", "set values on the command line. Separate values with commas: key1=val1,key2=val2") f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks. DEPRECATED. Use no-hooks") f.BoolVar(&upgrade.disableHooks, "no-hooks", false, "disable pre/post upgrade hooks") @@ -149,6 +151,7 @@ func (u *upgradeCmd) run() error { chartPath, helm.UpdateValueOverrides(rawVals), helm.UpgradeDryRun(u.dryRun), + helm.UpgradeRestart(u.restart), helm.UpgradeDisableHooks(u.disableHooks)) if err != nil { return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 5ae781328..bb1793bb5 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -133,6 +133,7 @@ func (h *Client) UpdateRelease(rlsName string, chstr string, opts ...UpdateOptio req.DryRun = h.opts.dryRun req.Name = rlsName req.DisableHooks = h.opts.disableHooks + req.Restart = h.opts.restart ctx := NewContext() if h.opts.before != nil { diff --git a/pkg/helm/option.go b/pkg/helm/option.go index a445e8643..8e0f3651d 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -40,6 +40,8 @@ type options struct { dryRun bool // if set, re-use an existing name reuseName bool + // + restart bool // if set, skip running hooks disableHooks bool // name of release @@ -212,6 +214,13 @@ func RollbackDryRun(dry bool) RollbackOption { } } +// RollbackDryRun will (if true) execute a rollback as a dry run. +func RollbackRestart(restart bool) RollbackOption { + return func(opts *options) { + opts.restart = restart + } +} + // RollbackVersion sets the version of the release to deploy. func RollbackVersion(ver int32) RollbackOption { return func(opts *options) { @@ -233,6 +242,13 @@ func UpgradeDryRun(dry bool) UpdateOption { } } +// UpgradeDryRun will (if true) execute an upgrade as a dry run. +func UpgradeRestart(restart bool) UpdateOption { + return func(opts *options) { + opts.restart = restart + } +} + // ContentOption allows setting optional attributes when // performing a GetReleaseContent tiller rpc. type ContentOption func(*options) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 3f64778ab..9936cebab 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -164,7 +164,7 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // not present in the target configuration // // Namespace will set the namespaces -func (c *Client) Update(namespace string, currentReader, targetReader io.Reader) error { +func (c *Client) Update(namespace string, currentReader, targetReader io.Reader, restart bool) error { currentInfos, err := c.newBuilder(namespace, currentReader).Do().Infos() if err != nil { return fmt.Errorf("failed decoding reader into objects: %s", err) @@ -205,7 +205,7 @@ func (c *Client) Update(namespace string, currentReader, targetReader io.Reader) return err } - if err := updateResource(c, info, currentObj); err != nil { + if err := updateResource(c, info, currentObj, restart); err != nil { if alreadyExistErr, ok := err.(ErrAlreadyExists); ok { log.Printf(alreadyExistErr.errorMsg) } else { @@ -301,7 +301,7 @@ func deleteResource(info *resource.Info) error { return resource.NewHelper(info.Client, info.Mapping).Delete(info.Namespace, info.Name) } -func updateResource(c *Client, target *resource.Info, currentObj runtime.Object) error { +func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, restart bool) error { encoder := api.Codecs.LegacyCodec(registered.EnabledVersions()...) original, err := runtime.Encode(encoder, currentObj) if err != nil { @@ -330,22 +330,24 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object) return err } - kind := target.Mapping.GroupVersionKind.Kind - - client, _ := c.ClientSet() - switch kind { - case "ReplicationController": - rc := currentObj.(*v1.ReplicationController) - err = restartPods(client, target.Namespace, rc.Spec.Selector) - case "DaemonSet": - daemonSet := currentObj.(*v1beta1.DaemonSet) - err = restartPods(client, target.Namespace, daemonSet.Spec.Selector.MatchLabels) - case "StatefulSet": - petSet := currentObj.(*apps.StatefulSet) - err = restartPods(client, target.Namespace, petSet.Spec.Selector.MatchLabels) + if restart { + kind := target.Mapping.GroupVersionKind.Kind + + client, _ := c.ClientSet() + switch kind { + case "ReplicationController": + rc := currentObj.(*v1.ReplicationController) + err = restartPods(client, target.Namespace, rc.Spec.Selector) + case "DaemonSet": + daemonSet := currentObj.(*v1beta1.DaemonSet) + err = restartPods(client, target.Namespace, daemonSet.Spec.Selector.MatchLabels) + case "StatefulSet": + petSet := currentObj.(*apps.StatefulSet) + err = restartPods(client, target.Namespace, petSet.Spec.Selector.MatchLabels) case "ReplicaSet": replicaSet := currentObj.(*v1beta1.ReplicaSet) err = restartPods(client, target.Namespace, replicaSet.Spec.Selector.MatchLabels) + } } return err diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 2c6ed8148..4d2d843ba 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -246,6 +246,8 @@ type UpdateReleaseRequest struct { DryRun bool `protobuf:"varint,4,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"` // DisableHooks causes the server to skip running any hooks for the upgrade. DisableHooks bool `protobuf:"varint,5,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"` + // Performs pods restart for resources if applicable + Restart bool `protobuf:"varint,6,opt,name=restart,json=restart" json:"restart,omitempty"` } func (m *UpdateReleaseRequest) Reset() { *m = UpdateReleaseRequest{} } @@ -293,6 +295,8 @@ type RollbackReleaseRequest struct { DisableHooks bool `protobuf:"varint,3,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"` // Version is the version of the release to deploy. Version int32 `protobuf:"varint,4,opt,name=version" json:"version,omitempty"` + // Performs pods restart for resources if applicable + Restart bool `protobuf:"varint,5,opt,name=restart,json=restart" json:"restart,omitempty"` } func (m *RollbackReleaseRequest) Reset() { *m = RollbackReleaseRequest{} } diff --git a/pkg/tiller/environment/environment.go b/pkg/tiller/environment/environment.go index 1b2aa4e6d..bde2740ad 100644 --- a/pkg/tiller/environment/environment.go +++ b/pkg/tiller/environment/environment.go @@ -131,7 +131,7 @@ type KubeClient interface { // // reader must contain a YAML stream (one or more YAML documents separated // by "\n---\n"). - Update(namespace string, originalReader, modifiedReader io.Reader) error + Update(namespace string, originalReader, modifiedReader io.Reader, restart bool) error } // PrintingKubeClient implements KubeClient, but simply prints the reader to diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index e5266c509..62d8a3c53 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -340,7 +340,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R } } - if err := s.performKubeUpdate(originalRelease, updatedRelease); err != nil { + if err := s.performKubeUpdate(originalRelease, updatedRelease, req.Restart); err != nil { log.Printf("warning: Release Upgrade %q failed: %s", updatedRelease.Name, err) originalRelease.Info.Status.Code = release.Status_SUPERSEDED updatedRelease.Info.Status.Code = release.Status_FAILED @@ -472,7 +472,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R } } - if err := s.performKubeUpdate(currentRelease, targetRelease); err != nil { + if err := s.performKubeUpdate(currentRelease, targetRelease, req.Restart); err != nil { log.Printf("warning: Release Rollback %q failed: %s", targetRelease.Name, err) currentRelease.Info.Status.Code = release.Status_SUPERSEDED targetRelease.Info.Status.Code = release.Status_FAILED @@ -496,11 +496,11 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R return res, nil } -func (s *ReleaseServer) performKubeUpdate(currentRelease, targetRelease *release.Release) error { +func (s *ReleaseServer) performKubeUpdate(currentRelease, targetRelease *release.Release, restart bool) error { kubeCli := s.env.KubeClient current := bytes.NewBufferString(currentRelease.Manifest) target := bytes.NewBufferString(targetRelease.Manifest) - return kubeCli.Update(targetRelease.Namespace, current, target) + return kubeCli.Update(targetRelease.Namespace, current, target, restart) } // prepareRollback finds the previous release and prepares a new release object with @@ -818,7 +818,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install // so as to append to the old release's history r.Version = old.Version + 1 - if err := s.performKubeUpdate(old, r); err != nil { + if err := s.performKubeUpdate(old, r, false); err != nil { log.Printf("warning: Release replace %q failed: %s", r.Name, err) old.Info.Status.Code = release.Status_SUPERSEDED r.Info.Status.Code = release.Status_FAILED