1package command 2 3import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "github.com/mitchellh/cli" 8 "sort" 9 "strings" 10) 11 12// InfoCommand is a Command implementation that queries a running 13// Serf agent for various debugging statistics for operators 14type InfoCommand struct { 15 Ui cli.Ui 16} 17 18func (i *InfoCommand) Help() string { 19 helpText := ` 20Usage: serf info [options] 21 22 Provides debugging information for operators 23 24Options: 25 26 -format If provided, output is returned in the specified 27 format. Valid formats are 'json', and 'text' (default) 28 29 -rpc-addr=127.0.0.1:7373 RPC address of the Serf agent. 30 31 -rpc-auth="" RPC auth token of the Serf agent. 32` 33 return strings.TrimSpace(helpText) 34} 35 36func (i *InfoCommand) Run(args []string) int { 37 var format string 38 cmdFlags := flag.NewFlagSet("info", flag.ContinueOnError) 39 cmdFlags.Usage = func() { i.Ui.Output(i.Help()) } 40 cmdFlags.StringVar(&format, "format", "text", "output format") 41 rpcAddr := RPCAddrFlag(cmdFlags) 42 rpcAuth := RPCAuthFlag(cmdFlags) 43 if err := cmdFlags.Parse(args); err != nil { 44 return 1 45 } 46 47 client, err := RPCClient(*rpcAddr, *rpcAuth) 48 if err != nil { 49 i.Ui.Error(fmt.Sprintf("Error connecting to Serf agent: %s", err)) 50 return 1 51 } 52 defer client.Close() 53 54 stats, err := client.Stats() 55 if err != nil { 56 i.Ui.Error(fmt.Sprintf("Error querying agent: %s", err)) 57 return 1 58 } 59 60 output, err := formatOutput(StatsContainer(stats), format) 61 if err != nil { 62 i.Ui.Error(fmt.Sprintf("Encoding error: %s", err)) 63 return 1 64 } 65 66 i.Ui.Output(string(output)) 67 return 0 68} 69 70func (i *InfoCommand) Synopsis() string { 71 return "Provides debugging information for operators" 72} 73 74type StatsContainer map[string]map[string]string 75 76func (s StatsContainer) String() string { 77 var buf bytes.Buffer 78 79 // Get the keys in sorted order 80 keys := make([]string, 0, len(s)) 81 for key := range s { 82 keys = append(keys, key) 83 } 84 sort.Strings(keys) 85 86 // Iterate over each top-level key 87 for _, key := range keys { 88 buf.WriteString(fmt.Sprintf(key + ":\n")) 89 90 // Sort the sub-keys 91 subvals := s[key] 92 subkeys := make([]string, 0, len(subvals)) 93 for k := range subvals { 94 subkeys = append(subkeys, k) 95 } 96 sort.Strings(subkeys) 97 98 // Iterate over the subkeys 99 for _, subkey := range subkeys { 100 val := subvals[subkey] 101 buf.WriteString(fmt.Sprintf("\t%s = %s\n", subkey, val)) 102 } 103 } 104 return buf.String() 105} 106