Skip to content

Commit ff455e3

Browse files
authored
Merge pull request #9540 from gyuho/hhh
ctlv3: support "write-out" for "endpoint health" command
2 parents c54636a + 881fd20 commit ff455e3

File tree

7 files changed

+69
-8
lines changed

7 files changed

+69
-8
lines changed

CHANGELOG-3.4.md

+2
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ See [security doc](https://github.com/coreos/etcd/blob/master/Documentation/op-g
141141
- Add [`defrag --cluster`](https://github.com/coreos/etcd/pull/9390) flag.
142142
- Add ["raft applied index" field to `endpoint status`](https://github.com/coreos/etcd/pull/9176).
143143
- Add ["errors" field to `endpoint status`](https://github.com/coreos/etcd/pull/9206).
144+
- Add [`endpoint health --write-out` support](https://github.com/coreos/etcd/pull/9540).
145+
- Previously, [`endpoint health --write-out json` did not work](https://github.com/coreos/etcd/issues/9532).
144146

145147
### Added: gRPC gateway
146148

etcdctl/ctlv3/command/ep_command.go

+20-8
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,17 @@ func newEpHashKVCommand() *cobra.Command {
7676
return hc
7777
}
7878

79+
type epHealth struct {
80+
Ep string `json:"endpoint"`
81+
Health bool `json:"health"`
82+
Took string `json:"took"`
83+
Error string `json:"error,omitempty"`
84+
}
85+
7986
// epHealthCommandFunc executes the "endpoint-health" command.
8087
func epHealthCommandFunc(cmd *cobra.Command, args []string) {
8188
flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
89+
initDisplayFromCmd(cmd)
8290

8391
sec := secureCfgFromCmd(cmd)
8492
dt := dialTimeoutFromCmd(cmd)
@@ -95,15 +103,15 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) {
95103
}
96104

97105
var wg sync.WaitGroup
98-
errc := make(chan error, len(cfgs))
106+
hch := make(chan epHealth, len(cfgs))
99107
for _, cfg := range cfgs {
100108
wg.Add(1)
101109
go func(cfg *v3.Config) {
102110
defer wg.Done()
103111
ep := cfg.Endpoints[0]
104112
cli, err := v3.New(*cfg)
105113
if err != nil {
106-
errc <- fmt.Errorf("%s is unhealthy: failed to connect: %v", ep, err)
114+
hch <- epHealth{Ep: ep, Health: false, Error: err.Error()}
107115
return
108116
}
109117
st := time.Now()
@@ -112,25 +120,29 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) {
112120
ctx, cancel := commandCtx(cmd)
113121
_, err = cli.Get(ctx, "health")
114122
cancel()
123+
eh := epHealth{Ep: ep, Health: false, Took: time.Since(st).String()}
115124
// permission denied is OK since proposal goes through consensus to get it
116125
if err == nil || err == rpctypes.ErrPermissionDenied {
117-
fmt.Printf("%s is healthy: successfully committed proposal: took = %v\n", ep, time.Since(st))
126+
eh.Health = true
118127
} else {
119-
errc <- fmt.Errorf("%s is unhealthy: failed to commit proposal: %v", ep, err)
128+
eh.Error = err.Error()
120129
}
130+
hch <- eh
121131
}(cfg)
122132
}
123133

124134
wg.Wait()
125-
close(errc)
135+
close(hch)
126136

127137
errs := false
128-
for err := range errc {
129-
if err != nil {
138+
healthList := []epHealth{}
139+
for h := range hch {
140+
healthList = append(healthList, h)
141+
if h.Error != "" {
130142
errs = true
131-
fmt.Fprintln(os.Stderr, err)
132143
}
133144
}
145+
display.EndpointHealth(healthList)
134146
if errs {
135147
ExitWithError(ExitError, fmt.Errorf("unhealthy cluster"))
136148
}

etcdctl/ctlv3/command/printer.go

+15
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type printer interface {
4444
MemberUpdate(id uint64, r v3.MemberUpdateResponse)
4545
MemberList(v3.MemberListResponse)
4646

47+
EndpointHealth([]epHealth)
4748
EndpointStatus([]epStatus)
4849
EndpointHashKV([]epHashKV)
4950
MoveLeader(leader, target uint64, r v3.MoveLeaderResponse)
@@ -149,6 +150,7 @@ func newPrinterUnsupported(n string) printer {
149150
return &printerUnsupported{printerRPC{nil, f}}
150151
}
151152

153+
func (p *printerUnsupported) EndpointHealth([]epHealth) { p.p(nil) }
152154
func (p *printerUnsupported) EndpointStatus([]epStatus) { p.p(nil) }
153155
func (p *printerUnsupported) EndpointHashKV([]epHashKV) { p.p(nil) }
154156
func (p *printerUnsupported) DBStatus(snapshot.Status) { p.p(nil) }
@@ -173,6 +175,19 @@ func makeMemberListTable(r v3.MemberListResponse) (hdr []string, rows [][]string
173175
return hdr, rows
174176
}
175177

178+
func makeEndpointHealthTable(healthList []epHealth) (hdr []string, rows [][]string) {
179+
hdr = []string{"endpoint", "health", "took", "error"}
180+
for _, h := range healthList {
181+
rows = append(rows, []string{
182+
h.Ep,
183+
fmt.Sprintf("%v", h.Health),
184+
h.Took,
185+
h.Error,
186+
})
187+
}
188+
return hdr, rows
189+
}
190+
176191
func makeEndpointStatusTable(statusList []epStatus) (hdr []string, rows [][]string) {
177192
hdr = []string{"endpoint", "ID", "version", "db size", "is leader", "raft term", "raft index", "raft applied index", "errors"}
178193
for _, status := range statusList {

etcdctl/ctlv3/command/printer_fields.go

+10
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ func (p *fieldsPrinter) MemberList(r v3.MemberListResponse) {
141141
}
142142
}
143143

144+
func (p *fieldsPrinter) EndpointHealth(hs []epHealth) {
145+
for _, h := range hs {
146+
fmt.Printf("\"Endpoint\" : %q\n", h.Ep)
147+
fmt.Println(`"Health" :`, h.Health)
148+
fmt.Println(`"Took" :`, h.Took)
149+
fmt.Println(`"Error" :`, h.Error)
150+
fmt.Println()
151+
}
152+
}
153+
144154
func (p *fieldsPrinter) EndpointStatus(eps []epStatus) {
145155
for _, ep := range eps {
146156
p.hdr(ep.Resp.Header)

etcdctl/ctlv3/command/printer_json.go

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func newJSONPrinter() printer {
3030
}
3131
}
3232

33+
func (p *jsonPrinter) EndpointHealth(r []epHealth) { printJSON(r) }
3334
func (p *jsonPrinter) EndpointStatus(r []epStatus) { printJSON(r) }
3435
func (p *jsonPrinter) EndpointHashKV(r []epHashKV) { printJSON(r) }
3536
func (p *jsonPrinter) DBStatus(r snapshot.Status) { printJSON(r) }

etcdctl/ctlv3/command/printer_simple.go

+11
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package command
1616

1717
import (
1818
"fmt"
19+
"os"
1920
"strings"
2021

2122
v3 "github.com/coreos/etcd/clientv3"
@@ -142,6 +143,16 @@ func (s *simplePrinter) MemberList(resp v3.MemberListResponse) {
142143
}
143144
}
144145

146+
func (s *simplePrinter) EndpointHealth(hs []epHealth) {
147+
for _, h := range hs {
148+
if h.Error == "" {
149+
fmt.Fprintf(os.Stderr, "%s is healthy: successfully committed proposal: took = %v\n", h.Ep, h.Took)
150+
} else {
151+
fmt.Fprintf(os.Stderr, "%s is unhealthy: failed to commit proposal: %v", h.Ep, h.Error)
152+
}
153+
}
154+
}
155+
145156
func (s *simplePrinter) EndpointStatus(statusList []epStatus) {
146157
_, rows := makeEndpointStatusTable(statusList)
147158
for _, row := range rows {

etcdctl/ctlv3/command/printer_table.go

+10
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ func (tp *tablePrinter) MemberList(r v3.MemberListResponse) {
3535
table.SetAlignment(tablewriter.ALIGN_RIGHT)
3636
table.Render()
3737
}
38+
func (tp *tablePrinter) EndpointHealth(r []epHealth) {
39+
hdr, rows := makeEndpointHealthTable(r)
40+
table := tablewriter.NewWriter(os.Stdout)
41+
table.SetHeader(hdr)
42+
for _, row := range rows {
43+
table.Append(row)
44+
}
45+
table.SetAlignment(tablewriter.ALIGN_RIGHT)
46+
table.Render()
47+
}
3848
func (tp *tablePrinter) EndpointStatus(r []epStatus) {
3949
hdr, rows := makeEndpointStatusTable(r)
4050
table := tablewriter.NewWriter(os.Stdout)

0 commit comments

Comments
 (0)