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