-
Notifications
You must be signed in to change notification settings - Fork 0
/
status.go
142 lines (118 loc) · 3.55 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
139
140
141
142
// Copyright © 2017 Chef Software
package main
import (
"context"
"time"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
api "github.com/chef/automate/api/interservice/deployment"
"github.com/chef/automate/components/automate-cli/pkg/status"
"github.com/chef/automate/components/automate-deployment/pkg/client"
)
var statusCmdFlags = struct {
waitForHealthy bool
waitTimeout int64
waitRefreshInterval int64
}{}
func newStatusCmd() *cobra.Command {
var statusCmd = &cobra.Command{
Use: "status",
Short: "Retrieve Chef Automate status",
Long: "Retrieve Chef Automate status. Includes status of Automate services.",
RunE: runStatusCmd,
}
statusCmd.PersistentFlags().BoolVarP(
&statusCmdFlags.waitForHealthy, "wait-for-healthy", "w", false,
"Wait until the status response is healthy or the timeout is reached",
)
statusCmd.PersistentFlags().Int64VarP(
&statusCmdFlags.waitTimeout, "wait-timeout", "t", 600,
"How many seconds to wait for the status to be healthy before returning an error",
)
statusCmd.PersistentFlags().Int64VarP(
&statusCmdFlags.waitRefreshInterval, "wait-refresh-interval", "r", 2,
"How many seconds to wait between polling for status updates",
)
return statusCmd
}
type statusResult struct {
Services []api.FormattedServiceStatus `json:"services"`
}
var (
statusErrUndeployed = status.New(status.UnhealthyStatusError, "No services have been deployed")
statusErrUnhealthy = status.New(status.UnhealthyStatusError, "One or more services are unhealthy")
)
func runStatusCmd(cmd *cobra.Command, args []string) error {
writeStatus := func(res *api.StatusResponse) {
writer.Titlef(
"Status from deployment with channel [%s] and type [%s]",
res.DeploymentConfig.V1.Svc.Channel.GetValue(),
res.DeploymentConfig.V1.Svc.DeploymentType.GetValue(),
)
writer.Title(res.ServiceStatus.FormatStatus())
status.GlobalResult = statusResult{
Services: res.ServiceStatus.FormattedServices(),
}
}
getStatus := func() (*api.StatusResponse, error) {
connection, err := client.Connection(client.DefaultClientTimeout)
if err != nil {
return nil, err
}
res, err := connection.Status(context.Background(), &api.StatusRequest{})
if err != nil {
return nil, status.Wrap(
err,
status.DeploymentServiceCallError,
"Request to obtain Chef Automate status information failed",
)
}
return res, nil
}
handleBadStatus := func(res *api.StatusResponse, err error) error {
if err != nil {
return err
}
writeStatus(res)
if len(res.ServiceStatus.Services) == 0 {
return statusErrUndeployed
}
return statusErrUnhealthy
}
startTime := time.Now()
res, err := getStatus()
if err == nil {
if res.ServiceStatus.AllHealthy() {
writeStatus(res)
return nil
}
}
if !statusCmdFlags.waitForHealthy {
return handleBadStatus(res, err)
}
timeout := startTime.Add(time.Second * time.Duration(statusCmdFlags.waitTimeout))
refresh := time.NewTicker(time.Second * time.Duration(statusCmdFlags.waitRefreshInterval)).C
// Listen to the refresh channel and query for the status. If the timeout
// elapses before a healthy status has been returned then write the status
// if possible and return an error.
for {
select {
case <-refresh:
logrus.Debug("Refreshing status")
res, err := getStatus()
if err == nil {
if res.ServiceStatus.AllHealthy() {
writeStatus(res)
return nil
}
}
if time.Now().After(timeout) {
logrus.Debug("Timeout elapsed")
return handleBadStatus(res, err)
}
}
}
}
func init() {
RootCmd.AddCommand(newStatusCmd())
}