github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/command/server_members.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/hashicorp/nomad/api" 9 "github.com/ryanuber/columnize" 10 ) 11 12 type ServerMembersCommand struct { 13 Meta 14 } 15 16 func (c *ServerMembersCommand) Help() string { 17 helpText := ` 18 Usage: nomad server-members [options] 19 20 Display a list of the known servers and their status. 21 22 General Options: 23 24 ` + generalOptionsUsage() + ` 25 26 Agent Members Options: 27 28 -detailed 29 Show detailed information about each member. This dumps 30 a raw set of tags which shows more information than the 31 default output format. 32 ` 33 return strings.TrimSpace(helpText) 34 } 35 36 func (c *ServerMembersCommand) Synopsis() string { 37 return "Display a list of known servers and their status" 38 } 39 40 func (c *ServerMembersCommand) Run(args []string) int { 41 var detailed bool 42 43 flags := c.Meta.FlagSet("server-members", FlagSetClient) 44 flags.Usage = func() { c.Ui.Output(c.Help()) } 45 flags.BoolVar(&detailed, "detailed", false, "Show detailed output") 46 47 if err := flags.Parse(args); err != nil { 48 return 1 49 } 50 51 // Check for extra arguments 52 args = flags.Args() 53 if len(args) != 0 { 54 c.Ui.Error(c.Help()) 55 return 1 56 } 57 58 // Get the HTTP client 59 client, err := c.Meta.Client() 60 if err != nil { 61 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 62 return 1 63 } 64 65 // Query the members 66 mem, err := client.Agent().Members() 67 if err != nil { 68 c.Ui.Error(fmt.Sprintf("Error querying servers: %s", err)) 69 return 1 70 } 71 72 // Sort the members 73 sort.Sort(api.AgentMembersNameSort(mem)) 74 75 // Determine the leaders per region. 76 leaders, err := regionLeaders(client, mem) 77 if err != nil { 78 c.Ui.Error(fmt.Sprintf("Error determining leaders: %s", err)) 79 return 1 80 } 81 82 // Format the list 83 var out []string 84 if detailed { 85 out = detailedOutput(mem) 86 } else { 87 out = standardOutput(mem, leaders) 88 } 89 90 // Dump the list 91 c.Ui.Output(columnize.SimpleFormat(out)) 92 return 0 93 } 94 95 func standardOutput(mem []*api.AgentMember, leaders map[string]string) []string { 96 // Format the members list 97 members := make([]string, len(mem)+1) 98 members[0] = "Name|Address|Port|Status|Leader|Protocol|Build|Datacenter|Region" 99 for i, member := range mem { 100 reg := member.Tags["region"] 101 regLeader, ok := leaders[reg] 102 isLeader := false 103 if ok { 104 if regLeader == fmt.Sprintf("%s:%s", member.Addr, member.Tags["port"]) { 105 106 isLeader = true 107 } 108 } 109 110 members[i+1] = fmt.Sprintf("%s|%s|%d|%s|%t|%d|%s|%s|%s", 111 member.Name, 112 member.Addr, 113 member.Port, 114 member.Status, 115 isLeader, 116 member.ProtocolCur, 117 member.Tags["build"], 118 member.Tags["dc"], 119 member.Tags["region"]) 120 } 121 return members 122 } 123 124 func detailedOutput(mem []*api.AgentMember) []string { 125 // Format the members list 126 members := make([]string, len(mem)+1) 127 members[0] = "Name|Address|Port|Tags" 128 for i, member := range mem { 129 // Format the tags 130 tagPairs := make([]string, 0, len(member.Tags)) 131 for k, v := range member.Tags { 132 tagPairs = append(tagPairs, fmt.Sprintf("%s=%s", k, v)) 133 } 134 tags := strings.Join(tagPairs, ",") 135 136 members[i+1] = fmt.Sprintf("%s|%s|%d|%s", 137 member.Name, 138 member.Addr, 139 member.Port, 140 tags) 141 } 142 return members 143 } 144 145 // regionLeaders returns a map of regions to the IP of the member that is the 146 // leader. 147 func regionLeaders(client *api.Client, mem []*api.AgentMember) (map[string]string, error) { 148 // Determine the unique regions. 149 leaders := make(map[string]string) 150 regions := make(map[string]struct{}) 151 for _, m := range mem { 152 regions[m.Tags["region"]] = struct{}{} 153 } 154 155 if len(regions) == 0 { 156 return leaders, nil 157 } 158 159 status := client.Status() 160 for reg := range regions { 161 l, err := status.RegionLeader(reg) 162 if err != nil { 163 // This error means that region has no leader. 164 if strings.Contains(err.Error(), "No cluster leader") { 165 continue 166 } 167 return nil, err 168 } 169 170 leaders[reg] = l 171 } 172 173 return leaders, nil 174 }