瀏覽代碼

ctlv3: add 'endpoint hashkv' command

Signed-off-by: Gyu-Ho Lee <gyuhox@gmail.com>
Gyu-Ho Lee 8 年之前
父節點
當前提交
5176b63fa0

+ 43 - 0
etcdctl/README.md

@@ -641,6 +641,49 @@ Get the status for all endpoints in the cluster associated with the default endp
 +------------------------+------------------+----------------+---------+-----------+-----------+------------+
 ```
 
+### ENDPOINT HASHKV
+
+ENDPOINT HASHKV fetches the hash of the key-value store of an endpoint.
+
+#### Output
+
+##### Simple format
+
+Prints a humanized table of each endpoint URL and KV history hash.
+
+##### JSON format
+
+Prints a line of JSON encoding each endpoint URL and KV history hash.
+
+#### Examples
+
+Get the hash for the default endpoint:
+
+```bash
+./etcdctl endpoint hashkv
+# 127.0.0.1:2379, 1084519789
+```
+
+Get the status for the default endpoint as JSON:
+
+```bash
+./etcdctl -w json endpoint hashkv
+# [{"Endpoint":"127.0.0.1:2379","Hash":{"header":{"cluster_id":14841639068965178418,"member_id":10276657743932975437,"revision":1,"raft_term":3},"hash":1084519789,"compact_revision":-1}}]
+```
+
+Get the status for all endpoints in the cluster associated with the default endpoint:
+
+```bash
+./etcdctl -w table endpoint --cluster hashkv
++------------------------+------------+
+|        ENDPOINT        |    HASH    |
++------------------------+------------+
+| http://127.0.0.1:12379 | 1084519789 |
+| http://127.0.0.1:22379 | 1084519789 |
+| http://127.0.0.1:32379 | 1084519789 |
++------------------------+------------+
+```
+
 ### ALARM \<subcommand\>
 
 Provides alarm related commands

+ 41 - 0
etcdctl/ctlv3/command/ep_command.go

@@ -28,6 +28,7 @@ import (
 )
 
 var epClusterEndpoints bool
+var epHashKVRev int64
 
 // NewEndpointCommand returns the cobra command for "endpoint".
 func NewEndpointCommand() *cobra.Command {
@@ -39,6 +40,7 @@ func NewEndpointCommand() *cobra.Command {
 	ec.PersistentFlags().BoolVar(&epClusterEndpoints, "cluster", false, "use all endpoints from the cluster member list")
 	ec.AddCommand(newEpHealthCommand())
 	ec.AddCommand(newEpStatusCommand())
+	ec.AddCommand(newEpHashKVCommand())
 
 	return ec
 }
@@ -64,6 +66,16 @@ The items in the lists are endpoint, ID, version, db size, is leader, raft term,
 	}
 }
 
+func newEpHashKVCommand() *cobra.Command {
+	hc := &cobra.Command{
+		Use:   "hashkv",
+		Short: "Prints the KV history hash for each endpoint in --endpoints",
+		Run:   epHashKVCommandFunc,
+	}
+	hc.PersistentFlags().Int64Var(&epHashKVRev, "rev", 0, "maximum revision to hash (default: all revisions)")
+	return hc
+}
+
 // epHealthCommandFunc executes the "endpoint-health" command.
 func epHealthCommandFunc(cmd *cobra.Command, args []string) {
 	flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
@@ -151,6 +163,35 @@ func epStatusCommandFunc(cmd *cobra.Command, args []string) {
 	}
 }
 
+type epHashKV struct {
+	Ep   string             `json:"Endpoint"`
+	Resp *v3.HashKVResponse `json:"HashKV"`
+}
+
+func epHashKVCommandFunc(cmd *cobra.Command, args []string) {
+	c := mustClientFromCmd(cmd)
+
+	hashList := []epHashKV{}
+	var err error
+	for _, ep := range endpointsFromCluster(cmd) {
+		ctx, cancel := commandCtx(cmd)
+		resp, serr := c.HashKV(ctx, ep, epHashKVRev)
+		cancel()
+		if serr != nil {
+			err = serr
+			fmt.Fprintf(os.Stderr, "Failed to get the hash of endpoint %s (%v)\n", ep, serr)
+			continue
+		}
+		hashList = append(hashList, epHashKV{Ep: ep, Resp: resp})
+	}
+
+	display.EndpointHashKV(hashList)
+
+	if err != nil {
+		ExitWithError(ExitError, err)
+	}
+}
+
 func endpointsFromCluster(cmd *cobra.Command) []string {
 	if !epClusterEndpoints {
 		endpoints, err := cmd.Flags().GetStringSlice("endpoints")

+ 13 - 0
etcdctl/ctlv3/command/printer.go

@@ -43,6 +43,7 @@ type printer interface {
 	MemberList(v3.MemberListResponse)
 
 	EndpointStatus([]epStatus)
+	EndpointHashKV([]epHashKV)
 	MoveLeader(leader, target uint64, r v3.MoveLeaderResponse)
 
 	Alarm(v3.AlarmResponse)
@@ -146,6 +147,7 @@ func newPrinterUnsupported(n string) printer {
 }
 
 func (p *printerUnsupported) EndpointStatus([]epStatus) { p.p(nil) }
+func (p *printerUnsupported) EndpointHashKV([]epHashKV) { p.p(nil) }
 func (p *printerUnsupported) DBStatus(dbstatus)         { p.p(nil) }
 
 func (p *printerUnsupported) MoveLeader(leader, target uint64, r v3.MoveLeaderResponse) { p.p(nil) }
@@ -184,6 +186,17 @@ func makeEndpointStatusTable(statusList []epStatus) (hdr []string, rows [][]stri
 	return
 }
 
+func makeEndpointHashKVTable(hashList []epHashKV) (hdr []string, rows [][]string) {
+	hdr = []string{"endpoint", "hash"}
+	for _, h := range hashList {
+		rows = append(rows, []string{
+			h.Ep,
+			fmt.Sprint(h.Resp.Hash),
+		})
+	}
+	return
+}
+
 func makeDBStatusTable(ds dbstatus) (hdr []string, rows [][]string) {
 	hdr = []string{"hash", "revision", "total keys", "total size"}
 	rows = append(rows, []string{

+ 9 - 0
etcdctl/ctlv3/command/printer_fields.go

@@ -146,6 +146,15 @@ func (p *fieldsPrinter) EndpointStatus(eps []epStatus) {
 	}
 }
 
+func (p *fieldsPrinter) EndpointHashKV(hs []epHashKV) {
+	for _, h := range hs {
+		p.hdr(h.Resp.Header)
+		fmt.Printf("\"Endpoint\" : %q\n", h.Ep)
+		fmt.Println(`"Hash" :`, h.Resp.Hash)
+		fmt.Println()
+	}
+}
+
 func (p *fieldsPrinter) Alarm(r v3.AlarmResponse) {
 	p.hdr(r.Header)
 	for _, a := range r.Alarms {

+ 1 - 0
etcdctl/ctlv3/command/printer_json.go

@@ -29,6 +29,7 @@ func newJSONPrinter() printer {
 }
 
 func (p *jsonPrinter) EndpointStatus(r []epStatus) { printJSON(r) }
+func (p *jsonPrinter) EndpointHashKV(r []epHashKV) { printJSON(r) }
 func (p *jsonPrinter) DBStatus(r dbstatus)         { printJSON(r) }
 
 func printJSON(v interface{}) {

+ 7 - 0
etcdctl/ctlv3/command/printer_simple.go

@@ -136,6 +136,13 @@ func (s *simplePrinter) EndpointStatus(statusList []epStatus) {
 	}
 }
 
+func (s *simplePrinter) EndpointHashKV(hashList []epHashKV) {
+	_, rows := makeEndpointHashKVTable(hashList)
+	for _, row := range rows {
+		fmt.Println(strings.Join(row, ", "))
+	}
+}
+
 func (s *simplePrinter) DBStatus(ds dbstatus) {
 	_, rows := makeDBStatusTable(ds)
 	for _, row := range rows {

+ 10 - 0
etcdctl/ctlv3/command/printer_table.go

@@ -44,6 +44,16 @@ func (tp *tablePrinter) EndpointStatus(r []epStatus) {
 	table.SetAlignment(tablewriter.ALIGN_RIGHT)
 	table.Render()
 }
+func (tp *tablePrinter) EndpointHashKV(r []epHashKV) {
+	hdr, rows := makeEndpointHashKVTable(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) DBStatus(r dbstatus) {
 	hdr, rows := makeDBStatusTable(r)
 	table := tablewriter.NewWriter(os.Stdout)