Skip to content

Commit

Permalink
command/members: Improve output. Fixes #143
Browse files Browse the repository at this point in the history
  • Loading branch information
armon committed Jun 6, 2014
1 parent b144633 commit e9c7098
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 25 deletions.
98 changes: 75 additions & 23 deletions command/members.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ Usage: consul members [options]
Options:
-role=<regexp> If provided, output is filtered to only nodes matching
the regular expression for role
-detailed Provides detailed information about nodes
-rpc-addr=127.0.0.1:8400 RPC address of the Consul agent.
Expand All @@ -40,24 +39,20 @@ Options:
}

func (c *MembersCommand) Run(args []string) int {
var detailed bool
var wan bool
var roleFilter, statusFilter string
var statusFilter string
cmdFlags := flag.NewFlagSet("members", flag.ContinueOnError)
cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }
cmdFlags.BoolVar(&detailed, "detailed", false, "detailed output")
cmdFlags.BoolVar(&wan, "wan", false, "wan members")
cmdFlags.StringVar(&roleFilter, "role", ".*", "role filter")
cmdFlags.StringVar(&statusFilter, "status", ".*", "status filter")
rpcAddr := RPCAddrFlag(cmdFlags)
if err := cmdFlags.Parse(args); err != nil {
return 1
}

// Compile the regexp
roleRe, err := regexp.Compile(roleFilter)
if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to compile role regexp: %v", err))
return 1
}
statusRe, err := regexp.Compile(statusFilter)
if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to compile status regexp: %v", err))
Expand All @@ -82,13 +77,80 @@ func (c *MembersCommand) Run(args []string) int {
return 1
}

// Filter the results
n := len(members)
for i := 0; i < n; i++ {
member := members[i]
if !statusRe.MatchString(member.Status) {
members[i], members[n-1] = members[n-1], members[i]
i--
n--
continue
}
}
members = members[:n]

// No matching members
if len(members) == 0 {
return 2
}

// Generate the output
var result []string
if detailed {
result = c.detailedOutput(members)
} else {
result = c.standardOutput(members)
}

// Generate the columnized version
output := columnize.SimpleFormat(result)
c.Ui.Output(string(output))

return 0
}

// standardOutput is used to dump the most useful information about nodes
// in a more human-friendly format
func (c *MembersCommand) standardOutput(members []agent.Member) []string {
result := make([]string, 0, len(members))
header := "Node|Address|Status|Type|Build|Protocol"
result = append(result, header)
for _, member := range members {
// Skip the non-matching members
if !roleRe.MatchString(member.Tags["role"]) || !statusRe.MatchString(member.Status) {
continue
addr := net.TCPAddr{IP: member.Addr, Port: int(member.Port)}
protocol := member.Tags["vsn"]
build := member.Tags["build"]
if build == "" {
build = "< 0.3"
} else if idx := strings.Index(build, ":"); idx != -1 {
build = build[:idx]
}

switch member.Tags["role"] {
case "node":
line := fmt.Sprintf("%s|%s|%s|client|%s|%s",
member.Name, addr.String(), member.Status, build, protocol)
result = append(result, line)
case "consul":
line := fmt.Sprintf("%s|%s|%s|server|%s|%s",
member.Name, addr.String(), member.Status, build, protocol)
result = append(result, line)
default:
line := fmt.Sprintf("%s|%s|%s|unknown||",
member.Name, addr.String(), member.Status)
result = append(result, line)
}
}
return result
}

// detailedOutput is used to dump all known information about nodes in
// their raw format
func (c *MembersCommand) detailedOutput(members []agent.Member) []string {
result := make([]string, 0, len(members))
header := "Node|Address|Status|Tags"
result = append(result, header)
for _, member := range members {
// Format the tags as tag1=v1,tag2=v2,...
var tagPairs []string
for name, value := range member.Tags {
Expand All @@ -101,17 +163,7 @@ func (c *MembersCommand) Run(args []string) int {
member.Name, addr.String(), member.Status, tags)
result = append(result, line)
}

// No matching members
if len(result) == 0 {
return 2
}

// Generate the columnized version
output := columnize.SimpleFormat(result)
c.Ui.Output(string(output))

return 0
return result
}

func (c *MembersCommand) Synopsis() string {
Expand Down
4 changes: 2 additions & 2 deletions website/source/docs/commands/members.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Usage: `consul members [options]`

The command-line flags are all optional. The list of available flags are:

* `-role` - If provided, output is filtered to only nodes matching
the regular expression for role
* `-detailed` - If provided, output shows more detailed information
about each node.

* `-rpc-addr` - Address to the RPC server of the agent you want to contact
to send this command. If this isn't specified, the command will contact
Expand Down

0 comments on commit e9c7098

Please sign in to comment.