Browse Source

etcdctl: --cluster flag using cluster endpoints for endpoint commands

Queries the cluster for endpoints to use for the endpoint commands.

Fixes #8117
Anthony Romano 8 years ago
parent
commit
1a2be432c5
2 changed files with 62 additions and 19 deletions
  1. 30 13
      etcdctl/README.md
  2. 32 6
      etcdctl/ctlv3/command/ep_command.go

+ 30 - 13
etcdctl/README.md

@@ -565,6 +565,10 @@ Prints a humanized table of the member IDs, statuses, names, peer addresses, and
 
 
 ENDPOINT provides commands for querying individual endpoints.
 ENDPOINT provides commands for querying individual endpoints.
 
 
+#### Options
+
+- cluster -- fetch and use all endpoints from the etcd cluster member list
+
 ### ENDPOINT HEALTH
 ### ENDPOINT HEALTH
 
 
 ENDPOINT HEALTH checks the health of the list of endpoints with respect to cluster. An endpoint is unhealthy
 ENDPOINT HEALTH checks the health of the list of endpoints with respect to cluster. An endpoint is unhealthy
@@ -576,11 +580,20 @@ If an endpoint can participate in consensus, prints a message indicating the end
 
 
 #### Example
 #### Example
 
 
+Check the default endpoint's health:
+
 ```bash
 ```bash
 ./etcdctl endpoint health
 ./etcdctl endpoint health
-# 127.0.0.1:32379 is healthy: successfully committed proposal: took = 2.130877ms
 # 127.0.0.1:2379 is healthy: successfully committed proposal: took = 2.095242ms
 # 127.0.0.1:2379 is healthy: successfully committed proposal: took = 2.095242ms
-# 127.0.0.1:22379 is healthy: successfully committed proposal: took = 2.083263ms
+```
+
+Check all endpoints for the cluster associated with the default endpoint:
+
+```bash
+./etcdctl endpoint --cluster health
+# http://127.0.0.1:2379 is healthy: successfully committed proposal: took = 1.060091ms
+# http://127.0.0.1:22379 is healthy: successfully committed proposal: took = 903.138µs
+# http://127.0.0.1:32379 is healthy: successfully committed proposal: took = 1.113848ms
 ```
 ```
 
 
 ### ENDPOINT STATUS
 ### ENDPOINT STATUS
@@ -599,27 +612,31 @@ Prints a line of JSON encoding each endpoint URL, ID, version, database size, le
 
 
 #### Examples
 #### Examples
 
 
+Get the status for the default endpoint:
+
 ```bash
 ```bash
 ./etcdctl endpoint status
 ./etcdctl endpoint status
 # 127.0.0.1:2379, 8211f1d0f64f3269, 3.0.0, 25 kB, false, 2, 63
 # 127.0.0.1:2379, 8211f1d0f64f3269, 3.0.0, 25 kB, false, 2, 63
-# 127.0.0.1:22379, 91bc3c398fb3c146, 3.0.0, 25 kB, false, 2, 63
-# 127.0.0.1:32379, fd422379fda50e48, 3.0.0, 25 kB, true, 2, 63
 ```
 ```
 
 
+Get the status for the default endpoint as JSON:
+
 ```bash
 ```bash
 ./etcdctl -w json endpoint status
 ./etcdctl -w json endpoint status
-# [{"Endpoint":"127.0.0.1:2379","Status":{"header":{"cluster_id":17237436991929493444,"member_id":9372538179322589801,"revision":2,"raft_term":2},"version":"3.0.0","dbSize":24576,"leader":18249187646912138824,"raftIndex":32623,"raftTerm":2}},{"Endpoint":"127.0.0.1:22379","Status":{"header":{"cluster_id":17237436991929493444,"member_id":10501334649042878790,"revision":2,"raft_term":2},"version":"3.0.0","dbSize":24576,"leader":18249187646912138824,"raftIndex":32623,"raftTerm":2}},{"Endpoint":"127.0.0.1:32379","Status":{"header":{"cluster_id":17237436991929493444,"member_id":18249187646912138824,"revision":2,"raft_term":2},"version":"3.0.0","dbSize":24576,"leader":18249187646912138824,"raftIndex":32623,"raftTerm":2}}]
+# [{"Endpoint":"127.0.0.1:2379","Status":{"header":{"cluster_id":17237436991929493444,"member_id":9372538179322589801,"revision":2,"raft_term":2},"version":"3.0.0","dbSize":24576,"leader":18249187646912138824,"raftIndex":32623,"raftTerm":2}}]
 ```
 ```
 
 
+Get the status for all endpoints in the cluster associated with the default endpoint:
+
 ```bash
 ```bash
-./etcdctl -w table endpoint status
-+-----------------+------------------+---------+---------+-----------+-----------+------------+
-|    ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
-+-----------------+------------------+---------+---------+-----------+-----------+------------+
-| 127.0.0.1:2379  | 8211f1d0f64f3269 |  3.0.0  | 25 kB   | false     |         2 |         52 |
-| 127.0.0.1:22379 | 91bc3c398fb3c146 |  3.0.0  | 25 kB   | false     |         2 |         52 |
-| 127.0.0.1:32379 | fd422379fda50e48 |  3.0.0  | 25 kB   | true      |         2 |         52 |
-+-----------------+------------------+---------+---------+-----------+-----------+------------+
+./etcdctl -w table endpoint --cluster status
++------------------------+------------------+----------------+---------+-----------+-----------+------------+
+|        ENDPOINT        |        ID        |    VERSION     | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
++------------------------+------------------+----------------+---------+-----------+-----------+------------+
+| http://127.0.0.1:2379  | 8211f1d0f64f3269 | 3.2.0-rc.1+git |   25 kB |     false |         2 |          8 |
+| http://127.0.0.1:22379 | 91bc3c398fb3c146 | 3.2.0-rc.1+git |   25 kB |     false |         2 |          8 |
+| http://127.0.0.1:32379 | fd422379fda50e48 | 3.2.0-rc.1+git |   25 kB |      true |         2 |          8 |
++------------------------+------------------+----------------+---------+-----------+-----------+------------+
 ```
 ```
 
 
 ### ALARM \<subcommand\>
 ### ALARM \<subcommand\>

+ 32 - 6
etcdctl/ctlv3/command/ep_command.go

@@ -27,6 +27,8 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
 )
 )
 
 
+var epClusterEndpoints bool
+
 // NewEndpointCommand returns the cobra command for "endpoint".
 // NewEndpointCommand returns the cobra command for "endpoint".
 func NewEndpointCommand() *cobra.Command {
 func NewEndpointCommand() *cobra.Command {
 	ec := &cobra.Command{
 	ec := &cobra.Command{
@@ -34,6 +36,7 @@ func NewEndpointCommand() *cobra.Command {
 		Short: "Endpoint related commands",
 		Short: "Endpoint related commands",
 	}
 	}
 
 
+	ec.PersistentFlags().BoolVar(&epClusterEndpoints, "cluster", false, "use all endpoints from the cluster member list")
 	ec.AddCommand(newEpHealthCommand())
 	ec.AddCommand(newEpHealthCommand())
 	ec.AddCommand(newEpStatusCommand())
 	ec.AddCommand(newEpStatusCommand())
 
 
@@ -64,16 +67,12 @@ The items in the lists are endpoint, ID, version, db size, is leader, raft term,
 // epHealthCommandFunc executes the "endpoint-health" command.
 // epHealthCommandFunc executes the "endpoint-health" command.
 func epHealthCommandFunc(cmd *cobra.Command, args []string) {
 func epHealthCommandFunc(cmd *cobra.Command, args []string) {
 	flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
 	flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
-	endpoints, err := cmd.Flags().GetStringSlice("endpoints")
-	if err != nil {
-		ExitWithError(ExitError, err)
-	}
 
 
 	sec := secureCfgFromCmd(cmd)
 	sec := secureCfgFromCmd(cmd)
 	dt := dialTimeoutFromCmd(cmd)
 	dt := dialTimeoutFromCmd(cmd)
 	auth := authCfgFromCmd(cmd)
 	auth := authCfgFromCmd(cmd)
 	cfgs := []*v3.Config{}
 	cfgs := []*v3.Config{}
-	for _, ep := range endpoints {
+	for _, ep := range endpointsFromCluster(cmd) {
 		cfg, err := newClientCfg([]string{ep}, dt, sec, auth)
 		cfg, err := newClientCfg([]string{ep}, dt, sec, auth)
 		if err != nil {
 		if err != nil {
 			ExitWithError(ExitBadArgs, err)
 			ExitWithError(ExitBadArgs, err)
@@ -121,7 +120,7 @@ func epStatusCommandFunc(cmd *cobra.Command, args []string) {
 
 
 	statusList := []epStatus{}
 	statusList := []epStatus{}
 	var err error
 	var err error
-	for _, ep := range c.Endpoints() {
+	for _, ep := range endpointsFromCluster(cmd) {
 		ctx, cancel := commandCtx(cmd)
 		ctx, cancel := commandCtx(cmd)
 		resp, serr := c.Status(ctx, ep)
 		resp, serr := c.Status(ctx, ep)
 		cancel()
 		cancel()
@@ -139,3 +138,30 @@ func epStatusCommandFunc(cmd *cobra.Command, args []string) {
 		os.Exit(ExitError)
 		os.Exit(ExitError)
 	}
 	}
 }
 }
+
+func endpointsFromCluster(cmd *cobra.Command) []string {
+	if !epClusterEndpoints {
+		endpoints, err := cmd.Flags().GetStringSlice("endpoints")
+		if err != nil {
+			ExitWithError(ExitError, err)
+		}
+		return endpoints
+	}
+	c := mustClientFromCmd(cmd)
+	ctx, cancel := commandCtx(cmd)
+	defer func() {
+		c.Close()
+		cancel()
+	}()
+	membs, err := c.MemberList(ctx)
+	if err != nil {
+		err = fmt.Errorf("failed to fetch endpoints from etcd cluster member list: %v", err)
+		ExitWithError(ExitError, err)
+	}
+
+	ret := []string{}
+	for _, m := range membs.Members {
+		ret = append(ret, m.ClientURLs...)
+	}
+	return ret
+}