-
Notifications
You must be signed in to change notification settings - Fork 819
/
status.go
138 lines (121 loc) · 3.93 KB
/
status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package status
import (
"context"
"fmt"
"time"
"github.com/argoproj/argo-rollouts/pkg/apiclient/rollout"
"github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/signals"
"github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options"
completionutil "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/util/completion"
"github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/viewcontroller"
"github.com/spf13/cobra"
)
const (
statusLong = `Watch rollout until it finishes or the timeout is exceeded. Returns success if
the rollout is healthy upon completion and an error otherwise.`
statusExample = `
# Watch the rollout until it succeeds
%[1]s status guestbook
# Watch the rollout until it succeeds, fail if it takes more than 60 seconds
%[1]s status --timeout 60s guestbook
`
)
type StatusOptions struct {
Watch bool
Timeout time.Duration
options.ArgoRolloutsOptions
}
// NewCmdStatus returns a new instance of a `rollouts status` command
func NewCmdStatus(o *options.ArgoRolloutsOptions) *cobra.Command {
statusOptions := StatusOptions{
ArgoRolloutsOptions: *o,
}
var cmd = &cobra.Command{
Use: "status ROLLOUT_NAME",
Short: "Show the status of a rollout",
Long: statusLong,
Example: o.Example(statusExample),
SilenceUsage: true,
RunE: func(c *cobra.Command, args []string) error {
if len(args) != 1 {
return o.UsageErr(c)
}
name := args[0]
controller := viewcontroller.NewRolloutViewController(o.Namespace(), name, statusOptions.KubeClientset(), statusOptions.RolloutsClientset())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
signals.SetupSignalHandler(cancel)
controller.Start(ctx)
ri, err := controller.GetRolloutInfo()
if err != nil {
return err
}
if !statusOptions.Watch {
if ri.Status == "Healthy" || ri.Status == "Degraded" {
fmt.Fprintln(o.Out, ri.Status)
} else {
fmt.Fprintf(o.Out, "%s - %s\n", ri.Status, ri.Message)
}
} else {
rolloutUpdates := make(chan *rollout.RolloutInfo)
controller.RegisterCallback(func(roInfo *rollout.RolloutInfo) {
rolloutUpdates <- roInfo
})
go controller.Run(ctx)
statusOptions.WatchStatus(ctx.Done(), rolloutUpdates)
defer close(rolloutUpdates)
// the final rollout info after timeout or reach Healthy or Degraded status
ri, err = controller.GetRolloutInfo()
if err != nil {
return err
}
}
if ri.Status == "Degraded" {
return fmt.Errorf("The rollout is in a degraded state with message: %s", ri.Message)
} else if ri.Status != "Healthy" && statusOptions.Watch {
return fmt.Errorf("Rollout status watch exceeded timeout")
}
return nil
},
ValidArgsFunction: completionutil.RolloutNameCompletionFunc(o),
}
cmd.Flags().BoolVarP(&statusOptions.Watch, "watch", "w", true, "Watch the status of the rollout until it's done")
cmd.Flags().DurationVarP(&statusOptions.Timeout, "timeout", "t", time.Duration(0), "The length of time to watch before giving up. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). Zero means wait forever")
return cmd
}
func (o *StatusOptions) WatchStatus(stopCh <-chan struct{}, rolloutUpdates <-chan *rollout.RolloutInfo) string {
timeout := make(chan bool)
var roInfo *rollout.RolloutInfo
var prevMessage string
if o.Timeout != 0 {
go func() {
time.Sleep(o.Timeout)
timeout <- true
}()
}
printStatus := func(roInfo rollout.RolloutInfo) {
message := roInfo.Status
if roInfo.Message != "" {
message = fmt.Sprintf("%s - %s", roInfo.Status, roInfo.Message)
}
if message != prevMessage {
fmt.Fprintln(o.Out, message)
prevMessage = message
}
}
for {
select {
case roInfo = <-rolloutUpdates:
if roInfo != nil {
printStatus(*roInfo)
if roInfo.Status == "Healthy" || roInfo.Status == "Degraded" {
return roInfo.Status
}
}
case <-stopCh:
return ""
case <-timeout:
return ""
}
}
}