Skip to content

Commit

Permalink
Merge pull request #935 from hashicorp/f-server-members-leader
Browse files Browse the repository at this point in the history
cli: server-members displays leader per region
  • Loading branch information
dadgar committed Mar 17, 2016
2 parents 8a433ee + 1390640 commit 074b245
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
11 changes: 11 additions & 0 deletions api/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ func (s *Status) Leader() (string, error) {
return resp, nil
}

// RegionLeader is used to query for the leader in the passed region.
func (s *Status) RegionLeader(region string) (string, error) {
var resp string
q := QueryOptions{Region: region}
_, err := s.client.query("/v1/status/leader", &resp, &q)
if err != nil {
return "", err
}
return resp, nil
}

// Peers is used to query the addresses of the server peers
// in the cluster.
func (s *Status) Peers() ([]string, error) {
Expand Down
52 changes: 48 additions & 4 deletions command/server_members.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,47 @@ func (c *ServerMembersCommand) Run(args []string) int {
// Sort the members
sort.Sort(api.AgentMembersNameSort(mem))

// Determine the leaders per region.
leaders, err := regionLeaders(client, mem)
if err != nil && !strings.Contains(err.Error(), "No cluster leader") {
c.Ui.Error(fmt.Sprintf("Error determining leaders: %s", err))
return 1
}

// Format the list
var out []string
if detailed {
out = detailedOutput(mem)
} else {
out = standardOutput(mem)
out = standardOutput(mem, leaders)
}

// Dump the list
c.Ui.Output(columnize.SimpleFormat(out))
return 0
}

func standardOutput(mem []*api.AgentMember) []string {
func standardOutput(mem []*api.AgentMember, leaders map[string]string) []string {
// Format the members list
members := make([]string, len(mem)+1)
members[0] = "Name|Address|Port|Status|Protocol|Build|Datacenter|Region"
members[0] = "Name|Address|Port|Status|Leader|Protocol|Build|Datacenter|Region"
for i, member := range mem {
members[i+1] = fmt.Sprintf("%s|%s|%d|%s|%d|%s|%s|%s",
reg := member.Tags["region"]
regLeader, ok := leaders[reg]
isLeader := false
if ok {
if regLeader == fmt.Sprintf("%s:%s", member.Addr, member.Tags["port"]) {

isLeader = true
}
}

members[i+1] = fmt.Sprintf("%s|%s|%d|%s|%t|%d|%s|%s|%s",
member.Name,
member.Addr,
member.Port,
member.Status,
isLeader,
member.ProtocolCur,
member.Tags["build"],
member.Tags["dc"],
Expand Down Expand Up @@ -123,3 +141,29 @@ func detailedOutput(mem []*api.AgentMember) []string {
}
return members
}

// regionLeaders returns a map of regions to the IP of the member that is the
// leader.
func regionLeaders(client *api.Client, mem []*api.AgentMember) (map[string]string, error) {
// Determine the unique regions.
leaders := make(map[string]string)
regions := make(map[string]struct{})
for _, m := range mem {
regions[m.Tags["region"]] = struct{}{}
}

if len(regions) == 0 {
return leaders, nil
}

status := client.Status()
for reg := range regions {
l, err := status.RegionLeader(reg)
if err != nil {
return leaders, err
}
leaders[reg] = l
}

return leaders, nil
}
2 changes: 1 addition & 1 deletion nomad/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ func (s *Server) setupWorkers() error {
}

// numOtherPeers is used to check on the number of known peers
// excluding the local ndoe
// excluding the local node
func (s *Server) numOtherPeers() (int, error) {
peers, err := s.raftPeers.Peers()
if err != nil {
Expand Down

0 comments on commit 074b245

Please sign in to comment.