-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
service_list.go
180 lines (139 loc) · 4.5 KB
/
service_list.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package command
import (
"fmt"
"sort"
"strings"
"github.com/hashicorp/nomad/api"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
// Ensure ServiceListCommand satisfies the cli.Command interface.
var _ cli.Command = &ServiceListCommand{}
// ServiceListCommand implements cli.Command.
type ServiceListCommand struct {
Meta
}
// Help satisfies the cli.Command Help function.
func (s *ServiceListCommand) Help() string {
helpText := `
Usage: nomad service list [options]
List is used to list the currently registered services.
If ACLs are enabled, this command requires a token with the 'read-job'
capabilities for the namespace of all services. Any namespaces that the token
does not have access to will have its services filtered from the results.
General Options:
` + generalOptionsUsage(usageOptsDefault) + `
Service List Options:
-json
Output the services in JSON format.
-t
Format and display the services using a Go template.
`
return strings.TrimSpace(helpText)
}
// Synopsis satisfies the cli.Command Synopsis function.
func (s *ServiceListCommand) Synopsis() string {
return "Display all registered Nomad services"
}
func (s *ServiceListCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(s.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-json": complete.PredictNothing,
"-t": complete.PredictAnything,
})
}
// Name returns the name of this command.
func (s *ServiceListCommand) Name() string { return "service list" }
// Run satisfies the cli.Command Run function.
func (s *ServiceListCommand) Run(args []string) int {
var (
json bool
tmpl, name string
)
flags := s.Meta.FlagSet(s.Name(), FlagSetClient)
flags.Usage = func() { s.Ui.Output(s.Help()) }
flags.BoolVar(&json, "json", false, "")
flags.StringVar(&name, "name", "", "")
flags.StringVar(&tmpl, "t", "", "")
if err := flags.Parse(args); err != nil {
return 1
}
if args = flags.Args(); len(args) > 0 {
s.Ui.Error("This command takes no arguments")
s.Ui.Error(commandErrorText(s))
return 1
}
client, err := s.Meta.Client()
if err != nil {
s.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
return 1
}
list, _, err := client.Services().List(nil)
if err != nil {
s.Ui.Error(fmt.Sprintf("Error listing service registrations: %s", err))
return 1
}
if len(list) == 0 {
s.Ui.Output("No service registrations found")
return 0
}
if json || len(tmpl) > 0 {
out, err := Format(json, tmpl, list)
if err != nil {
s.Ui.Error(err.Error())
return 1
}
s.Ui.Output(out)
return 0
}
s.formatOutput(list)
return 0
}
func (s *ServiceListCommand) formatOutput(regs []*api.ServiceRegistrationListStub) {
// Create objects to hold sorted a sorted namespace array and a mapping, so
// we can perform service lookups on a namespace basis.
sortedNamespaces := make([]string, len(regs))
namespacedServices := make(map[string][]*api.ServiceRegistrationStub)
for i, namespaceServices := range regs {
sortedNamespaces[i] = namespaceServices.Namespace
namespacedServices[namespaceServices.Namespace] = namespaceServices.Services
}
// Sort the namespaces.
sort.Strings(sortedNamespaces)
// The table always starts with the service name.
outputTable := []string{"Service Name"}
// If the request was made using the wildcard namespace, include this in
// the output.
if s.Meta.namespace == api.AllNamespacesNamespace {
outputTable[0] += "|Namespace"
}
// The tags come last and are always present.
outputTable[0] += "|Tags"
for _, ns := range sortedNamespaces {
// Grab the services belonging to this namespace.
services := namespacedServices[ns]
// Create objects to hold sorted a sorted service name array and a
// mapping, so we can perform service tag lookups on a name basis.
sortedNames := make([]string, len(services))
serviceTags := make(map[string][]string)
for i, service := range services {
sortedNames[i] = service.ServiceName
serviceTags[service.ServiceName] = service.Tags
}
// Sort the service names.
sort.Strings(sortedNames)
for _, serviceName := range sortedNames {
// Grab the service tags, and sort these for good measure.
tags := serviceTags[serviceName]
sort.Strings(tags)
// Build the output array entry.
regOutput := serviceName
if s.Meta.namespace == api.AllNamespacesNamespace {
regOutput += "|" + ns
}
regOutput += "|" + fmt.Sprintf("[%s]", strings.Join(tags, ","))
outputTable = append(outputTable, regOutput)
}
}
s.Ui.Output(formatList(outputTable))
}