Skip to content

Commit c38a98e

Browse files
author
Chris Baker
committed
cli: add acl token list command, documentation
docs: fix some incorrect acl policy docs (typos, copy-paste errors)
1 parent ec3b8cd commit c38a98e

File tree

7 files changed

+233
-7
lines changed

7 files changed

+233
-7
lines changed

command/acl_token_list.go

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package command
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/hashicorp/nomad/api"
8+
"github.com/posener/complete"
9+
)
10+
11+
type ACLTokenListCommand struct {
12+
Meta
13+
}
14+
15+
func (c *ACLTokenListCommand) Help() string {
16+
helpText := `
17+
Usage: nomad acl token list
18+
19+
List is used to list existing ACL tokens.
20+
21+
General Options:
22+
23+
` + generalOptionsUsage() + `
24+
25+
List Options:
26+
27+
-json
28+
Output the ACL tokens in a JSON format.
29+
30+
-t
31+
Format and display the ACL tokens using a Go template.
32+
`
33+
34+
return strings.TrimSpace(helpText)
35+
}
36+
37+
func (c *ACLTokenListCommand) AutocompleteFlags() complete.Flags {
38+
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
39+
complete.Flags{
40+
"-json": complete.PredictNothing,
41+
"-t": complete.PredictAnything,
42+
})
43+
}
44+
45+
func (c *ACLTokenListCommand) AutocompleteArgs() complete.Predictor {
46+
return complete.PredictNothing
47+
}
48+
49+
func (c *ACLTokenListCommand) Synopsis() string {
50+
return "List ACL tokens"
51+
}
52+
53+
func (c *ACLTokenListCommand) Name() string { return "acl token list" }
54+
55+
func (c *ACLTokenListCommand) Run(args []string) int {
56+
var json bool
57+
var tmpl string
58+
59+
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
60+
flags.Usage = func() { c.Ui.Output(c.Help()) }
61+
flags.BoolVar(&json, "json", false, "")
62+
flags.StringVar(&tmpl, "t", "", "")
63+
64+
if err := flags.Parse(args); err != nil {
65+
return 1
66+
}
67+
68+
// Check that we got no arguments
69+
args = flags.Args()
70+
if l := len(args); l != 0 {
71+
c.Ui.Error("This command takes no arguments")
72+
c.Ui.Error(commandErrorText(c))
73+
return 1
74+
}
75+
76+
// Get the HTTP client
77+
client, err := c.Meta.Client()
78+
if err != nil {
79+
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
80+
return 1
81+
}
82+
83+
// Fetch info on the policy
84+
tokens, _, err := client.ACLTokens().List(nil)
85+
if err != nil {
86+
c.Ui.Error(fmt.Sprintf("Error listing ACL tokens: %s", err))
87+
return 1
88+
}
89+
90+
if json || len(tmpl) > 0 {
91+
out, err := Format(json, tmpl, tokens)
92+
if err != nil {
93+
c.Ui.Error(err.Error())
94+
return 1
95+
}
96+
97+
c.Ui.Output(out)
98+
return 0
99+
}
100+
101+
c.Ui.Output(formatTokens(tokens))
102+
return 0
103+
}
104+
105+
func formatTokens(tokens []*api.ACLTokenListStub) string {
106+
if len(tokens) == 0 {
107+
return "No tokens found"
108+
}
109+
110+
output := make([]string, 0, len(tokens)+1)
111+
output = append(output, fmt.Sprintf("Name|Type|Global|Accessor ID"))
112+
for _, p := range tokens {
113+
output = append(output, fmt.Sprintf("%s|%s|%t|%s", p.Name, p.Type, p.Global, p.AccessorID))
114+
}
115+
116+
return formatList(output)
117+
}

command/acl_token_list_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package command
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/hashicorp/nomad/acl"
8+
"github.com/hashicorp/nomad/command/agent"
9+
"github.com/hashicorp/nomad/nomad/mock"
10+
"github.com/hashicorp/nomad/nomad/structs"
11+
"github.com/mitchellh/cli"
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestACLTokenListCommand(t *testing.T) {
16+
assert := assert.New(t)
17+
t.Parallel()
18+
config := func(c *agent.Config) {
19+
c.ACL.Enabled = true
20+
}
21+
22+
srv, _, url := testServer(t, true, config)
23+
state := srv.Agent.Server().State()
24+
defer srv.Shutdown()
25+
26+
// Bootstrap an initial ACL token
27+
token := srv.RootToken
28+
assert.NotNil(token, "failed to bootstrap ACL token")
29+
30+
// Create a valid token
31+
mockToken := mock.ACLToken()
32+
mockToken.Policies = []string{acl.PolicyWrite}
33+
mockToken.SetHash()
34+
assert.Nil(state.UpsertACLTokens(1000, []*structs.ACLToken{mockToken}))
35+
36+
ui := new(cli.MockUi)
37+
cmd := &ACLTokenListCommand{Meta: Meta{Ui: ui, flagAddress: url}}
38+
39+
// Attempt to list tokens without a valid management token
40+
invalidToken := mock.ACLToken()
41+
code := cmd.Run([]string{"-address=" + url, "-token=" + invalidToken.SecretID})
42+
assert.Equal(1, code)
43+
44+
// Apply a token with a valid management token
45+
code = cmd.Run([]string{"-address=" + url, "-token=" + token.SecretID})
46+
assert.Equal(0, code)
47+
48+
// Check the output
49+
out := ui.OutputWriter.String()
50+
if !strings.Contains(out, mockToken.Name) {
51+
t.Fatalf("bad: %v", out)
52+
}
53+
54+
// List json
55+
if code := cmd.Run([]string{"-address=" + url, "-token=" + token.SecretID, "-json"}); code != 0 {
56+
t.Fatalf("expected exit 0, got: %d; %v", code, ui.ErrorWriter.String())
57+
}
58+
out = ui.OutputWriter.String()
59+
if !strings.Contains(out, "CreateIndex") {
60+
t.Fatalf("expected json output, got: %s", out)
61+
}
62+
ui.OutputWriter.Reset()
63+
}

command/commands.go

+5
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ func Commands(metaPtr *Meta, agentUi cli.Ui) map[string]cli.CommandFactory {
130130
Meta: meta,
131131
}, nil
132132
},
133+
"acl token list": func() (cli.Command, error) {
134+
return &ACLTokenListCommand{
135+
Meta: meta,
136+
}, nil
137+
},
133138
"acl token self": func() (cli.Command, error) {
134139
return &ACLTokenSelfCommand{
135140
Meta: meta,

website/source/docs/commands/acl/policy-list.html.md.erb

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ description: >
66
The policy list command is used to list available ACL policies.
77
---
88

9-
# Command: acl policy info
9+
# Command: acl policy list
1010

1111
The `acl policy list` command is used to list available ACL policies.
1212

@@ -22,17 +22,17 @@ nomad acl policy list
2222
#
2323
## List Options
2424

25-
* `-json` : Output the namespaces in their JSON format.
25+
* `-json` : Output the policies in their JSON format.
2626

27-
* `-t` : Format and display the namespaces using a Go template.
27+
* `-t` : Format and display the policies using a Go template.
2828

2929
## Examples
3030

3131
List all ACL policies:
3232

3333
```
3434
$ nomad acl policy list
35-
Name Description
36-
default-ns Write access to the default namespace
37-
node-read Node read access
35+
Name Description
36+
policy-1 The first policy
37+
policy-2 The second policy
3838
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
layout: "docs"
3+
page_title: "Commands: acl token list"
4+
sidebar_current: "docs-commands-acl-token-list"
5+
description: >
6+
The token list command is used to list existing ACL tokens.
7+
---
8+
9+
# Command: acl token list
10+
11+
The `acl token list` command is used to list existing ACL tokens.
12+
13+
## Usage
14+
15+
```
16+
nomad acl token list
17+
```
18+
19+
## General Options
20+
21+
<%= partial "docs/commands/_general_options" %>
22+
#
23+
## List Options
24+
25+
* `-json` : Output the tokens in their JSON format.
26+
27+
* `-t` : Format and display the tokens using a Go template.
28+
29+
## Examples
30+
31+
List all ACL tokens:
32+
33+
```
34+
$ nomad acl token list
35+
Name Type Global Accessor ID
36+
Bootstrap Token management true 32b61154-47f1-3694-1430-a5544bafcd3e
37+
<none> client false fcf2bf84-a257-8f39-9d16-a954ed25b5be
38+
```

website/source/docs/commands/acl/token-self.html.md.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Fetch information about an existing ACL token:
2828
```
2929
$ export NOMAD_TOKEN=d532c40a-30f1-695c-19e5-c35b882b0efd
3030

31-
$ nomad acl tokenjself
31+
$ nomad acl token self
3232
Accessor ID = d532c40a-30f1-695c-19e5-c35b882b0efd
3333
Secret ID = 85310d07-9afa-ef53-0933-0c043cd673c7
3434
Name = my token

website/source/layouts/docs.erb

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
<li<%= sidebar_current("docs-commands-acl-token-info") %>>
101101
<a href="/docs/commands/acl/token-info.html">token info</a>
102102
</li>
103+
<li<%= sidebar_current("docs-commands-acl-token-list") %>>
104+
<a href="/docs/commands/acl/token-list.html">token list</a>
105+
</li>
103106
<li<%= sidebar_current("docs-commands-acl-token-self") %>>
104107
<a href="/docs/commands/acl/token-self.html">token self</a>
105108
</li>

0 commit comments

Comments
 (0)