mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
rollout undo add dry-run implementation
This commit is contained in:
parent
85c91eb332
commit
6a68dbdac4
@ -1931,6 +1931,9 @@ __EOF__
|
|||||||
# Update the deployment (revision 2)
|
# Update the deployment (revision 2)
|
||||||
kubectl apply -f hack/testdata/deployment-revision2.yaml "${kube_flags[@]}"
|
kubectl apply -f hack/testdata/deployment-revision2.yaml "${kube_flags[@]}"
|
||||||
kube::test::get_object_assert deployment.extensions "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
|
kube::test::get_object_assert deployment.extensions "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
|
||||||
|
# Rollback to revision 1 with dry-run - should be no-op
|
||||||
|
kubectl rollout undo deployment nginx --to-revision=1 --dry-run=true "${kube_flags[@]}"
|
||||||
|
kube::test::get_object_assert deployment.extensions "{{range.items}}{{$deployment_image_field}}:{{end}}" "${IMAGE_DEPLOYMENT_R2}:"
|
||||||
# Rollback to revision 1
|
# Rollback to revision 1
|
||||||
kubectl rollout undo deployment nginx --to-revision=1 "${kube_flags[@]}"
|
kubectl rollout undo deployment nginx --to-revision=1 "${kube_flags[@]}"
|
||||||
sleep 1
|
sleep 1
|
||||||
|
@ -38,6 +38,7 @@ type UndoOptions struct {
|
|||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
Infos []*resource.Info
|
Infos []*resource.Info
|
||||||
ToRevision int64
|
ToRevision int64
|
||||||
|
DryRun bool
|
||||||
|
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
Filenames []string
|
Filenames []string
|
||||||
@ -52,7 +53,10 @@ var (
|
|||||||
kubectl rollout undo deployment/abc
|
kubectl rollout undo deployment/abc
|
||||||
|
|
||||||
# Rollback to deployment revision 3
|
# Rollback to deployment revision 3
|
||||||
kubectl rollout undo deployment/abc --to-revision=3`)
|
kubectl rollout undo deployment/abc --to-revision=3
|
||||||
|
|
||||||
|
# Rollback to the previous deployment with dry-run
|
||||||
|
kubectl rollout undo --dry-run=true deployment/abc`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdRolloutUndo(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
func NewCmdRolloutUndo(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
@ -80,6 +84,7 @@ func NewCmdRolloutUndo(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().Int64("to-revision", 0, "The revision to rollback to. Default to 0 (last revision).")
|
cmd.Flags().Int64("to-revision", 0, "The revision to rollback to. Default to 0 (last revision).")
|
||||||
usage := "Filename, directory, or URL to a file identifying the resource to get from a server."
|
usage := "Filename, directory, or URL to a file identifying the resource to get from a server."
|
||||||
kubectl.AddJsonFilenameFlag(cmd, &opts.Filenames, usage)
|
kubectl.AddJsonFilenameFlag(cmd, &opts.Filenames, usage)
|
||||||
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmdutil.AddRecursiveFlag(cmd, &opts.Recursive)
|
cmdutil.AddRecursiveFlag(cmd, &opts.Recursive)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -92,6 +97,7 @@ func (o *UndoOptions) CompleteUndo(f *cmdutil.Factory, cmd *cobra.Command, out i
|
|||||||
o.ToRevision = cmdutil.GetFlagInt64(cmd, "to-revision")
|
o.ToRevision = cmdutil.GetFlagInt64(cmd, "to-revision")
|
||||||
o.Mapper, o.Typer = f.Object(false)
|
o.Mapper, o.Typer = f.Object(false)
|
||||||
o.Out = out
|
o.Out = out
|
||||||
|
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||||
|
|
||||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -129,7 +135,7 @@ func (o *UndoOptions) CompleteUndo(f *cmdutil.Factory, cmd *cobra.Command, out i
|
|||||||
func (o *UndoOptions) RunUndo() error {
|
func (o *UndoOptions) RunUndo() error {
|
||||||
allErrs := []error{}
|
allErrs := []error{}
|
||||||
for ix, info := range o.Infos {
|
for ix, info := range o.Infos {
|
||||||
result, err := o.Rollbackers[ix].Rollback(info.Object, nil, o.ToRevision)
|
result, err := o.Rollbackers[ix].Rollback(info.Object, nil, o.ToRevision, o.DryRun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
allErrs = append(allErrs, cmdutil.AddSourceToErr("undoing", info.Source, err))
|
allErrs = append(allErrs, cmdutil.AddSourceToErr("undoing", info.Source, err))
|
||||||
continue
|
continue
|
||||||
|
@ -631,10 +631,10 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||||||
HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) {
|
HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) {
|
||||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||||
client, err := clients.ClientForVersion(&mappingVersion)
|
client, err := clients.ClientForVersion(&mappingVersion)
|
||||||
clientset := clientset.FromUnversionedClient(client)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
clientset := clientset.FromUnversionedClient(client)
|
||||||
return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset)
|
return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset)
|
||||||
},
|
},
|
||||||
Rollbacker: func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) {
|
Rollbacker: func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) {
|
||||||
@ -643,7 +643,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), client)
|
clientset := clientset.FromUnversionedClient(client)
|
||||||
|
return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), clientset)
|
||||||
},
|
},
|
||||||
StatusViewer: func(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) {
|
StatusViewer: func(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) {
|
||||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package kubectl
|
package kubectl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@ -25,18 +26,19 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
sliceutil "k8s.io/kubernetes/pkg/util/slice"
|
||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Rollbacker provides an interface for resources that can be rolled back.
|
// Rollbacker provides an interface for resources that can be rolled back.
|
||||||
type Rollbacker interface {
|
type Rollbacker interface {
|
||||||
Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64) (string, error)
|
Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64, dryRun bool) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RollbackerFor(kind unversioned.GroupKind, c client.Interface) (Rollbacker, error) {
|
func RollbackerFor(kind unversioned.GroupKind, c clientset.Interface) (Rollbacker, error) {
|
||||||
switch kind {
|
switch kind {
|
||||||
case extensions.Kind("Deployment"):
|
case extensions.Kind("Deployment"):
|
||||||
return &DeploymentRollbacker{c}, nil
|
return &DeploymentRollbacker{c}, nil
|
||||||
@ -45,14 +47,17 @@ func RollbackerFor(kind unversioned.GroupKind, c client.Interface) (Rollbacker,
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DeploymentRollbacker struct {
|
type DeploymentRollbacker struct {
|
||||||
c client.Interface
|
c clientset.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64) (string, error) {
|
func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64, dryRun bool) (string, error) {
|
||||||
d, ok := obj.(*extensions.Deployment)
|
d, ok := obj.(*extensions.Deployment)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("passed object is not a Deployment: %#v", obj)
|
return "", fmt.Errorf("passed object is not a Deployment: %#v", obj)
|
||||||
}
|
}
|
||||||
|
if dryRun {
|
||||||
|
return simpleDryRun(d, r.c, toRevision)
|
||||||
|
}
|
||||||
if d.Spec.Paused {
|
if d.Spec.Paused {
|
||||||
return "", fmt.Errorf("you cannot rollback a paused deployment; resume it first with 'kubectl rollout resume deployment/%s' and try again", d.Name)
|
return "", fmt.Errorf("you cannot rollback a paused deployment; resume it first with 'kubectl rollout resume deployment/%s' and try again", d.Name)
|
||||||
}
|
}
|
||||||
@ -66,7 +71,7 @@ func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations m
|
|||||||
result := ""
|
result := ""
|
||||||
|
|
||||||
// Get current events
|
// Get current events
|
||||||
events, err := r.c.Events(d.Namespace).List(api.ListOptions{})
|
events, err := r.c.Core().Events(d.Namespace).List(api.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
@ -75,7 +80,7 @@ func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations m
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
// Watch for the changes of events
|
// Watch for the changes of events
|
||||||
watch, err := r.c.Events(d.Namespace).Watch(api.ListOptions{Watch: true, ResourceVersion: events.ResourceVersion})
|
watch, err := r.c.Core().Events(d.Namespace).Watch(api.ListOptions{Watch: true, ResourceVersion: events.ResourceVersion})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
@ -123,3 +128,50 @@ func isRollbackEvent(e *api.Event) (bool, string) {
|
|||||||
}
|
}
|
||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRevision int64) (string, error) {
|
||||||
|
_, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, c)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", deployment.Name, err)
|
||||||
|
}
|
||||||
|
allRSs := allOldRSs
|
||||||
|
if newRS != nil {
|
||||||
|
allRSs = append(allRSs, newRS)
|
||||||
|
}
|
||||||
|
|
||||||
|
revisionToSpec := make(map[int64]*api.PodTemplateSpec)
|
||||||
|
for _, rs := range allRSs {
|
||||||
|
v, err := deploymentutil.Revision(rs)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
revisionToSpec[v] = &rs.Spec.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(revisionToSpec) == 0 {
|
||||||
|
return "No rollout history found.", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if toRevision > 0 {
|
||||||
|
template, ok := revisionToSpec[toRevision]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("unable to find specified revision")
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
DescribePodTemplate(template, buf)
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the revisionToSpec map by revision
|
||||||
|
revisions := make([]int64, 0, len(revisionToSpec))
|
||||||
|
for r := range revisionToSpec {
|
||||||
|
revisions = append(revisions, r)
|
||||||
|
}
|
||||||
|
sliceutil.SortInts64(revisions)
|
||||||
|
|
||||||
|
template, _ := revisionToSpec[revisions[len(revisions)-1]]
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
buf.WriteString("\n")
|
||||||
|
DescribePodTemplate(template, buf)
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user