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