mirror of https://github.com/k3s-io/k3s
Merge pull request #34443 from kargakis/add-revision-flag-in-rollout-status
Automatic merge from submit-queue kubectl: add --revision flag in rollout status Fixes https://github.com/kubernetes/kubernetes/issues/33185 @kubernetes/kubectl ptalpull/6/head
commit
5859bebf13
|
@ -2168,6 +2168,8 @@ __EOF__
|
||||||
kubectl rollout undo deployment nginx "${kube_flags[@]}"
|
kubectl rollout undo deployment nginx "${kube_flags[@]}"
|
||||||
# Check that the new replica set (nginx-618515232) has all old revisions stored in an annotation
|
# Check that the new replica set (nginx-618515232) has all old revisions stored in an annotation
|
||||||
kubectl get rs nginx-618515232 -o yaml | grep "deployment.kubernetes.io/revision-history: 1,3"
|
kubectl get rs nginx-618515232 -o yaml | grep "deployment.kubernetes.io/revision-history: 1,3"
|
||||||
|
# Check that trying to watch the status of a superseded revision returns an error
|
||||||
|
! kubectl rollout status deployment/nginx --revision=3
|
||||||
# Clean up
|
# Clean up
|
||||||
kubectl delete deployment nginx "${kube_flags[@]}"
|
kubectl delete deployment nginx "${kube_flags[@]}"
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,13 @@ import (
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/annotations"
|
"k8s.io/kubernetes/pkg/api/annotations"
|
||||||
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/errors"
|
"k8s.io/kubernetes/pkg/util/errors"
|
||||||
"k8s.io/kubernetes/pkg/util/integer"
|
"k8s.io/kubernetes/pkg/util/integer"
|
||||||
intstrutil "k8s.io/kubernetes/pkg/util/intstr"
|
intstrutil "k8s.io/kubernetes/pkg/util/intstr"
|
||||||
|
@ -117,9 +119,13 @@ func LastRevision(allRSs []*extensions.ReplicaSet) int64 {
|
||||||
return secMax
|
return secMax
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revision returns the revision number of the input replica set
|
// Revision returns the revision number of the input object.
|
||||||
func Revision(rs *extensions.ReplicaSet) (int64, error) {
|
func Revision(obj runtime.Object) (int64, error) {
|
||||||
v, ok := rs.Annotations[RevisionAnnotation]
|
acc, err := meta.Accessor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v, ok := acc.GetAnnotations()[RevisionAnnotation]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,9 @@ func RunHistory(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []st
|
||||||
return cmdutil.UsageError(cmd, "Required resource not specified.")
|
return cmdutil.UsageError(cmd, "Required resource not specified.")
|
||||||
}
|
}
|
||||||
revision := cmdutil.GetFlagInt64(cmd, "revision")
|
revision := cmdutil.GetFlagInt64(cmd, "revision")
|
||||||
|
if revision < 0 {
|
||||||
|
return fmt.Errorf("revision must be a positive integer: %v", revision)
|
||||||
|
}
|
||||||
|
|
||||||
mapper, typer := f.Object()
|
mapper, typer := f.Object()
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,14 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
status_long = dedent.Dedent(`
|
status_long = dedent.Dedent(`
|
||||||
Show the status of the newest rollout.
|
Show the status of the rollout.
|
||||||
|
|
||||||
By default 'rollout status' will watch the status of the newest rollout
|
By default 'rollout status' will watch the status of the latest rollout
|
||||||
until it's done. If you don't want to wait for the rollout to finish then
|
until it's done. If you don't want to wait for the rollout to finish then
|
||||||
you can use --watch=false.`)
|
you can use --watch=false. Note that if a new rollout starts in-between, then
|
||||||
|
'rollout status' will continue watching the latest revision. If you want to
|
||||||
|
pin to a specific revision and abort if it is rolled over by another revision,
|
||||||
|
use --revision=N where N is the revision you need to watch for.`)
|
||||||
status_example = dedent.Dedent(`
|
status_example = dedent.Dedent(`
|
||||||
# Watch the rollout status of a deployment
|
# Watch the rollout status of a deployment
|
||||||
kubectl rollout status deployment/nginx`)
|
kubectl rollout status deployment/nginx`)
|
||||||
|
@ -50,7 +53,7 @@ func NewCmdRolloutStatus(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "status (TYPE NAME | TYPE/NAME) [flags]",
|
Use: "status (TYPE NAME | TYPE/NAME) [flags]",
|
||||||
Short: "Show the status of newest rollout",
|
Short: "Show the status of the rollout",
|
||||||
Long: status_long,
|
Long: status_long,
|
||||||
Example: status_example,
|
Example: status_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
@ -62,7 +65,8 @@ func NewCmdRolloutStatus(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
|
|
||||||
usage := "identifying the resource to get from a server."
|
usage := "identifying the resource to get from a server."
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||||
cmd.Flags().BoolP("watch", "w", true, "Watch the status of the newest rollout until it's done.")
|
cmd.Flags().BoolP("watch", "w", true, "Watch the status of the rollout until it's done.")
|
||||||
|
cmd.Flags().Int64("revision", 0, "Pin to a specific revision for showing its status. Defaults to 0 (last revision).")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +118,13 @@ func RunStatus(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []str
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
revision := cmdutil.GetFlagInt64(cmd, "revision")
|
||||||
|
if revision < 0 {
|
||||||
|
return fmt.Errorf("revision must be a positive integer: %v", revision)
|
||||||
|
}
|
||||||
|
|
||||||
// check if deployment's has finished the rollout
|
// check if deployment's has finished the rollout
|
||||||
status, done, err := statusViewer.Status(cmdNamespace, info.Name)
|
status, done, err := statusViewer.Status(cmdNamespace, info.Name, revision)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -140,7 +149,7 @@ func RunStatus(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []str
|
||||||
return intr.Run(func() error {
|
return intr.Run(func() error {
|
||||||
_, err := watch.Until(0, w, func(e watch.Event) (bool, error) {
|
_, err := watch.Until(0, w, func(e watch.Event) (bool, error) {
|
||||||
// print deployment's status
|
// print deployment's status
|
||||||
status, done, err := statusViewer.Status(cmdNamespace, info.Name)
|
status, done, err := statusViewer.Status(cmdNamespace, info.Name, revision)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,12 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/unversioned"
|
extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StatusViewer provides an interface for resources that provides rollout status.
|
// StatusViewer provides an interface for resources that have rollout status.
|
||||||
type StatusViewer interface {
|
type StatusViewer interface {
|
||||||
Status(namespace, name string) (string, bool, error)
|
Status(namespace, name string, revision int64) (string, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatusViewerFor(kind unversioned.GroupKind, c internalclientset.Interface) (StatusViewer, error) {
|
func StatusViewerFor(kind unversioned.GroupKind, c internalclientset.Interface) (StatusViewer, error) {
|
||||||
|
@ -43,11 +44,20 @@ type DeploymentStatusViewer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status returns a message describing deployment status, and a bool value indicating if the status is considered done
|
// Status returns a message describing deployment status, and a bool value indicating if the status is considered done
|
||||||
func (s *DeploymentStatusViewer) Status(namespace, name string) (string, bool, error) {
|
func (s *DeploymentStatusViewer) Status(namespace, name string, revision int64) (string, bool, error) {
|
||||||
deployment, err := s.c.Deployments(namespace).Get(name)
|
deployment, err := s.c.Deployments(namespace).Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false, err
|
return "", false, err
|
||||||
}
|
}
|
||||||
|
if revision > 0 {
|
||||||
|
deploymentRev, err := util.Revision(deployment)
|
||||||
|
if err != nil {
|
||||||
|
return "", false, fmt.Errorf("cannot get the revision of deployment %q: %v", deployment.Name, err)
|
||||||
|
}
|
||||||
|
if revision != deploymentRev {
|
||||||
|
return "", false, fmt.Errorf("desired revision (%d) is different from the running revision (%d)", revision, deploymentRev)
|
||||||
|
}
|
||||||
|
}
|
||||||
if deployment.Generation <= deployment.Status.ObservedGeneration {
|
if deployment.Generation <= deployment.Status.ObservedGeneration {
|
||||||
if deployment.Status.UpdatedReplicas < deployment.Spec.Replicas {
|
if deployment.Status.UpdatedReplicas < deployment.Spec.Replicas {
|
||||||
return fmt.Sprintf("Waiting for rollout to finish: %d out of %d new replicas have been updated...\n", deployment.Status.UpdatedReplicas, deployment.Spec.Replicas), false, nil
|
return fmt.Sprintf("Waiting for rollout to finish: %d out of %d new replicas have been updated...\n", deployment.Status.UpdatedReplicas, deployment.Spec.Replicas), false, nil
|
||||||
|
@ -58,7 +68,7 @@ func (s *DeploymentStatusViewer) Status(namespace, name string) (string, bool, e
|
||||||
if deployment.Status.AvailableReplicas < deployment.Status.UpdatedReplicas {
|
if deployment.Status.AvailableReplicas < deployment.Status.UpdatedReplicas {
|
||||||
return fmt.Sprintf("Waiting for rollout to finish: %d of %d updated replicas are available...\n", deployment.Status.AvailableReplicas, deployment.Status.UpdatedReplicas), false, nil
|
return fmt.Sprintf("Waiting for rollout to finish: %d of %d updated replicas are available...\n", deployment.Status.AvailableReplicas, deployment.Status.UpdatedReplicas), false, nil
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("deployment %s successfully rolled out\n", name), true, nil
|
return fmt.Sprintf("deployment %q successfully rolled out\n", name), true, nil
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("Waiting for deployment spec update to be observed...\n"), false, nil
|
return fmt.Sprintf("Waiting for deployment spec update to be observed...\n"), false, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ func TestDeploymentStatusViewerStatus(t *testing.T) {
|
||||||
UnavailableReplicas: 0,
|
UnavailableReplicas: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
msg: "deployment foo successfully rolled out\n",
|
msg: "deployment \"foo\" successfully rolled out\n",
|
||||||
done: true,
|
done: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -119,7 +119,7 @@ func TestDeploymentStatusViewerStatus(t *testing.T) {
|
||||||
}
|
}
|
||||||
client := fake.NewSimpleClientset(d).Extensions()
|
client := fake.NewSimpleClientset(d).Extensions()
|
||||||
dsv := &DeploymentStatusViewer{c: client}
|
dsv := &DeploymentStatusViewer{c: client}
|
||||||
msg, done, err := dsv.Status("bar", "foo")
|
msg, done, err := dsv.Status("bar", "foo", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("DeploymentStatusViewer.Status(): %v", err)
|
t.Fatalf("DeploymentStatusViewer.Status(): %v", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue