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 }