1package command
2
3import (
4	"fmt"
5	"strings"
6
7	"github.com/hashicorp/nomad/api"
8	"github.com/posener/complete"
9)
10
11type NamespaceStatusCommand struct {
12	Meta
13}
14
15func (c *NamespaceStatusCommand) Help() string {
16	helpText := `
17Usage: nomad namespace status [options] <namespace>
18
19  Status is used to view the status of a particular namespace.
20
21General Options:
22
23  ` + generalOptionsUsage()
24
25	return strings.TrimSpace(helpText)
26}
27
28func (c *NamespaceStatusCommand) AutocompleteFlags() complete.Flags {
29	return c.Meta.AutocompleteFlags(FlagSetClient)
30}
31
32func (c *NamespaceStatusCommand) AutocompleteArgs() complete.Predictor {
33	return NamespacePredictor(c.Meta.Client, nil)
34}
35
36func (c *NamespaceStatusCommand) Synopsis() string {
37	return "Display a namespace's status"
38}
39
40func (c *NamespaceStatusCommand) Name() string { return "namespace status" }
41
42func (c *NamespaceStatusCommand) Run(args []string) int {
43	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
44	flags.Usage = func() { c.Ui.Output(c.Help()) }
45
46	if err := flags.Parse(args); err != nil {
47		return 1
48	}
49
50	// Check that we got one arguments
51	args = flags.Args()
52	if l := len(args); l != 1 {
53		c.Ui.Error("This command takes one argument: <namespace>")
54		c.Ui.Error(commandErrorText(c))
55		return 1
56	}
57
58	name := args[0]
59
60	// Get the HTTP client
61	client, err := c.Meta.Client()
62	if err != nil {
63		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
64		return 1
65	}
66
67	// Do a prefix lookup
68	ns, possible, err := getNamespace(client.Namespaces(), name)
69	if err != nil {
70		c.Ui.Error(fmt.Sprintf("Error retrieving namespaces: %s", err))
71		return 1
72	}
73
74	if len(possible) != 0 {
75		c.Ui.Error(fmt.Sprintf("Prefix matched multiple namespaces\n\n%s", formatNamespaces(possible)))
76		return 1
77	}
78
79	c.Ui.Output(formatNamespaceBasics(ns))
80
81	if ns.Quota != "" {
82		quotas := client.Quotas()
83		spec, _, err := quotas.Info(ns.Quota, nil)
84		if err != nil {
85			c.Ui.Error(fmt.Sprintf("Error retrieving quota spec: %s", err))
86			return 1
87		}
88
89		// Get the quota usages
90		usages, failures := quotaUsages(spec, quotas)
91
92		// Format the limits
93		c.Ui.Output(c.Colorize().Color("\n[bold]Quota Limits[reset]"))
94		c.Ui.Output(formatQuotaLimits(spec, usages))
95
96		// Display any failures
97		if len(failures) != 0 {
98			c.Ui.Error(c.Colorize().Color("\n[bold][red]Lookup Failures[reset]"))
99			for region, failure := range failures {
100				c.Ui.Error(fmt.Sprintf("  * Failed to retrieve quota usage for region %q: %v", region, failure))
101				return 1
102			}
103		}
104	}
105
106	return 0
107}
108
109// formatNamespaceBasics formats the basic information of the namespace
110func formatNamespaceBasics(ns *api.Namespace) string {
111	basic := []string{
112		fmt.Sprintf("Name|%s", ns.Name),
113		fmt.Sprintf("Description|%s", ns.Description),
114		fmt.Sprintf("Quota|%s", ns.Quota),
115	}
116
117	return formatKV(basic)
118}
119
120func getNamespace(client *api.Namespaces, ns string) (match *api.Namespace, possible []*api.Namespace, err error) {
121	// Do a prefix lookup
122	namespaces, _, err := client.PrefixList(ns, nil)
123	if err != nil {
124		return nil, nil, err
125	}
126
127	l := len(namespaces)
128	switch {
129	case l == 0:
130		return nil, nil, fmt.Errorf("Namespace %q matched no namespaces", ns)
131	case l == 1:
132		return namespaces[0], nil, nil
133	default:
134		// search for an exact match in the returned namespaces
135		for _, namespace := range namespaces {
136			if namespace.Name == ns {
137				return namespace, nil, nil
138			}
139		}
140		// if not found, return the fuzzy matches.
141		return nil, namespaces, nil
142	}
143}
144