diff --git a/.changelog/16055.txt b/.changelog/16055.txt new file mode 100644 index 00000000000..58d1e73fdb8 --- /dev/null +++ b/.changelog/16055.txt @@ -0,0 +1,3 @@ +```release-note:improvement +cli: Add `-json` and `-t` flag to `nomad acl token create` command +``` diff --git a/command/acl_token_create.go b/command/acl_token_create.go index e15d38be6db..ada1afb081d 100644 --- a/command/acl_token_create.go +++ b/command/acl_token_create.go @@ -53,6 +53,12 @@ Create Options: Specifies the time-to-live of the created ACL token. This takes the form of a time duration such as "5m" and "1h". By default, tokens will be created without a TTL and therefore never expire. + + -json + Output the ACL token information in JSON format. + + -t + Format and display the ACL token information using a Go template. ` return strings.TrimSpace(helpText) } @@ -67,6 +73,8 @@ func (c *ACLTokenCreateCommand) AutocompleteFlags() complete.Flags { "role-id": complete.PredictAnything, "role-name": complete.PredictAnything, "ttl": complete.PredictAnything, + "-json": complete.PredictNothing, + "-t": complete.PredictAnything, }) } @@ -81,8 +89,8 @@ func (c *ACLTokenCreateCommand) Synopsis() string { func (c *ACLTokenCreateCommand) Name() string { return "acl token create" } func (c *ACLTokenCreateCommand) Run(args []string) int { - var name, tokenType, ttl string - var global bool + var name, tokenType, ttl, tmpl string + var global, json bool var policies []string flags := c.Meta.FlagSet(c.Name(), FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } @@ -90,6 +98,8 @@ func (c *ACLTokenCreateCommand) Run(args []string) int { flags.StringVar(&tokenType, "type", "client", "") flags.BoolVar(&global, "global", false, "") flags.StringVar(&ttl, "ttl", "", "") + flags.BoolVar(&json, "json", false, "") + flags.StringVar(&tmpl, "t", "", "") flags.Var((funcVar)(func(s string) error { policies = append(policies, s) return nil @@ -148,6 +158,16 @@ func (c *ACLTokenCreateCommand) Run(args []string) int { return 1 } + if json || len(tmpl) > 0 { + out, err := Format(json, tmpl, token) + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + c.Ui.Output(out) + return 0 + } // Format the output outputACLToken(c.Ui, token) return 0 diff --git a/command/acl_token_create_test.go b/command/acl_token_create_test.go index 75cb5b898bb..49f7d110ce0 100644 --- a/command/acl_token_create_test.go +++ b/command/acl_token_create_test.go @@ -1,6 +1,7 @@ package command import ( + "encoding/json" "testing" "github.com/hashicorp/nomad/api" @@ -45,12 +46,50 @@ func TestACLTokenCreateCommand(t *testing.T) { ui.OutputWriter.Reset() ui.ErrorWriter.Reset() + // Test with a no-expiry token and -json/-t flag + testCasesNoTTL := []string{"-json", "-t='{{ .Policies }}'"} + var jsonMap map[string]interface{} + for _, outputFormatFlag := range testCasesNoTTL { + code = cmd.Run([]string{"-address=" + url, "-token=" + token.SecretID, "-policy=foo", "-type=client", outputFormatFlag}) + require.Equal(t, 0, code) + + // Check the output + out = ui.OutputWriter.String() + require.Contains(t, out, "foo") + if outputFormatFlag == "-json" { + err := json.Unmarshal([]byte(out), &jsonMap) + require.Nil(t, err, "Output not in JSON format") + } + + ui.OutputWriter.Reset() + ui.ErrorWriter.Reset() + } + // Create a new token that has an expiry TTL set and check the response. code = cmd.Run([]string{"-address=" + url, "-token=" + token.SecretID, "-type=management", "-ttl=10m"}) require.Equal(t, 0, code) out = ui.OutputWriter.String() require.NotContains(t, out, "Expiry Time = ") + ui.OutputWriter.Reset() + ui.ErrorWriter.Reset() + + // Test with a token that has expiry TTL set and -json/-t flag + testCasesWithTTL := [][]string{{"-json", "ExpirationTTL"}, {"-t='{{ .ExpirationTTL }}'", "10m0s"}} + for _, outputFormatFlag := range testCasesWithTTL { + code = cmd.Run([]string{"-address=" + url, "-token=" + token.SecretID, "-type=management", "-ttl=10m", outputFormatFlag[0]}) + require.Equal(t, 0, code) + + // Check the output + out = ui.OutputWriter.String() + if outputFormatFlag[0] == "-json" { + err := json.Unmarshal([]byte(out), &jsonMap) + require.Nil(t, err, "Output not in JSON format") + } + require.Contains(t, out, outputFormatFlag[1]) + ui.OutputWriter.Reset() + ui.ErrorWriter.Reset() + } } func Test_generateACLTokenRoleLinks(t *testing.T) { diff --git a/website/content/docs/commands/acl/token/create.mdx b/website/content/docs/commands/acl/token/create.mdx index aeac4ee876e..655c034bd94 100644 --- a/website/content/docs/commands/acl/token/create.mdx +++ b/website/content/docs/commands/acl/token/create.mdx @@ -44,6 +44,10 @@ The `acl token create` command requires no arguments. form of a time duration such as "5m" and "1h". By default, tokens will be created without a TTL and therefore never expire. +- `-json`:Output the ACL token information in JSON format. + +- `-t`: Format and display the ACL token information using a Go template. + ## Examples Create a new ACL token linked to an ACL Policy and Role: