Skip to content

Commit

Permalink
etcdctl: --cluster flag using cluster endpoints for endpoint commands
Browse files Browse the repository at this point in the history
Queries the cluster for endpoints to use for the endpoint commands.

Fixes etcd-io#8117
  • Loading branch information
heyitsanthony committed Jun 21, 2017
1 parent a40cdc7 commit 1a2be43
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 19 deletions.
43 changes: 30 additions & 13 deletions etcdctl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ Prints a humanized table of the member IDs, statuses, names, peer addresses, and

ENDPOINT provides commands for querying individual endpoints.

#### Options

- cluster -- fetch and use all endpoints from the etcd cluster member list

### ENDPOINT HEALTH

ENDPOINT HEALTH checks the health of the list of endpoints with respect to cluster. An endpoint is unhealthy
Expand All @@ -576,11 +580,20 @@ If an endpoint can participate in consensus, prints a message indicating the end

#### Example

Check the default endpoint's health:

```bash
./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: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
Expand All @@ -599,27 +612,31 @@ Prints a line of JSON encoding each endpoint URL, ID, version, database size, le

#### Examples

Get the status for the default endpoint:

```bash
./etcdctl endpoint status
# 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
./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
./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\>
Expand Down
38 changes: 32 additions & 6 deletions etcdctl/ctlv3/command/ep_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ import (
"github.com/spf13/cobra"
)

var epClusterEndpoints bool

// NewEndpointCommand returns the cobra command for "endpoint".
func NewEndpointCommand() *cobra.Command {
ec := &cobra.Command{
Use: "endpoint <subcommand>",
Short: "Endpoint related commands",
}

ec.PersistentFlags().BoolVar(&epClusterEndpoints, "cluster", false, "use all endpoints from the cluster member list")
ec.AddCommand(newEpHealthCommand())
ec.AddCommand(newEpStatusCommand())

Expand Down Expand Up @@ -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.
func epHealthCommandFunc(cmd *cobra.Command, args []string) {
flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
endpoints, err := cmd.Flags().GetStringSlice("endpoints")
if err != nil {
ExitWithError(ExitError, err)
}

sec := secureCfgFromCmd(cmd)
dt := dialTimeoutFromCmd(cmd)
auth := authCfgFromCmd(cmd)
cfgs := []*v3.Config{}
for _, ep := range endpoints {
for _, ep := range endpointsFromCluster(cmd) {
cfg, err := newClientCfg([]string{ep}, dt, sec, auth)
if err != nil {
ExitWithError(ExitBadArgs, err)
Expand Down Expand Up @@ -121,7 +120,7 @@ func epStatusCommandFunc(cmd *cobra.Command, args []string) {

statusList := []epStatus{}
var err error
for _, ep := range c.Endpoints() {
for _, ep := range endpointsFromCluster(cmd) {
ctx, cancel := commandCtx(cmd)
resp, serr := c.Status(ctx, ep)
cancel()
Expand All @@ -139,3 +138,30 @@ func epStatusCommandFunc(cmd *cobra.Command, args []string) {
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
}

0 comments on commit 1a2be43

Please sign in to comment.