github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/acl_token_create.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/hashicorp/go-set"
     9  	"github.com/hashicorp/nomad/api"
    10  	"github.com/hashicorp/nomad/helper"
    11  	"github.com/posener/complete"
    12  )
    13  
    14  type ACLTokenCreateCommand struct {
    15  	Meta
    16  
    17  	roleNames []string
    18  	roleIDs   []string
    19  }
    20  
    21  func (c *ACLTokenCreateCommand) Help() string {
    22  	helpText := `
    23  Usage: nomad acl token create [options]
    24  
    25    Create is used to issue new ACL tokens. Requires a management token.
    26  
    27  General Options:
    28  
    29    ` + generalOptionsUsage(usageOptsDefault|usageOptsNoNamespace) + `
    30  
    31  Create Options:
    32  
    33    -name=""
    34      Sets the human readable name for the ACL token.
    35  
    36    -type="client"
    37      Sets the type of token. Must be one of "client" (default), or "management".
    38  
    39    -global=false
    40      Toggles the global mode of the token. Global tokens are replicated to all regions.
    41  
    42    -policy=""
    43      Specifies a policy to associate with the token. Can be specified multiple times,
    44      but only with client type tokens.
    45  
    46    -role-id
    47       ID of a role to use for this token. May be specified multiple times.
    48  
    49    -role-name
    50       Name of a role to use for this token. May be specified multiple times.
    51  
    52    -ttl
    53      Specifies the time-to-live of the created ACL token. This takes the form of
    54      a time duration such as "5m" and "1h". By default, tokens will be created
    55      without a TTL and therefore never expire.
    56  `
    57  	return strings.TrimSpace(helpText)
    58  }
    59  
    60  func (c *ACLTokenCreateCommand) AutocompleteFlags() complete.Flags {
    61  	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
    62  		complete.Flags{
    63  			"name":      complete.PredictAnything,
    64  			"type":      complete.PredictAnything,
    65  			"global":    complete.PredictNothing,
    66  			"policy":    complete.PredictAnything,
    67  			"role-id":   complete.PredictAnything,
    68  			"role-name": complete.PredictAnything,
    69  			"ttl":       complete.PredictAnything,
    70  		})
    71  }
    72  
    73  func (c *ACLTokenCreateCommand) AutocompleteArgs() complete.Predictor {
    74  	return complete.PredictNothing
    75  }
    76  
    77  func (c *ACLTokenCreateCommand) Synopsis() string {
    78  	return "Create a new ACL token"
    79  }
    80  
    81  func (c *ACLTokenCreateCommand) Name() string { return "acl token create" }
    82  
    83  func (c *ACLTokenCreateCommand) Run(args []string) int {
    84  	var name, tokenType, ttl string
    85  	var global bool
    86  	var policies []string
    87  	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
    88  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    89  	flags.StringVar(&name, "name", "", "")
    90  	flags.StringVar(&tokenType, "type", "client", "")
    91  	flags.BoolVar(&global, "global", false, "")
    92  	flags.StringVar(&ttl, "ttl", "", "")
    93  	flags.Var((funcVar)(func(s string) error {
    94  		policies = append(policies, s)
    95  		return nil
    96  	}), "policy", "")
    97  	flags.Var((funcVar)(func(s string) error {
    98  		c.roleNames = append(c.roleNames, s)
    99  		return nil
   100  	}), "role-name", "")
   101  	flags.Var((funcVar)(func(s string) error {
   102  		c.roleIDs = append(c.roleIDs, s)
   103  		return nil
   104  	}), "role-id", "")
   105  	if err := flags.Parse(args); err != nil {
   106  		return 1
   107  	}
   108  
   109  	// Check that we got no arguments
   110  	args = flags.Args()
   111  	if l := len(args); l != 0 {
   112  		c.Ui.Error("This command takes no arguments")
   113  		c.Ui.Error(commandErrorText(c))
   114  		return 1
   115  	}
   116  
   117  	// Set up the token.
   118  	tk := &api.ACLToken{
   119  		Name:     name,
   120  		Type:     tokenType,
   121  		Policies: policies,
   122  		Roles:    generateACLTokenRoleLinks(c.roleNames, c.roleIDs),
   123  		Global:   global,
   124  	}
   125  
   126  	// If the user set a TTL flag value, convert this to a time duration and
   127  	// add it to our token request object.
   128  	if ttl != "" {
   129  		ttlDuration, err := time.ParseDuration(ttl)
   130  		if err != nil {
   131  			c.Ui.Error(fmt.Sprintf("Failed to parse TTL as time duration: %s", err))
   132  			return 1
   133  		}
   134  		tk.ExpirationTTL = ttlDuration
   135  	}
   136  
   137  	// Get the HTTP client
   138  	client, err := c.Meta.Client()
   139  	if err != nil {
   140  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
   141  		return 1
   142  	}
   143  
   144  	// Create the bootstrap token
   145  	token, _, err := client.ACLTokens().Create(tk, nil)
   146  	if err != nil {
   147  		c.Ui.Error(fmt.Sprintf("Error creating token: %s", err))
   148  		return 1
   149  	}
   150  
   151  	// Format the output
   152  	outputACLToken(c.Ui, token)
   153  	return 0
   154  }
   155  
   156  // generateACLTokenRoleLinks takes the command input role links by ID and name
   157  // and coverts this to the relevant API object. It handles de-duplicating
   158  // entries to the best effort, so this doesn't need to be done on the leader.
   159  func generateACLTokenRoleLinks(roleNames, roleIDs []string) []*api.ACLTokenRoleLink {
   160  	var tokenLinks []*api.ACLTokenRoleLink
   161  
   162  	roleNameSet := set.From[string](roleNames).List()
   163  	roleNameFn := func(name string) *api.ACLTokenRoleLink { return &api.ACLTokenRoleLink{Name: name} }
   164  
   165  	roleIDsSet := set.From[string](roleIDs).List()
   166  	roleIDFn := func(id string) *api.ACLTokenRoleLink { return &api.ACLTokenRoleLink{ID: id} }
   167  
   168  	tokenLinks = append(tokenLinks, helper.ConvertSlice(roleNameSet, roleNameFn)...)
   169  	tokenLinks = append(tokenLinks, helper.ConvertSlice(roleIDsSet, roleIDFn)...)
   170  
   171  	return tokenLinks
   172  }