Add CLI for workers (#2164)

pull/2146/head
Jeff Mitchell 4 years ago committed by GitHub
parent 5b978d7fa7
commit b84001c07d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,7 @@
package workers
import (
"strconv"
"strings"
"github.com/hashicorp/boundary/api"
@ -21,6 +22,7 @@ type options struct {
withAutomaticVersioning bool
withSkipCurlOutput bool
withFilter string
withRecursive bool
}
func getDefaultOptions() options {
@ -44,6 +46,9 @@ func getOpts(opt ...Option) (options, []api.Option) {
if opts.withFilter != "" {
opts.queryMap["filter"] = opts.withFilter
}
if opts.withRecursive {
opts.queryMap["recursive"] = strconv.FormatBool(opts.withRecursive)
}
return opts, apiOpts
}
@ -74,6 +79,14 @@ func WithFilter(filter string) Option {
}
}
// WithRecursive tells the API to use recursion for listing operations on this
// resource
func WithRecursive(recurse bool) Option {
return func(o *options) {
o.withRecursive = true
}
}
func WithAddress(inAddress string) Option {
return func(o *options) {
o.postMap["address"] = inAddress

@ -3,6 +3,7 @@ package workers
import (
"context"
"errors"
"fmt"
"net/url"
"time"
@ -193,6 +194,26 @@ func (c *Client) Update(ctx context.Context, id string, version uint32, opt ...O
opts, apiOpts := getOpts(opt...)
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingErr := c.Read(ctx, id, append([]Option{WithSkipCurlOutput(true)}, opt...)...)
if existingErr != nil {
if api.AsServerError(existingErr) != nil {
return nil, fmt.Errorf("error from controller when performing initial check-and-set read: %w", existingErr)
}
return nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingTarget == nil {
return nil, errors.New("nil resource response found when performing initial check-and-set read")
}
if existingTarget.Item == nil {
return nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Item.Version
}
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("workers/%s", url.PathEscape(id)), opts.postMap, apiOpts...)

@ -738,6 +738,10 @@ var inputStructs = []*structInfo{
fieldFilter: []string{"private_key"},
recursiveListing: true,
},
{
inProto: &workers.WorkerProvidedConfiguration{},
outFile: "workers/worker_provided_configuration.gen.go",
},
{
inProto: &workers.Worker{},
outFile: "workers/worker.gen.go",
@ -769,9 +773,6 @@ var inputStructs = []*structInfo{
pluralResourceName: "workers",
createResponseTypes: true,
recursiveListing: true,
},
{
inProto: &workers.WorkerProvidedConfiguration{},
outFile: "workers/worker_provided_configuration.gen.go",
versionEnabled: true,
},
}

@ -25,6 +25,7 @@ import (
"github.com/hashicorp/boundary/internal/cmd/commands/targetscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/userscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/version"
"github.com/hashicorp/boundary/internal/cmd/commands/workerscmd"
"github.com/mitchellh/cli"
)
@ -1028,5 +1029,42 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
Func: "remove-accounts",
}, nil
},
"workers create": func() (cli.Command, error) {
return &workerscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"workers create worker-led": func() (cli.Command, error) {
return &workerscmd.WorkerLedCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"workers read": func() (cli.Command, error) {
return &workerscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"workers update": func() (cli.Command, error) {
return &workerscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"workers delete": func() (cli.Command, error) {
return &workerscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"workers list": func() (cli.Command, error) {
return &workerscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
}
}

@ -117,7 +117,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -115,6 +115,12 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}
c.plural = "auth token"

@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -117,7 +117,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -115,7 +115,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -538,9 +538,15 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
c.UI.Error("Controller has no name set. It must be the unique name of this instance.")
return base.CommandUserError
}
if c.Config.Worker != nil && c.Config.Worker.Name == "" {
c.UI.Error("Worker has no name set. It must be the unique name of this instance.")
return base.CommandUserError
if c.Config.Worker != nil {
if c.Config.Worker.Name == "" {
c.UI.Error("Worker has no name set. It must be the unique name of this instance.")
return base.CommandUserError
}
if c.Config.Worker.AuthStoragePath == "" {
c.UI.Error("No worker auth KMS specified and no worker auth storage path specified.")
return base.CommandUserError
}
}
return base.CommandSuccess

@ -14,6 +14,8 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"sync"
"testing"
"time"
@ -50,6 +52,7 @@ worker {
tags {
type = ["dev", "local"]
}
auth_storage_path = "%s"
}
`
@ -61,6 +64,7 @@ worker {
tags {
foo = ["bar", "baz"]
}
auth_storage_path = "%s"
}
`
@ -74,10 +78,14 @@ func TestServer_ReloadWorkerTags(t *testing.T) {
testController := controller.NewTestController(t, controller.WithWorkerAuthKms(workerAuthWrapper), controller.WithRootKms(rootWrapper), controller.WithRecoveryKms(recoveryWrapper))
defer testController.Shutdown()
authStoragePath, err := os.MkdirTemp("", "")
require.NoError(err)
t.Cleanup(func() { os.RemoveAll(authStoragePath) })
wg := &sync.WaitGroup{}
cmd := testServerCommand(t, testServerCommandOpts{})
cmd.presetConfig = atomic.NewString(fmt.Sprintf(workerBaseConfig+tag1Config, key, testController.ClusterAddrs()[0]))
cmd.presetConfig = atomic.NewString(fmt.Sprintf(workerBaseConfig+tag1Config, key, testController.ClusterAddrs()[0], filepath.Join(authStoragePath, "tag1")))
wg.Add(1)
go func() {
@ -110,7 +118,7 @@ func TestServer_ReloadWorkerTags(t *testing.T) {
time.Sleep(10 * time.Second)
fetchWorkerTags("test", "type", []string{"dev", "local"})
cmd.presetConfig.Store(fmt.Sprintf(workerBaseConfig+tag2Config, key, testController.ClusterAddrs()[0]))
cmd.presetConfig.Store(fmt.Sprintf(workerBaseConfig+tag2Config, key, testController.ClusterAddrs()[0], filepath.Join(authStoragePath, "tag2")))
cmd.SighupCh <- struct{}{}
select {

@ -110,6 +110,12 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}
c.plural = "session"

@ -123,7 +123,10 @@ func (c *Command) Run(args []string) int {
case "":
return cli.RunResultHelp
case "create", "update":
case "create":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}

@ -0,0 +1,215 @@
package workerscmd
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/workers"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func (c *Command) printListTable(items []*workers.Worker) string {
if len(items) == 0 {
return "No workers found"
}
var output []string
output = []string{
"",
"Worker information:",
}
for i, item := range items {
if i > 0 {
output = append(output, "")
}
if item.Id != "" {
output = append(output,
fmt.Sprintf(" ID: %s", item.Id),
)
} else {
output = append(output,
fmt.Sprintf(" ID: %s", "(not available)"),
)
}
if c.FlagRecursive && item.ScopeId != "" {
output = append(output,
fmt.Sprintf(" Scope ID: %s", item.ScopeId),
)
}
if item.Version > 0 {
output = append(output,
fmt.Sprintf(" Version: %d", item.Version),
)
}
if item.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", item.Name),
)
}
if item.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", item.Description),
)
}
if item.CanonicalAddress != "" {
output = append(output,
fmt.Sprintf(" Canonical Address: %s", item.CanonicalAddress),
)
}
if !item.LastStatusTime.IsZero() {
output = append(output,
fmt.Sprintf(" Last Status Time: %s", item.LastStatusTime.Format(time.RFC1123)),
)
}
if true {
output = append(output,
fmt.Sprintf(" Active Connection Count: %d", item.ActiveConnectionCount),
)
}
if len(item.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, item.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(result api.GenericResult) string {
item := result.GetItem().(*workers.Worker)
nonAttributeMap := map[string]interface{}{}
if item.Id != "" {
nonAttributeMap["ID"] = item.Id
}
if item.Version != 0 {
nonAttributeMap["Version"] = item.Version
}
if !item.CreatedTime.IsZero() {
nonAttributeMap["Created Time"] = item.CreatedTime.Local().Format(time.RFC1123)
}
if !item.UpdatedTime.IsZero() {
nonAttributeMap["Updated Time"] = item.UpdatedTime.Local().Format(time.RFC1123)
}
if item.Name != "" {
nonAttributeMap["Name"] = item.Name
}
if item.Description != "" {
nonAttributeMap["Description"] = item.Description
}
if !item.LastStatusTime.IsZero() {
nonAttributeMap["Last Status Time"] = item.LastStatusTime
}
nonAttributeMap["Active Connection Count"] = item.ActiveConnectionCount
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Worker information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
}
if item.Scope != nil {
ret = append(ret,
"",
" Scope:",
base.ScopeInfoForOutput(item.Scope, maxLength),
)
}
var workerProvidedTags map[string][]string
var workerProvidedAddress string
if item.WorkerProvidedConfiguration != nil {
config := item.WorkerProvidedConfiguration
configMap := make(map[string]any)
if config.Address != "" {
configMap["Address"] = config.Address
workerProvidedAddress = config.Address
}
if config.Name != "" {
configMap["Name"] = config.Name
}
ret = append(ret,
"",
" Worker-Provided Configuration:",
base.WrapMap(4, maxLength, configMap),
)
workerProvidedTags = config.Tags
}
if len(item.Address) > 0 || len(item.CanonicalAddress) > 0 || len(workerProvidedAddress) > 0 {
ret = append(ret,
"",
" Address:",
)
if len(item.Address) > 0 {
ret = append(ret,
" Item (via API):",
" "+item.Address,
)
}
if len(workerProvidedAddress) > 0 {
ret = append(ret,
" Worker Configuration:",
" "+workerProvidedAddress,
)
}
if len(item.CanonicalAddress) > 0 {
ret = append(ret,
" Canonical:",
" "+item.CanonicalAddress,
)
}
}
if len(item.Tags) > 0 || len(item.CanonicalTags) > 0 || len(workerProvidedTags) > 0 {
ret = append(ret,
"",
" Tags:",
)
if len(item.Tags) > 0 {
tagMap := make(map[string]any, len(item.Tags))
for k, v := range item.Tags {
tagMap[k] = v
}
ret = append(ret,
" Item (via API):",
base.WrapMap(6, 2, tagMap),
)
}
if len(workerProvidedTags) > 0 {
tagMap := make(map[string]any, len(workerProvidedTags))
for k, v := range workerProvidedTags {
tagMap[k] = v
}
ret = append(ret,
" Worker Configuration:",
base.WrapMap(6, 2, tagMap),
)
}
if len(item.CanonicalTags) > 0 {
tagMap := make(map[string]any, len(item.CanonicalTags))
for k, v := range item.CanonicalTags {
tagMap[k] = v
}
ret = append(ret,
" Canonical:",
base.WrapMap(6, 2, tagMap),
)
}
}
if len(item.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, item.AuthorizedActions),
)
}
return base.WrapForHelpText(ret)
}

@ -0,0 +1,63 @@
package workerscmd
import (
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/workers"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func init() {
extraWorkerLedActionsFlagsMapFunc = extraWorkerLedActionsFlagsMapFuncImpl
extraWorkerLedFlagsFunc = extraWorkerLedFlagsFuncImpl
executeExtraWorkerLedActions = executeExtraWorkerLedActionsImpl
}
type extraWorkerLedCmdVars struct {
flagWorkerGeneratedAuthToken string
}
func extraWorkerLedActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"worker-generated-auth-token"},
}
}
func (c *WorkerLedCommand) extraWorkerLedHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary workers create worker-led [options] [args]",
"",
" Create a worker using the worker-led approach by providing an auth token from the worker. Example:",
"",
` $ boundary workers create worker-led -name us-east-1-1 -worker-generated-auth-token <token>"`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func extraWorkerLedFlagsFuncImpl(c *WorkerLedCommand, set *base.FlagSets, f *base.FlagSet) {
f = set.NewFlagSet("Worker Creation Options")
for _, name := range flagsWorkerLedMap[c.Func] {
switch name {
case "worker-generated-auth-token":
f.StringVar(&base.StringVar{
Name: "worker-generated-auth-token",
Target: &c.flagWorkerGeneratedAuthToken,
Usage: "The auth token provided by the worker to use to register it to Boundary",
})
}
}
}
func executeExtraWorkerLedActionsImpl(c *WorkerLedCommand, origResult api.GenericResult, origError error, workerClient *workers.Client, version uint32, opts []workers.Option) (api.GenericResult, error) {
switch c.Func {
case "create":
return workerClient.CreateWorkerLed(c.Context, c.flagWorkerGeneratedAuthToken, c.FlagScopeId, opts...)
}
return origResult, origError
}

@ -0,0 +1,244 @@
// Code generated by "make cli"; DO NOT EDIT.
package workerscmd
import (
"errors"
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/workers"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initWorkerLedFlags() {
flagsOnce.Do(func() {
extraFlags := extraWorkerLedActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsWorkerLedMap[k] = append(flagsWorkerLedMap[k], v...)
}
})
}
var (
_ cli.Command = (*WorkerLedCommand)(nil)
_ cli.CommandAutocomplete = (*WorkerLedCommand)(nil)
)
type WorkerLedCommand struct {
*base.Command
Func string
plural string
extraWorkerLedCmdVars
}
func (c *WorkerLedCommand) AutocompleteArgs() complete.Predictor {
initWorkerLedFlags()
return complete.PredictAnything
}
func (c *WorkerLedCommand) AutocompleteFlags() complete.Flags {
initWorkerLedFlags()
return c.Flags().Completions()
}
func (c *WorkerLedCommand) Synopsis() string {
if extra := extraWorkerLedSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "worker"
synopsisStr = fmt.Sprintf("%s %s", "worker-led-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *WorkerLedCommand) Help() string {
initWorkerLedFlags()
var helpStr string
helpMap := common.HelpMap("worker")
switch c.Func {
default:
helpStr = c.extraWorkerLedHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsWorkerLedMap = map[string][]string{
"create": {"scope-id", "name", "description"},
}
func (c *WorkerLedCommand) Flags() *base.FlagSets {
if len(flagsWorkerLedMap[c.Func]) == 0 {
return c.FlagSet(base.FlagSetNone)
}
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "worker-led-type worker", flagsWorkerLedMap, c.Func)
extraWorkerLedFlagsFunc(c, set, f)
return set
}
func (c *WorkerLedCommand) Run(args []string) int {
initWorkerLedFlags()
switch c.Func {
case "":
return cli.RunResultHelp
case "update":
return cli.RunResultHelp
}
c.plural = "worker-led-type worker"
switch c.Func {
case "list":
c.plural = "worker-led-type workers"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
if strutil.StrListContains(flagsWorkerLedMap[c.Func], "id") && c.FlagId == "" {
c.PrintCliError(errors.New("ID is required but not passed in via -id"))
return base.CommandUserError
}
var opts []workers.Option
if strutil.StrListContains(flagsWorkerLedMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.PrintCliError(errors.New("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID"))
return base.CommandUserError
}
}
}
client, err := c.Client()
if c.WrapperCleanupFunc != nil {
defer func() {
if err := c.WrapperCleanupFunc(); err != nil {
c.PrintCliError(fmt.Errorf("Error cleaning kms wrapper: %w", err))
}
}()
}
if err != nil {
c.PrintCliError(fmt.Errorf("Error creating API client: %w", err))
return base.CommandCliError
}
workersClient := workers.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, workers.DefaultName())
default:
opts = append(opts, workers.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, workers.DefaultDescription())
default:
opts = append(opts, workers.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, workers.WithRecursive(true))
}
if c.FlagFilter != "" {
opts = append(opts, workers.WithFilter(c.FlagFilter))
}
var version uint32
if ok := extraWorkerLedFlagsHandlingFunc(c, f, &opts); !ok {
return base.CommandUserError
}
var result api.GenericResult
switch c.Func {
}
result, err = executeExtraWorkerLedActions(c, result, err, workersClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
var opts []base.Option
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural), opts...)
return base.CommandApiError
}
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return base.CommandCliError
}
output, err := printCustomWorkerLedActionOutput(c)
if err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
if output {
return base.CommandSuccess
}
switch c.Func {
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(result))
case "json":
if ok := c.PrintJsonItem(result); !ok {
return base.CommandCliError
}
}
return base.CommandSuccess
}
var (
extraWorkerLedActionsFlagsMapFunc = func() map[string][]string { return nil }
extraWorkerLedSynopsisFunc = func(*WorkerLedCommand) string { return "" }
extraWorkerLedFlagsFunc = func(*WorkerLedCommand, *base.FlagSets, *base.FlagSet) {}
extraWorkerLedFlagsHandlingFunc = func(*WorkerLedCommand, *base.FlagSets, *[]workers.Option) bool { return true }
executeExtraWorkerLedActions = func(_ *WorkerLedCommand, inResult api.GenericResult, inErr error, _ *workers.Client, _ uint32, _ []workers.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomWorkerLedActionOutput = func(*WorkerLedCommand) (bool, error) { return false, nil }
)

@ -0,0 +1,314 @@
// Code generated by "make cli"; DO NOT EDIT.
package workerscmd
import (
"errors"
"fmt"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/workers"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initFlags() {
flagsOnce.Do(func() {
extraFlags := extraActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsMap[k] = append(flagsMap[k], v...)
}
})
}
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
plural string
}
func (c *Command) AutocompleteArgs() complete.Predictor {
initFlags()
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
initFlags()
return c.Flags().Completions()
}
func (c *Command) Synopsis() string {
if extra := extraSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "worker"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("worker")
switch c.Func {
case "read":
helpStr = helpMap[c.Func]() + c.Flags().Help()
case "update":
helpStr = helpMap[c.Func]() + c.Flags().Help()
case "delete":
helpStr = helpMap[c.Func]() + c.Flags().Help()
case "list":
helpStr = helpMap[c.Func]() + c.Flags().Help()
default:
helpStr = helpMap["base"]()
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"update": {"id", "name", "description", "version"},
"delete": {"id"},
"list": {"scope-id", "filter", "recursive"},
}
func (c *Command) Flags() *base.FlagSets {
if len(flagsMap[c.Func]) == 0 {
return c.FlagSet(base.FlagSetNone)
}
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "worker", flagsMap, c.Func)
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
switch c.Func {
case "":
return cli.RunResultHelp
case "create":
return cli.RunResultHelp
}
c.plural = "worker"
switch c.Func {
case "list":
c.plural = "workers"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.PrintCliError(errors.New("ID is required but not passed in via -id"))
return base.CommandUserError
}
var opts []workers.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "list":
if c.FlagScopeId == "" {
c.PrintCliError(errors.New("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID"))
return base.CommandUserError
}
}
}
client, err := c.Client()
if c.WrapperCleanupFunc != nil {
defer func() {
if err := c.WrapperCleanupFunc(); err != nil {
c.PrintCliError(fmt.Errorf("Error cleaning kms wrapper: %w", err))
}
}()
}
if err != nil {
c.PrintCliError(fmt.Errorf("Error creating API client: %w", err))
return base.CommandCliError
}
workersClient := workers.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, workers.DefaultName())
default:
opts = append(opts, workers.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, workers.DefaultDescription())
default:
opts = append(opts, workers.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, workers.WithRecursive(true))
}
if c.FlagFilter != "" {
opts = append(opts, workers.WithFilter(c.FlagFilter))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, workers.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ok := extraFlagsHandlingFunc(c, f, &opts); !ok {
return base.CommandUserError
}
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = workersClient.Read(c.Context, c.FlagId, opts...)
case "update":
result, err = workersClient.Update(c.Context, c.FlagId, version, opts...)
case "delete":
result, err = workersClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listResult, err = workersClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, workersClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
var opts []base.Option
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural), opts...)
return base.CommandApiError
}
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return base.CommandCliError
}
output, err := printCustomActionOutput(c)
if err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
if output {
return base.CommandSuccess
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
if ok := c.PrintJsonItem(result); !ok {
return base.CommandCliError
}
case "table":
c.UI.Output("The delete operation completed successfully.")
}
return base.CommandSuccess
case "list":
switch base.Format(c.UI) {
case "json":
if ok := c.PrintJsonItems(listResult); !ok {
return base.CommandCliError
}
case "table":
listedItems := listResult.GetItems().([]*workers.Worker)
c.UI.Output(c.printListTable(listedItems))
}
return base.CommandSuccess
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(result))
case "json":
if ok := c.PrintJsonItem(result); !ok {
return base.CommandCliError
}
}
return base.CommandSuccess
}
var (
flagsOnce = new(sync.Once)
extraActionsFlagsMapFunc = func() map[string][]string { return nil }
extraSynopsisFunc = func(*Command) string { return "" }
extraFlagsFunc = func(*Command, *base.FlagSets, *base.FlagSet) {}
extraFlagsHandlingFunc = func(*Command, *base.FlagSets, *[]workers.Option) bool { return true }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *workers.Client, _ uint32, _ []workers.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)

@ -30,10 +30,6 @@ type cmdInfo struct {
// output env var and print
HasExampleCliOutput bool
// IsAbstractType triggers some behavior specialized for abstract types,
// e.g. those that have subcommands for create/update
IsAbstractType bool
// HasId controls whether to add ID emptiness checking. Note that some
// commands that allow name/scope id or name/scope name handling may skip
// this in favor of custom logic.
@ -79,6 +75,10 @@ type cmdInfo struct {
// IsPluginType controls whether standard plugin flags are generated
IsPluginType bool
// SkipClientCallActions allows skipping creation of an actual client
// call for an action in favor of custom logic in extra actions
SkipClientCallActions []string
}
var inputStructs = map[string][]*cmdInfo{
@ -89,7 +89,6 @@ var inputStructs = map[string][]*cmdInfo{
StdActions: []string{"read", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
IsAbstractType: true,
Container: "AuthMethod",
HasId: true,
HasName: true,
@ -130,7 +129,6 @@ var inputStructs = map[string][]*cmdInfo{
ResourceType: resource.AuthMethod.String(),
Pkg: "authmethods",
StdActions: []string{"read", "delete", "list"},
IsAbstractType: true,
HasExtraHelpFunc: true,
Container: "Scope",
HasId: true,
@ -179,7 +177,6 @@ var inputStructs = map[string][]*cmdInfo{
ResourceType: resource.CredentialStore.String(),
Pkg: "credentialstores",
StdActions: []string{"read", "delete", "list"},
IsAbstractType: true,
HasExtraHelpFunc: true,
Container: "Scope",
HasId: true,
@ -206,7 +203,6 @@ var inputStructs = map[string][]*cmdInfo{
ResourceType: resource.CredentialLibrary.String(),
Pkg: "credentiallibraries",
StdActions: []string{"read", "delete", "list"},
IsAbstractType: true,
HasExtraHelpFunc: true,
Container: "CredentialStore",
HasId: true,
@ -246,7 +242,6 @@ var inputStructs = map[string][]*cmdInfo{
ResourceType: resource.HostCatalog.String(),
Pkg: "hostcatalogs",
StdActions: []string{"read", "delete", "list"},
IsAbstractType: true,
HasExtraHelpFunc: true,
Container: "Scope",
HasId: true,
@ -290,7 +285,6 @@ var inputStructs = map[string][]*cmdInfo{
StdActions: []string{"read", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
IsAbstractType: true,
Container: "HostCatalog",
HasId: true,
HasName: true,
@ -332,7 +326,6 @@ var inputStructs = map[string][]*cmdInfo{
Pkg: "hosts",
StdActions: []string{"read", "delete", "list"},
HasExtraHelpFunc: true,
IsAbstractType: true,
Container: "HostCatalog",
HasId: true,
HasName: true,
@ -358,7 +351,6 @@ var inputStructs = map[string][]*cmdInfo{
ResourceType: resource.ManagedGroup.String(),
Pkg: "managedgroups",
StdActions: []string{"read", "delete", "list"},
IsAbstractType: true,
Container: "AuthMethod",
HasId: true,
HasName: true,
@ -425,7 +417,6 @@ var inputStructs = map[string][]*cmdInfo{
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
HasExampleCliOutput: true,
IsAbstractType: true,
HasName: true,
HasDescription: true,
Container: "Scope",
@ -461,4 +452,31 @@ var inputStructs = map[string][]*cmdInfo{
VersionedActions: []string{"update", "add-accounts", "remove-accounts", "set-accounts"},
},
},
"workers": {
{
ResourceType: resource.Worker.String(),
Pkg: "workers",
StdActions: []string{"read", "update", "delete", "list"},
HasId: true,
Container: "Scope",
HasName: true,
HasDescription: true,
VersionedActions: []string{"update"},
},
{
ResourceType: resource.Worker.String(),
Pkg: "workers",
StdActions: []string{"create"},
SubActionPrefix: "worker-led",
HasExtraCommandVars: true,
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
Container: "Scope",
HasDescription: true,
NeedsSubtypeInCreate: true,
SkipClientCallActions: []string{"create"},
},
},
}

@ -229,8 +229,12 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Run(args []string) int {
switch c.Func {
case "":
return cli.RunResultHelp
{{ if .IsAbstractType }}
case "create", "update":
{{ if (not (hasAction .StdActions "create" ) )}}
case "create":
return cli.RunResultHelp
{{ end }}
{{ if (not (hasAction .StdActions "update" ) )}}
case "update":
return cli.RunResultHelp
{{ end }}
}
@ -403,9 +407,11 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Run(args []string) int {
switch c.Func {
{{ range $i, $action := $input.StdActions }}
{{ if eq $action "create" }}
{{ if ( not ( hasAction $input.SkipClientCallActions "create") ) }}
case "create":
result, err = {{ $input.Pkg }}Client.Create(c.Context, {{ if (and $input.SubActionPrefix $input.NeedsSubtypeInCreate) }}"{{ $input.SubActionPrefix }}",{{ end }} c.Flag{{ $input.Container }}Id, opts...)
{{ end }}
{{ end }}
{{ if eq $action "read" }}
case "read":
result, err = {{ $input.Pkg }}Client.Read(c.Context, c.FlagId, opts...)

Loading…
Cancel
Save