mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #9540 from gyuho/hhh
ctlv3: support "write-out" for "endpoint health" command
This commit is contained in:
commit
ff455e3567
@ -141,6 +141,8 @@ See [security doc](https://github.com/coreos/etcd/blob/master/Documentation/op-g
|
||||
- Add [`defrag --cluster`](https://github.com/coreos/etcd/pull/9390) flag.
|
||||
- Add ["raft applied index" field to `endpoint status`](https://github.com/coreos/etcd/pull/9176).
|
||||
- Add ["errors" field to `endpoint status`](https://github.com/coreos/etcd/pull/9206).
|
||||
- Add [`endpoint health --write-out` support](https://github.com/coreos/etcd/pull/9540).
|
||||
- Previously, [`endpoint health --write-out json` did not work](https://github.com/coreos/etcd/issues/9532).
|
||||
|
||||
### Added: gRPC gateway
|
||||
|
||||
|
@ -76,9 +76,17 @@ func newEpHashKVCommand() *cobra.Command {
|
||||
return hc
|
||||
}
|
||||
|
||||
type epHealth struct {
|
||||
Ep string `json:"endpoint"`
|
||||
Health bool `json:"health"`
|
||||
Took string `json:"took"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// epHealthCommandFunc executes the "endpoint-health" command.
|
||||
func epHealthCommandFunc(cmd *cobra.Command, args []string) {
|
||||
flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
|
||||
initDisplayFromCmd(cmd)
|
||||
|
||||
sec := secureCfgFromCmd(cmd)
|
||||
dt := dialTimeoutFromCmd(cmd)
|
||||
@ -95,7 +103,7 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errc := make(chan error, len(cfgs))
|
||||
hch := make(chan epHealth, len(cfgs))
|
||||
for _, cfg := range cfgs {
|
||||
wg.Add(1)
|
||||
go func(cfg *v3.Config) {
|
||||
@ -103,7 +111,7 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) {
|
||||
ep := cfg.Endpoints[0]
|
||||
cli, err := v3.New(*cfg)
|
||||
if err != nil {
|
||||
errc <- fmt.Errorf("%s is unhealthy: failed to connect: %v", ep, err)
|
||||
hch <- epHealth{Ep: ep, Health: false, Error: err.Error()}
|
||||
return
|
||||
}
|
||||
st := time.Now()
|
||||
@ -112,25 +120,29 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) {
|
||||
ctx, cancel := commandCtx(cmd)
|
||||
_, err = cli.Get(ctx, "health")
|
||||
cancel()
|
||||
eh := epHealth{Ep: ep, Health: false, Took: time.Since(st).String()}
|
||||
// permission denied is OK since proposal goes through consensus to get it
|
||||
if err == nil || err == rpctypes.ErrPermissionDenied {
|
||||
fmt.Printf("%s is healthy: successfully committed proposal: took = %v\n", ep, time.Since(st))
|
||||
eh.Health = true
|
||||
} else {
|
||||
errc <- fmt.Errorf("%s is unhealthy: failed to commit proposal: %v", ep, err)
|
||||
eh.Error = err.Error()
|
||||
}
|
||||
hch <- eh
|
||||
}(cfg)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errc)
|
||||
close(hch)
|
||||
|
||||
errs := false
|
||||
for err := range errc {
|
||||
if err != nil {
|
||||
healthList := []epHealth{}
|
||||
for h := range hch {
|
||||
healthList = append(healthList, h)
|
||||
if h.Error != "" {
|
||||
errs = true
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
}
|
||||
}
|
||||
display.EndpointHealth(healthList)
|
||||
if errs {
|
||||
ExitWithError(ExitError, fmt.Errorf("unhealthy cluster"))
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ type printer interface {
|
||||
MemberUpdate(id uint64, r v3.MemberUpdateResponse)
|
||||
MemberList(v3.MemberListResponse)
|
||||
|
||||
EndpointHealth([]epHealth)
|
||||
EndpointStatus([]epStatus)
|
||||
EndpointHashKV([]epHashKV)
|
||||
MoveLeader(leader, target uint64, r v3.MoveLeaderResponse)
|
||||
@ -149,6 +150,7 @@ func newPrinterUnsupported(n string) printer {
|
||||
return &printerUnsupported{printerRPC{nil, f}}
|
||||
}
|
||||
|
||||
func (p *printerUnsupported) EndpointHealth([]epHealth) { p.p(nil) }
|
||||
func (p *printerUnsupported) EndpointStatus([]epStatus) { p.p(nil) }
|
||||
func (p *printerUnsupported) EndpointHashKV([]epHashKV) { p.p(nil) }
|
||||
func (p *printerUnsupported) DBStatus(snapshot.Status) { p.p(nil) }
|
||||
@ -173,6 +175,19 @@ func makeMemberListTable(r v3.MemberListResponse) (hdr []string, rows [][]string
|
||||
return hdr, rows
|
||||
}
|
||||
|
||||
func makeEndpointHealthTable(healthList []epHealth) (hdr []string, rows [][]string) {
|
||||
hdr = []string{"endpoint", "health", "took", "error"}
|
||||
for _, h := range healthList {
|
||||
rows = append(rows, []string{
|
||||
h.Ep,
|
||||
fmt.Sprintf("%v", h.Health),
|
||||
h.Took,
|
||||
h.Error,
|
||||
})
|
||||
}
|
||||
return hdr, rows
|
||||
}
|
||||
|
||||
func makeEndpointStatusTable(statusList []epStatus) (hdr []string, rows [][]string) {
|
||||
hdr = []string{"endpoint", "ID", "version", "db size", "is leader", "raft term", "raft index", "raft applied index", "errors"}
|
||||
for _, status := range statusList {
|
||||
|
@ -141,6 +141,16 @@ func (p *fieldsPrinter) MemberList(r v3.MemberListResponse) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *fieldsPrinter) EndpointHealth(hs []epHealth) {
|
||||
for _, h := range hs {
|
||||
fmt.Printf("\"Endpoint\" : %q\n", h.Ep)
|
||||
fmt.Println(`"Health" :`, h.Health)
|
||||
fmt.Println(`"Took" :`, h.Took)
|
||||
fmt.Println(`"Error" :`, h.Error)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *fieldsPrinter) EndpointStatus(eps []epStatus) {
|
||||
for _, ep := range eps {
|
||||
p.hdr(ep.Resp.Header)
|
||||
|
@ -30,6 +30,7 @@ func newJSONPrinter() printer {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *jsonPrinter) EndpointHealth(r []epHealth) { printJSON(r) }
|
||||
func (p *jsonPrinter) EndpointStatus(r []epStatus) { printJSON(r) }
|
||||
func (p *jsonPrinter) EndpointHashKV(r []epHashKV) { printJSON(r) }
|
||||
func (p *jsonPrinter) DBStatus(r snapshot.Status) { printJSON(r) }
|
||||
|
@ -16,6 +16,7 @@ package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
v3 "github.com/coreos/etcd/clientv3"
|
||||
@ -142,6 +143,16 @@ func (s *simplePrinter) MemberList(resp v3.MemberListResponse) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *simplePrinter) EndpointHealth(hs []epHealth) {
|
||||
for _, h := range hs {
|
||||
if h.Error == "" {
|
||||
fmt.Fprintf(os.Stderr, "%s is healthy: successfully committed proposal: took = %v\n", h.Ep, h.Took)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "%s is unhealthy: failed to commit proposal: %v", h.Ep, h.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *simplePrinter) EndpointStatus(statusList []epStatus) {
|
||||
_, rows := makeEndpointStatusTable(statusList)
|
||||
for _, row := range rows {
|
||||
|
@ -35,6 +35,16 @@ func (tp *tablePrinter) MemberList(r v3.MemberListResponse) {
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
func (tp *tablePrinter) EndpointHealth(r []epHealth) {
|
||||
hdr, rows := makeEndpointHealthTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader(hdr)
|
||||
for _, row := range rows {
|
||||
table.Append(row)
|
||||
}
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
func (tp *tablePrinter) EndpointStatus(r []epStatus) {
|
||||
hdr, rows := makeEndpointStatusTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
|
Loading…
x
Reference in New Issue
Block a user