CLI Generation (#953)

This commit is contained in:
Jeff Mitchell authored and GitHub committed 2021-02-23 19:06:39 -05:00
1 parent 282bbe619e
commit 341e7aff0d
77 files changed
+10303 -6861

No files matched your search

+5 -2
View File
@@ -15,6 +15,9 @@ export GEN_BASEPATH := $(shell pwd)
api:
$(MAKE) --environment-overrides -C internal/api/genapi api
cli:
$(MAKE) --environment-overrides -C internal/cmd/gencli cli
tools:
go generate -tags tools tools/tools.go
@@ -74,7 +77,7 @@ endif
perms-table:
@go run internal/website/permstable/permstable.go
gen: cleangen proto api migrations perms-table fmt
gen: cleangen proto api cli migrations perms-table fmt
migrations:
$(MAKE) --environment-overrides -C internal/db/schema/migrations/generate migrations
@@ -182,7 +185,7 @@ docker-publish:
docker push $(IMAGE_TAG)
docker push hashicorp/boundary:latest
.PHONY: api tools gen migrations proto website ci-config ci-verify set-ui-version docker docker-build docker-build-dev docker-publish
.PHONY: api cli tools gen migrations proto website ci-config ci-verify set-ui-version docker docker-build docker-build-dev docker-publish
.NOTPARALLEL:
+113 -113
View File
@@ -6,24 +6,24 @@ import (
"syscall"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/commands/accounts"
"github.com/hashicorp/boundary/internal/cmd/commands/accountscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/authenticate"
"github.com/hashicorp/boundary/internal/cmd/commands/authmethods"
"github.com/hashicorp/boundary/internal/cmd/commands/authtokens"
"github.com/hashicorp/boundary/internal/cmd/commands/authmethodscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/authtokenscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/config"
"github.com/hashicorp/boundary/internal/cmd/commands/connect"
"github.com/hashicorp/boundary/internal/cmd/commands/database"
"github.com/hashicorp/boundary/internal/cmd/commands/dev"
"github.com/hashicorp/boundary/internal/cmd/commands/groups"
"github.com/hashicorp/boundary/internal/cmd/commands/hostcatalogs"
"github.com/hashicorp/boundary/internal/cmd/commands/hosts"
"github.com/hashicorp/boundary/internal/cmd/commands/hostsets"
"github.com/hashicorp/boundary/internal/cmd/commands/roles"
"github.com/hashicorp/boundary/internal/cmd/commands/scopes"
"github.com/hashicorp/boundary/internal/cmd/commands/groupscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/hostcatalogscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/hostscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/hostsetscmd"
"github.com/hashicorp/boundary/internal/cmd/commands/rolescmd"
"github.com/hashicorp/boundary/internal/cmd/commands/scopescmd"
"github.com/hashicorp/boundary/internal/cmd/commands/server"
"github.com/hashicorp/boundary/internal/cmd/commands/sessions"
"github.com/hashicorp/boundary/internal/cmd/commands/targets"
"github.com/hashicorp/boundary/internal/cmd/commands/users"
"github.com/hashicorp/boundary/internal/cmd/commands/sessionscmd"
"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/mitchellh/cli"
@@ -66,132 +66,132 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
},
"accounts": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"accounts read": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"accounts delete": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"accounts list": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"accounts set-password": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
Func: "set-password",
}, nil
},
"accounts change-password": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
Func: "change-password",
}, nil
},
"accounts create": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"accounts create password": func() (cli.Command, error) {
return &accounts.PasswordCommand{
return &accountscmd.PasswordCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"accounts update": func() (cli.Command, error) {
return &accounts.Command{
return &accountscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"accounts update password": func() (cli.Command, error) {
return &accounts.PasswordCommand{
return &accountscmd.PasswordCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"auth-methods": func() (cli.Command, error) {
return &authmethods.Command{
return &authmethodscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"auth-methods read": func() (cli.Command, error) {
return &authmethods.Command{
return &authmethodscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"auth-methods delete": func() (cli.Command, error) {
return &authmethods.Command{
return &authmethodscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"auth-methods list": func() (cli.Command, error) {
return &authmethods.Command{
return &authmethodscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"auth-methods create": func() (cli.Command, error) {
return &authmethods.Command{
return &authmethodscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"auth-methods create password": func() (cli.Command, error) {
return &authmethods.PasswordCommand{
return &authmethodscmd.PasswordCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"auth-methods update": func() (cli.Command, error) {
return &authmethods.Command{
return &authmethodscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"auth-methods update password": func() (cli.Command, error) {
return &authmethods.PasswordCommand{
return &authmethodscmd.PasswordCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"auth-tokens": func() (cli.Command, error) {
return &authtokens.Command{
return &authtokenscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"auth-tokens read": func() (cli.Command, error) {
return &authtokens.Command{
return &authtokenscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"auth-tokens delete": func() (cli.Command, error) {
return &authtokens.Command{
return &authtokenscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"auth-tokens list": func() (cli.Command, error) {
return &authtokens.Command{
return &authtokenscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
@@ -293,474 +293,474 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
},
"groups": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"groups create": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"groups update": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"groups read": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"groups delete": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"groups list": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"groups add-members": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "add-members",
}, nil
},
"groups set-members": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "set-members",
}, nil
},
"groups remove-members": func() (cli.Command, error) {
return &groups.Command{
return &groupscmd.Command{
Command: base.NewCommand(ui),
Func: "remove-members",
}, nil
},
"host-catalogs": func() (cli.Command, error) {
return &hostcatalogs.Command{
return &hostcatalogscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"host-catalogs read": func() (cli.Command, error) {
return &hostcatalogs.Command{
return &hostcatalogscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"host-catalogs delete": func() (cli.Command, error) {
return &hostcatalogs.Command{
return &hostcatalogscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"host-catalogs list": func() (cli.Command, error) {
return &hostcatalogs.Command{
return &hostcatalogscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"host-catalogs create": func() (cli.Command, error) {
return &hostcatalogs.Command{
return &hostcatalogscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"host-catalogs create static": func() (cli.Command, error) {
return &hostcatalogs.StaticCommand{
return &hostcatalogscmd.StaticCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"host-catalogs update": func() (cli.Command, error) {
return &hostcatalogs.Command{
return &hostcatalogscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"host-catalogs update static": func() (cli.Command, error) {
return &hostcatalogs.StaticCommand{
return &hostcatalogscmd.StaticCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"host-sets": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"host-sets read": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"host-sets delete": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"host-sets list": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"host-sets create": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"host-sets create static": func() (cli.Command, error) {
return &hostsets.StaticCommand{
return &hostsetscmd.StaticCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"host-sets update": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"host-sets update static": func() (cli.Command, error) {
return &hostsets.StaticCommand{
return &hostsetscmd.StaticCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"host-sets add-hosts": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "add-hosts",
}, nil
},
"host-sets remove-hosts": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "remove-hosts",
}, nil
},
"host-sets set-hosts": func() (cli.Command, error) {
return &hostsets.Command{
return &hostsetscmd.Command{
Command: base.NewCommand(ui),
Func: "set-hosts",
}, nil
},
"hosts": func() (cli.Command, error) {
return &hosts.Command{
return &hostscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"hosts read": func() (cli.Command, error) {
return &hosts.Command{
return &hostscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"hosts delete": func() (cli.Command, error) {
return &hosts.Command{
return &hostscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"hosts list": func() (cli.Command, error) {
return &hosts.Command{
return &hostscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"hosts create": func() (cli.Command, error) {
return &hosts.Command{
return &hostscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"hosts create static": func() (cli.Command, error) {
return &hosts.StaticCommand{
return &hostscmd.StaticCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"hosts update": func() (cli.Command, error) {
return &hosts.Command{
return &hostscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"hosts update static": func() (cli.Command, error) {
return &hosts.StaticCommand{
return &hostscmd.StaticCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"roles": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"roles create": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"roles update": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"roles read": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"roles delete": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"roles list": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"roles add-principals": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "add-principals",
}, nil
},
"roles set-principals": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "set-principals",
}, nil
},
"roles remove-principals": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "remove-principals",
}, nil
},
"roles add-grants": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "add-grants",
}, nil
},
"roles set-grants": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "set-grants",
}, nil
},
"roles remove-grants": func() (cli.Command, error) {
return &roles.Command{
return &rolescmd.Command{
Command: base.NewCommand(ui),
Func: "remove-grants",
}, nil
},
"scopes": func() (cli.Command, error) {
return &scopes.Command{
return &scopescmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"scopes create": func() (cli.Command, error) {
return &scopes.Command{
return &scopescmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"scopes read": func() (cli.Command, error) {
return &scopes.Command{
return &scopescmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"scopes update": func() (cli.Command, error) {
return &scopes.Command{
return &scopescmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"scopes delete": func() (cli.Command, error) {
return &scopes.Command{
return &scopescmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"scopes list": func() (cli.Command, error) {
return &scopes.Command{
return &scopescmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"sessions": func() (cli.Command, error) {
return &sessions.Command{
return &sessionscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"sessions read": func() (cli.Command, error) {
return &sessions.Command{
return &sessionscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"sessions list": func() (cli.Command, error) {
return &sessions.Command{
return &sessionscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"sessions cancel": func() (cli.Command, error) {
return &sessions.Command{
return &sessionscmd.Command{
Command: base.NewCommand(ui),
Func: "cancel",
}, nil
},
"targets": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"targets authorize-session": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "authorize-session",
}, nil
},
"targets read": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"targets delete": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"targets list": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"targets create": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"targets create tcp": func() (cli.Command, error) {
return &targets.TcpCommand{
return &targetscmd.TcpCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"targets update": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"targets update tcp": func() (cli.Command, error) {
return &targets.TcpCommand{
return &targetscmd.TcpCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"targets add-host-sets": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "add-host-sets",
}, nil
},
"targets remove-host-sets": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "remove-host-sets",
}, nil
},
"targets set-host-sets": func() (cli.Command, error) {
return &targets.Command{
return &targetscmd.Command{
Command: base.NewCommand(ui),
Func: "set-host-sets",
}, nil
},
"users": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
}, nil
},
"users create": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"users read": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"users update": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"users delete": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"users list": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"users add-accounts": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "add-accounts",
}, nil
},
"users set-accounts": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "set-accounts",
}, nil
},
"users remove-accounts": func() (cli.Command, error) {
return &users.Command{
return &userscmd.Command{
Command: base.NewCommand(ui),
Func: "remove-accounts",
}, nil
-407
View File
@@ -1,407 +0,0 @@
package accounts
import (
"fmt"
"net/http"
"os"
"strings"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/hashicorp/vault/sdk/helper/password"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
flagPassword string
flagCurrentPassword string
flagNewPassword string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "set-password":
return "Directly set the password on an account resource"
case "change-password":
return "Change the password on an account resource"
default:
return common.SynopsisFunc(c.Func, "account")
}
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"auth-method-id"},
"set-password": {"id", "password", "version"},
"change-password": {"id", "current-password", "new-password", "version"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("account")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary accounts [sub command] [options] [args]",
"",
" This command allows operations on Boundary account resources. Example:",
"",
" Read a account:",
"",
` $ boundary accounts read -id apw_1234567890`,
"",
" Please see the accounts subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary account resources. Example:",
"",
" Create a password-type account:",
"",
` $ boundary accounts create password -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary account resources. Example:",
"",
" Update a password-type account:",
"",
` $ boundary accounts update password -id apw_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "set-password":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts set-password [sub command] [options] [args]",
"",
" This command allows setting the password on account-type resources, if the types match and the operation is allowed by the given account type. Example:",
"",
" Set the password on a password-type account:",
"",
` $ boundary accounts set-password -id apw_1234567890 -password <empty, to be read by stdin>`,
"",
"",
})
case "change-password":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts change-password [sub command] [options] [args]",
"",
" This command allows changing the password (with verification of the current password) on account-type resources, if the types match and the operation is allowed by the given account type. Example:",
"",
" Change the password on a password-type account:",
"",
` $ boundary accounts change-password -id apw_1234567890 -current-password <empty, to be read by stdin> -new-password <empty, to be read by stdin>`,
"",
"",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
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, resource.Account.String(), flagsMap[c.Func])
for _, name := range flagsMap[c.Func] {
switch name {
case "password":
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
Usage: "The password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
case "current-password":
f.StringVar(&base.StringVar{
Name: "current-password",
Target: &c.flagCurrentPassword,
Usage: "The current password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
case "new-password":
f.StringVar(&base.StringVar{
Name: "new-password",
Target: &c.flagNewPassword,
Usage: "The new password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
}
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "auth-method-id") && c.FlagAuthMethodId == "" {
c.UI.Error("Auth Method ID must be passed in via -auth-method-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []accounts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, accounts.DefaultName())
default:
opts = append(opts, accounts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, accounts.DefaultDescription())
default:
opts = append(opts, accounts.WithDescription(c.FlagDescription))
}
if strutil.StrListContains(flagsMap[c.Func], "password") && c.flagPassword == "" {
fmt.Print("Password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
fmt.Print("Please enter it one more time for confirmation: ")
confirmation, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
if strings.TrimSpace(value) != strings.TrimSpace(confirmation) {
c.UI.Error("Entered password and confirmation value did not match.")
return 2
}
c.flagPassword = strings.TrimSpace(value)
}
if strutil.StrListContains(flagsMap[c.Func], "current-password") && c.flagCurrentPassword == "" {
fmt.Print("Current password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
c.flagCurrentPassword = strings.TrimSpace(value)
}
if strutil.StrListContains(flagsMap[c.Func], "new-password") && c.flagNewPassword == "" {
fmt.Print("New password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
fmt.Print("Please enter it one more time for confirmation: ")
confirmation, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
if strings.TrimSpace(value) != strings.TrimSpace(confirmation) {
c.UI.Error("Entered password and confirmation value did not match.")
return 2
}
c.flagNewPassword = strings.TrimSpace(value)
}
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, accounts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
accountClient := accounts.NewClient(client)
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = accountClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = accountClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = accountClient.List(c.Context, c.FlagAuthMethodId, opts...)
case "set-password":
result, err = accountClient.SetPassword(c.Context, c.FlagId, c.flagPassword, version, opts...)
case "change-password":
result, err = accountClient.ChangePassword(c.Context, c.FlagId, c.flagCurrentPassword, c.flagNewPassword, version, opts...)
}
plural := "account"
if c.Func == "list" {
plural = "accounts"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
accounts := listResult.GetItems().([]*accounts.Account)
switch base.Format(c.UI) {
case "json":
if len(accounts) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(accounts)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(accounts) == 0 {
c.UI.Output("No accounts found")
return 0
}
var output []string
output = []string{
"",
"Account information:",
}
for i, m := range accounts {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
account := result.GetItem().(*accounts.Account)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAccountTableOutput(account))
case "json":
b, err := base.JsonFormatter{}.Format(account)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
-59
View File
@@ -1,59 +0,0 @@
package accounts
import (
"time"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateAccountTableOutput(in *accounts.Account) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Auth Method ID": in.AuthMethodId,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Account information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{
"login_name": "Login Name",
}
-241
View File
@@ -1,241 +0,0 @@
package accounts
import (
"fmt"
"net/textproto"
"os"
"strings"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/hashicorp/vault/sdk/helper/password"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*PasswordCommand)(nil)
_ cli.CommandAutocomplete = (*PasswordCommand)(nil)
)
type PasswordCommand struct {
*base.Command
Func string
flagLoginName string
flagPassword string
}
func (c *PasswordCommand) Synopsis() string {
return fmt.Sprintf("%s a password-type account", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var passwordFlagsMap = map[string][]string{
"create": {"auth-method-id", "name", "description", "login-name", "password"},
"update": {"id", "name", "description", "version", "login-name"},
}
func (c *PasswordCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary accounts create password [options] [args]",
"",
" Create a password-type account. Example:",
"",
` $ boundary accounts create password -login-name prodops -description "Password account for ProdOps"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary accounts update password [options] [args]",
"",
" Update a password-type account given its ID. Example:",
"",
` $ boundary accounts update password -id apw_1234567890 -name "devops" -description "Password account for DevOps"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *PasswordCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
if len(passwordFlagsMap[c.Func]) > 0 {
common.PopulateCommonFlags(c.Command, f, "password-type account", passwordFlagsMap[c.Func])
}
f = set.NewFlagSet("Password Account Options")
for _, name := range passwordFlagsMap[c.Func] {
switch name {
case "login-name":
f.StringVar(&base.StringVar{
Name: "login-name",
Target: &c.flagLoginName,
Usage: "The login name for the account",
})
case "password":
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
Usage: "The password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
}
}
return set
}
func (c *PasswordCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *PasswordCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *PasswordCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "auth-method-id") && c.FlagAuthMethodId == "" {
c.UI.Error("Auth Method ID must be passed in via -auth-method-id")
return 1
}
if c.Func == "create" && c.flagLoginName == "" {
c.UI.Error("Login Name must be passed in via -login-name")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []accounts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, accounts.DefaultName())
default:
opts = append(opts, accounts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, accounts.DefaultDescription())
default:
opts = append(opts, accounts.WithDescription(c.FlagDescription))
}
switch c.flagLoginName {
case "":
case "null":
opts = append(opts, accounts.DefaultPasswordAccountLoginName())
default:
opts = append(opts, accounts.WithPasswordAccountLoginName(c.flagLoginName))
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "password") {
switch c.flagPassword {
case "":
fmt.Print("Password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
fmt.Print("Please enter it one more time for confirmation: ")
confirmation, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
if strings.TrimSpace(value) != strings.TrimSpace(confirmation) {
c.UI.Error("Entered password and confirmation value did not match.")
return 2
}
opts = append(opts, accounts.WithPasswordAccountPassword(strings.TrimSpace(value)))
default:
opts = append(opts, accounts.WithPasswordAccountPassword(c.flagPassword))
}
}
accountClient := accounts.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, accounts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = accountClient.Create(c.Context, c.FlagAuthMethodId, opts...)
case "update":
result, err = accountClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "password-type account"
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
account := result.GetItem().(*accounts.Account)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAccountTableOutput(account))
case "json":
b, err := base.JsonFormatter{}.Format(account)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
@@ -0,0 +1,321 @@
// Code generated by "make api"; DO NOT EDIT.
package accountscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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
extraCmdVars
}
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 := "account"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("account")
switch c.Func {
case "read":
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"auth-method-id"},
}
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, "account", 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", "update":
return cli.RunResultHelp
}
c.plural = "account"
switch c.Func {
case "list":
c.plural = "accounts"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []accounts.Option
if strutil.StrListContains(flagsMap[c.Func], "auth-method-id") {
switch c.Func {
case "list":
if c.FlagAuthMethodId == "" {
c.UI.Error("AuthMethod ID must be passed in via -auth-method-id or BOUNDARY_AUTH_METHOD_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
accountsClient := accounts.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, accounts.DefaultName())
default:
opts = append(opts, accounts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, accounts.DefaultDescription())
default:
opts = append(opts, accounts.WithDescription(c.FlagDescription))
}
var version uint32
switch c.Func {
case "change-password":
switch c.FlagVersion {
case 0:
opts = append(opts, accounts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-password":
switch c.FlagVersion {
case 0:
opts = append(opts, accounts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = accountsClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = accountsClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = accountsClient.List(c.Context, c.FlagAuthMethodId, opts...)
}
result, err = executeExtraActions(c, result, err, accountsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*accounts.Account)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*accounts.Account)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]accounts.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *accounts.Client, _ uint32, _ []accounts.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
+277
View File
@@ -0,0 +1,277 @@
package accountscmd
import (
"fmt"
"os"
"strings"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/hashicorp/vault/sdk/helper/password"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
}
type extraCmdVars struct {
flagPassword string
flagCurrentPassword string
flagNewPassword string
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"change-password": {"id", "current-password", "new-password", "version"},
"set-password": {"id", "password", "version"},
}
}
func extraSynopsisFuncImpl(c *Command) string {
switch c.Func {
case "change-password":
return "Change the password on an account resource"
case "set-password":
return "Directly set the password on an account resource"
default:
return ""
}
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary accounts [sub command] [options] [args]",
"",
" This command allows operations on Boundary account resources. Example:",
"",
" Read a account:",
"",
` $ boundary accounts read -id apw_1234567890`,
"",
" Please see the accounts subcommand help for detailed usage information.",
})
case "change-password":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts change-password [options] [args]",
"",
" This command allows changing the password (with verification of the current password) on account-type resources, if the types match and the operation is allowed by the given account type. Example:",
"",
" Change the password on a password-type account:",
"",
` $ boundary accounts change-password -id apw_1234567890 -current-password <empty, to be read by stdin> -new-password <empty, to be read by stdin>`,
"",
"",
})
case "set-password":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts set-password [options] [args]",
"",
" This command allows setting the password on account-type resources, if the types match and the operation is allowed by the given account type. Example:",
"",
" Set the password on a password-type account:",
"",
` $ boundary accounts set-password -id apw_1234567890 -password <empty, to be read by stdin>`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "password":
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
Usage: "The password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
case "current-password":
f.StringVar(&base.StringVar{
Name: "current-password",
Target: &c.flagCurrentPassword,
Usage: "The current password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
case "new-password":
f.StringVar(&base.StringVar{
Name: "new-password",
Target: &c.flagNewPassword,
Usage: "The new password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
}
}
}
func extraFlagsHandlingFuncImpl(c *Command, opts *[]accounts.Option) int {
if strutil.StrListContains(flagsMap[c.Func], "password") && c.flagPassword == "" {
fmt.Print("Password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
fmt.Print("Please enter it one more time for confirmation: ")
confirmation, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
if strings.TrimSpace(value) != strings.TrimSpace(confirmation) {
c.UI.Error("Entered password and confirmation value did not match.")
return 2
}
c.flagPassword = strings.TrimSpace(value)
}
if strutil.StrListContains(flagsMap[c.Func], "current-password") && c.flagCurrentPassword == "" {
fmt.Print("Current password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
fmt.Print("Please enter it one more time for confirmation: ")
confirmation, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
if strings.TrimSpace(value) != strings.TrimSpace(confirmation) {
c.UI.Error("Entered password and confirmation value did not match.")
return 2
}
c.flagCurrentPassword = strings.TrimSpace(value)
}
if strutil.StrListContains(flagsMap[c.Func], "new-password") && c.flagNewPassword == "" {
fmt.Print("New password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
c.flagNewPassword = strings.TrimSpace(value)
}
return 0
}
func executeExtraActionsImpl(c *Command, origResult api.GenericResult, origError error, accountClient *accounts.Client, version uint32, opts []accounts.Option) (api.GenericResult, error) {
switch c.Func {
case "set-password":
return accountClient.SetPassword(c.Context, c.FlagId, c.flagPassword, version, opts...)
case "change-password":
return accountClient.ChangePassword(c.Context, c.FlagId, c.flagCurrentPassword, c.flagNewPassword, version, opts...)
}
return origResult, origError
}
func (c *Command) printListTable(items []*accounts.Account) string {
if len(items) == 0 {
return "No accounts found"
}
var output []string
output = []string{
"",
"Account information:",
}
for i, m := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(item *accounts.Account) string {
nonAttributeMap := map[string]interface{}{
"ID": item.Id,
"Version": item.Version,
"Type": item.Type,
"Created Time": item.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": item.UpdatedTime.Local().Format(time.RFC1123),
"Auth Method ID": item.AuthMethodId,
}
if item.Name != "" {
nonAttributeMap["Name"] = item.Name
}
if item.Description != "" {
nonAttributeMap["Description"] = item.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, item.Attributes, keySubstMap)
ret := []string{
"",
"Account information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(item.Scope, maxLength),
}
if len(item.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, item.AuthorizedActions),
)
}
if len(item.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, item.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{
"login_name": "Login Name",
}
@@ -0,0 +1,238 @@
// Code generated by "make api"; DO NOT EDIT.
package accountscmd
import (
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initPasswordFlags() {
flagsOnce.Do(func() {
extraFlags := extraPasswordActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsPasswordMap[k] = append(flagsPasswordMap[k], v...)
}
})
}
var (
_ cli.Command = (*PasswordCommand)(nil)
_ cli.CommandAutocomplete = (*PasswordCommand)(nil)
)
type PasswordCommand struct {
*base.Command
Func string
plural string
extraPasswordCmdVars
}
func (c *PasswordCommand) AutocompleteArgs() complete.Predictor {
initPasswordFlags()
return complete.PredictAnything
}
func (c *PasswordCommand) AutocompleteFlags() complete.Flags {
initPasswordFlags()
return c.Flags().Completions()
}
func (c *PasswordCommand) Synopsis() string {
if extra := extraPasswordSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "account"
synopsisStr = fmt.Sprintf("%s %s", "password-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *PasswordCommand) Help() string {
initPasswordFlags()
var helpStr string
helpMap := common.HelpMap("account")
switch c.Func {
default:
helpStr = c.extraPasswordHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsPasswordMap = map[string][]string{
"create": {"auth-method-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *PasswordCommand) Flags() *base.FlagSets {
if len(flagsPasswordMap[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, "password-type account", flagsPasswordMap[c.Func])
extraPasswordFlagsFunc(c, set, f)
return set
}
func (c *PasswordCommand) Run(args []string) int {
initPasswordFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "password-type account"
switch c.Func {
case "list":
c.plural = "password-type accounts"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsPasswordMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []accounts.Option
if strutil.StrListContains(flagsPasswordMap[c.Func], "auth-method-id") {
switch c.Func {
case "create":
if c.FlagAuthMethodId == "" {
c.UI.Error("AuthMethod ID must be passed in via -auth-method-id or BOUNDARY_AUTH_METHOD_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
accountsClient := accounts.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, accounts.DefaultName())
default:
opts = append(opts, accounts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, accounts.DefaultDescription())
default:
opts = append(opts, accounts.WithDescription(c.FlagDescription))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, accounts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraPasswordFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = accountsClient.Create(c.Context, c.FlagAuthMethodId, opts...)
case "update":
result, err = accountsClient.Update(c.Context, c.FlagId, version, opts...)
}
result, err = executeExtraPasswordActions(c, result, err, accountsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomPasswordActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
}
item := result.GetItem().(*accounts.Account)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
var (
extraPasswordActionsFlagsMapFunc = func() map[string][]string { return nil }
extraPasswordSynopsisFunc = func(*PasswordCommand) string { return "" }
extraPasswordFlagsFunc = func(*PasswordCommand, *base.FlagSets, *base.FlagSet) {}
extraPasswordFlagsHandlingFunc = func(*PasswordCommand, *[]accounts.Option) int { return 0 }
executeExtraPasswordActions = func(_ *PasswordCommand, inResult api.GenericResult, inErr error, _ *accounts.Client, _ uint32, _ []accounts.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomPasswordActionOutput = func(*PasswordCommand) (bool, error) { return false, nil }
)
@@ -0,0 +1,123 @@
package accountscmd
import (
"fmt"
"os"
"strings"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/hashicorp/vault/sdk/helper/password"
)
func init() {
extraPasswordActionsFlagsMapFunc = extraPasswordActionsFlagsMapFuncImpl
extraPasswordFlagsFunc = extraPasswordFlagsFuncImpl
extraPasswordFlagsHandlingFunc = extraPasswordFlagsHandlingFuncImpl
}
func extraPasswordActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"login-name", "password"},
"update": {"login-name"},
}
}
type extraPasswordCmdVars struct {
flagLoginName string
flagPassword string
}
func (c *PasswordCommand) extraPasswordHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts create password [options] [args]",
"",
" Create a password-type account. Example:",
"",
` $ boundary accounts create password -login-name prodops -description "Password account for ProdOps"`,
"",
"",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts update password [options] [args]",
"",
" Update a password-type account given its ID. Example:",
"",
` $ boundary accounts update password -id apw_1234567890 -name "devops" -description "Password account for DevOps"`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func extraPasswordFlagsFuncImpl(c *PasswordCommand, set *base.FlagSets, f *base.FlagSet) {
f = set.NewFlagSet("Password Account Options")
for _, name := range flagsPasswordMap[c.Func] {
switch name {
case "login-name":
f.StringVar(&base.StringVar{
Name: "login-name",
Target: &c.flagLoginName,
Usage: "The login name for the account",
})
case "password":
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
Usage: "The password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
}
}
}
func extraPasswordFlagsHandlingFuncImpl(c *PasswordCommand, opts *[]accounts.Option) int {
if c.Func == "create" && c.flagLoginName == "" {
c.UI.Error("Login Name must be passed in via -login-name")
return 1
}
switch c.flagLoginName {
case "":
case "null":
*opts = append(*opts, accounts.DefaultPasswordAccountLoginName())
default:
*opts = append(*opts, accounts.WithPasswordAccountLoginName(c.flagLoginName))
}
if strutil.StrListContains(flagsPasswordMap[c.Func], "password") {
switch c.flagPassword {
case "":
fmt.Print("Password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
fmt.Print("Please enter it one more time for confirmation: ")
confirmation, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
if strings.TrimSpace(value) != strings.TrimSpace(confirmation) {
c.UI.Error("Entered password and confirmation value did not match.")
return 2
}
*opts = append(*opts, accounts.WithPasswordAccountPassword(strings.TrimSpace(value)))
default:
*opts = append(*opts, accounts.WithPasswordAccountPassword(c.flagPassword))
}
}
return 0
}
@@ -1,288 +0,0 @@
package authmethods
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
}
func (c *Command) Synopsis() string {
return common.SynopsisFunc(c.Func, "auth method")
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("auth method")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary auth-methods [sub command] [options] [args]",
"",
" This command allows operations on Boundary auth method resources. Example:",
"",
" Read an auth method:",
"",
` $ boundary auth-methods read -id ampw_1234567890`,
"",
" Please see the auth-methods subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary auth method resources. Example:",
"",
" Create a password-type auth method:",
"",
` $ boundary auth-methods create password -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary auth method resources. Example:",
"",
" Update a password-type auth method:",
"",
` $ boundary auth-methods update password -id ampw_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
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, resource.AuthMethod.String(), flagsMap[c.Func])
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []authmethods.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, authmethods.DefaultName())
default:
opts = append(opts, authmethods.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, authmethods.DefaultDescription())
default:
opts = append(opts, authmethods.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, authmethods.WithRecursive(true))
}
authmethodClient := authmethods.NewClient(client)
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = authmethodClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = authmethodClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = authmethodClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "auth method"
if c.Func == "list" {
plural = "auth methods"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedMethods := listResult.GetItems().([]*authmethods.AuthMethod)
switch base.Format(c.UI) {
case "json":
if len(listedMethods) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedMethods)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedMethods) == 0 {
c.UI.Output("No auth methods found")
return 0
}
var output []string
output = []string{
"",
"Auth Method information:",
}
for i, m := range listedMethods {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", m.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", m.Version),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if true {
output = append(output,
fmt.Sprintf(" Type: %s", m.Type),
fmt.Sprintf(" Version: %d", m.Version),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
method := result.GetItem().(*authmethods.AuthMethod)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAuthMethodTableOutput(method))
case "json":
b, err := base.JsonFormatter{}.Format(method)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
@@ -1,92 +0,0 @@
package authmethods
import (
"fmt"
"sort"
"time"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func addPasswordFlags(c *PasswordCommand, f *base.FlagSet) {
f.StringVar(&base.StringVar{
Name: "min-login-name-length",
Target: &c.flagMinLoginNameLength,
Usage: "The minimum length of login names",
})
f.StringVar(&base.StringVar{
Name: "min-password-length",
Target: &c.flagMinPasswordLength,
Usage: "The minimum length of passwords",
})
}
func generateAuthMethodTableOutput(in *authmethods.AuthMethod) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Auth Method information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.AuthorizedCollectionActions) > 0 {
keys := make([]string, 0, len(in.AuthorizedCollectionActions))
for k := range in.AuthorizedCollectionActions {
keys = append(keys, k)
}
sort.Strings(keys)
ret = append(ret,
"",
" Authorized Actions on Auth Method's Collections:",
)
for _, key := range keys {
ret = append(ret,
fmt.Sprintf(" %ss:", key),
base.WrapSlice(6, in.AuthorizedCollectionActions[key]),
)
}
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{
"min_login_name_length": "Minimum Login Name Length",
"min_password_length": "Minimum Password Length",
}
@@ -1,219 +0,0 @@
package authmethods
import (
"fmt"
"net/textproto"
"strconv"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*PasswordCommand)(nil)
_ cli.CommandAutocomplete = (*PasswordCommand)(nil)
)
type PasswordCommand struct {
*base.Command
Func string
flagMinLoginNameLength string
flagMinPasswordLength string
}
func (c *PasswordCommand) Synopsis() string {
return fmt.Sprintf("%s a password type auth-method", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var passwordFlagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *PasswordCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary auth-methods create password [options] [args]",
"",
" Create a password-type auth method. Example:",
"",
` $ boundary auth-methods create password -name prodops -description "Password auth-method for ProdOps"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary auth-methods update password [options] [args]",
"",
" Update a password-type auth method given its ID. Example:",
"",
` $ boundary auth-methods update password -id ampw_1234567890 -name "devops" -description "Password auth-method for DevOps"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *PasswordCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "password-type auth method", passwordFlagsMap[c.Func])
f = set.NewFlagSet("Password Auth-Method Options")
addPasswordFlags(c, f)
return set
}
func (c *PasswordCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *PasswordCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *PasswordCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []authmethods.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, authmethods.DefaultName())
default:
opts = append(opts, authmethods.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, authmethods.DefaultDescription())
default:
opts = append(opts, authmethods.WithDescription(c.FlagDescription))
}
var attributes map[string]interface{}
addAttribute := func(name string, value interface{}) {
if attributes == nil {
attributes = make(map[string]interface{})
}
attributes[name] = value
}
switch c.flagMinLoginNameLength {
case "":
case "null":
addAttribute("min_login_name_length", nil)
default:
length, err := strconv.ParseUint(c.flagMinLoginNameLength, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagMinLoginNameLength, err))
return 1
}
addAttribute("min_login_name_length", uint32(length))
}
switch c.flagMinPasswordLength {
case "":
case "null":
addAttribute("min_password_length", nil)
default:
length, err := strconv.ParseUint(c.flagMinPasswordLength, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagMinPasswordLength, err))
return 1
}
addAttribute("min_password_length", uint32(length))
}
if attributes != nil {
opts = append(opts, authmethods.WithAttributes(attributes))
}
authmethodClient := authmethods.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, authmethods.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = authmethodClient.Create(c.Context, "password", c.FlagScopeId, opts...)
case "update":
result, err = authmethodClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "password-type auth-method"
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
method := result.GetItem().(*authmethods.AuthMethod)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAuthMethodTableOutput(method))
case "json":
b, err := base.JsonFormatter{}.Format(method)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
@@ -0,0 +1,288 @@
// Code generated by "make api"; DO NOT EDIT.
package authmethodscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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 := "auth method"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("auth method")
switch c.Func {
case "read":
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "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, "auth method", 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", "update":
return cli.RunResultHelp
}
c.plural = "auth method"
switch c.Func {
case "list":
c.plural = "auth methods"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []authmethods.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
authmethodsClient := authmethods.NewClient(client)
switch c.FlagRecursive {
case true:
opts = append(opts, authmethods.WithRecursive(true))
}
var version uint32
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = authmethodsClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = authmethodsClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = authmethodsClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, authmethodsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*authmethods.AuthMethod)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*authmethods.AuthMethod)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]authmethods.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *authmethods.Client, _ uint32, _ []authmethods.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
@@ -0,0 +1,178 @@
package authmethodscmd
import (
"fmt"
"sort"
"time"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary auth-methods [sub command] [options] [args]",
"",
" This command allows operations on Boundary auth method resources. Example:",
"",
" Read an auth method:",
"",
` $ boundary auth-methods read -id ampw_1234567890`,
"",
" Please see the auth-methods subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary auth method resources. Example:",
"",
" Create a password-type auth method:",
"",
` $ boundary auth-methods create password -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary auth method resources. Example:",
"",
" Update a password-type auth method:",
"",
` $ boundary auth-methods update password -id ampw_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
}
return helpStr + c.Flags().Help()
}
func (c *Command) printListTable(items []*authmethods.AuthMethod) string {
if len(items) == 0 {
return "No auth methods found"
}
var output []string
output = []string{
"",
"Auth Method information:",
}
for i, m := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", m.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", m.Version),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if true {
output = append(output,
fmt.Sprintf(" Type: %s", m.Type),
fmt.Sprintf(" Version: %d", m.Version),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *authmethods.AuthMethod) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Auth Method information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.AuthorizedCollectionActions) > 0 {
keys := make([]string, 0, len(in.AuthorizedCollectionActions))
for k := range in.AuthorizedCollectionActions {
keys = append(keys, k)
}
sort.Strings(keys)
ret = append(ret,
"",
" Authorized Actions on Auth Method's Collections:",
)
for _, key := range keys {
ret = append(ret,
fmt.Sprintf(" %ss:", key),
base.WrapSlice(6, in.AuthorizedCollectionActions[key]),
)
}
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{
"min_login_name_length": "Minimum Login Name Length",
"min_password_length": "Minimum Password Length",
}
@@ -0,0 +1,243 @@
// Code generated by "make api"; DO NOT EDIT.
package authmethodscmd
import (
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initPasswordFlags() {
flagsOnce.Do(func() {
extraFlags := extraPasswordActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsPasswordMap[k] = append(flagsPasswordMap[k], v...)
}
})
}
var (
_ cli.Command = (*PasswordCommand)(nil)
_ cli.CommandAutocomplete = (*PasswordCommand)(nil)
)
type PasswordCommand struct {
*base.Command
Func string
plural string
extraPasswordCmdVars
}
func (c *PasswordCommand) AutocompleteArgs() complete.Predictor {
initPasswordFlags()
return complete.PredictAnything
}
func (c *PasswordCommand) AutocompleteFlags() complete.Flags {
initPasswordFlags()
return c.Flags().Completions()
}
func (c *PasswordCommand) Synopsis() string {
if extra := extraPasswordSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "auth method"
synopsisStr = fmt.Sprintf("%s %s", "password-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *PasswordCommand) Help() string {
initPasswordFlags()
var helpStr string
helpMap := common.HelpMap("auth method")
switch c.Func {
default:
helpStr = c.extraPasswordHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsPasswordMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *PasswordCommand) Flags() *base.FlagSets {
if len(flagsPasswordMap[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, "password-type auth method", flagsPasswordMap[c.Func])
extraPasswordFlagsFunc(c, set, f)
return set
}
func (c *PasswordCommand) Run(args []string) int {
initPasswordFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "password-type auth method"
switch c.Func {
case "list":
c.plural = "password-type auth methods"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsPasswordMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []authmethods.Option
if strutil.StrListContains(flagsPasswordMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
authmethodsClient := authmethods.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, authmethods.DefaultName())
default:
opts = append(opts, authmethods.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, authmethods.DefaultDescription())
default:
opts = append(opts, authmethods.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, authmethods.WithRecursive(true))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, authmethods.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraPasswordFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = authmethodsClient.Create(c.Context, "password", c.FlagScopeId, opts...)
case "update":
result, err = authmethodsClient.Update(c.Context, c.FlagId, version, opts...)
}
result, err = executeExtraPasswordActions(c, result, err, authmethodsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomPasswordActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
}
item := result.GetItem().(*authmethods.AuthMethod)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
var (
extraPasswordActionsFlagsMapFunc = func() map[string][]string { return nil }
extraPasswordSynopsisFunc = func(*PasswordCommand) string { return "" }
extraPasswordFlagsFunc = func(*PasswordCommand, *base.FlagSets, *base.FlagSet) {}
extraPasswordFlagsHandlingFunc = func(*PasswordCommand, *[]authmethods.Option) int { return 0 }
executeExtraPasswordActions = func(_ *PasswordCommand, inResult api.GenericResult, inErr error, _ *authmethods.Client, _ uint32, _ []authmethods.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomPasswordActionOutput = func(*PasswordCommand) (bool, error) { return false, nil }
)
@@ -0,0 +1,117 @@
package authmethodscmd
import (
"fmt"
"strconv"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func init() {
extraPasswordActionsFlagsMapFunc = extraPasswordActionsFlagsMapFuncImpl
extraPasswordFlagsFunc = extraPasswordFlagsFuncImpl
extraPasswordFlagsHandlingFunc = extraPasswordFlagHandlingFuncImpl
}
type extraPasswordCmdVars struct {
flagMinLoginNameLength string
flagMinPasswordLength string
}
func extraPasswordActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"min-login-name-length", "min-password-length"},
"update": {"min-login-name-length", "min-password-length"},
}
}
func (c *PasswordCommand) extraPasswordHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods create password [options] [args]",
"",
" Create a password-type auth method. Example:",
"",
` $ boundary auth-methods create password -name prodops -description "Password auth-method for ProdOps"`,
"",
"",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods update password [options] [args]",
"",
" Update a password-type auth method given its ID. Example:",
"",
` $ boundary auth-methods update password -id ampw_1234567890 -name "devops" -description "Password auth-method for DevOps"`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func extraPasswordFlagsFuncImpl(c *PasswordCommand, set *base.FlagSets, f *base.FlagSet) {
f = set.NewFlagSet("Password Auth Method Options")
for _, name := range flagsPasswordMap[c.Func] {
switch name {
case "min-login-name-length":
f.StringVar(&base.StringVar{
Name: "min-login-name-length",
Target: &c.flagMinLoginNameLength,
Usage: "The minimum length of login names",
})
case "min-password-length":
f.StringVar(&base.StringVar{
Name: "min-password-length",
Target: &c.flagMinPasswordLength,
Usage: "The minimum length of passwords",
})
}
}
}
func extraPasswordFlagHandlingFuncImpl(c *PasswordCommand, opts *[]authmethods.Option) int {
var attributes map[string]interface{}
addAttribute := func(name string, value interface{}) {
if attributes == nil {
attributes = make(map[string]interface{})
}
attributes[name] = value
}
switch c.flagMinLoginNameLength {
case "":
case "null":
addAttribute("min_login_name_length", nil)
default:
length, err := strconv.ParseUint(c.flagMinLoginNameLength, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagMinLoginNameLength, err))
return 1
}
addAttribute("min_login_name_length", uint32(length))
}
switch c.flagMinPasswordLength {
case "":
case "null":
addAttribute("min_password_length", nil)
default:
length, err := strconv.ParseUint(c.flagMinPasswordLength, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagMinPasswordLength, err))
return 1
}
addAttribute("min_password_length", uint32(length))
}
if attributes != nil {
*opts = append(*opts, authmethods.WithAttributes(attributes))
}
return 0
}
@@ -1,224 +0,0 @@
package authtokens
import (
"fmt"
"net/http"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
}
func (c *Command) Synopsis() string {
return common.SynopsisFunc(c.Func, "auth token")
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("auth token")
if c.Func == "" {
return helpMap["base"]()
}
return helpMap[c.Func]() + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
if len(flagsMap[c.Func]) > 0 {
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, resource.AuthToken.String(), flagsMap[c.Func])
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
authtokenClient := authtokens.NewClient(client)
var opts []authtokens.Option
switch c.FlagRecursive {
case true:
opts = append(opts, authtokens.WithRecursive(true))
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = authtokenClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = authtokenClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = authtokenClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "auth token"
if c.Func == "list" {
plural = "auth tokens"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedTokens := listResult.GetItems().([]*authtokens.AuthToken)
switch base.Format(c.UI) {
case "json":
if len(listedTokens) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedTokens)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedTokens) == 0 {
c.UI.Output("No auth tokens found")
return 0
}
var output []string
output = []string{
"",
"Auth Token information:",
}
for i, t := range listedTokens {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", t.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", t.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Approximate Last Used Time: %s", t.ApproximateLastUsedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Auth Method ID: %s", t.AuthMethodId),
fmt.Sprintf(" Created Time: %s", t.CreatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Expiration Time: %s", t.ExpirationTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Updated Time: %s", t.UpdatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" User ID: %s", t.UserId),
)
}
if len(t.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, t.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
token := result.GetItem().(*authtokens.AuthToken)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAuthTokenTableOutput(token))
case "json":
b, err := base.JsonFormatter{}.Format(token)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
-41
View File
@@ -1,41 +0,0 @@
package authtokens
import (
"time"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateAuthTokenTableOutput(in *authtokens.AuthToken) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Auth Method ID": in.AuthMethodId,
"User ID": in.UserId,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Expiration Time": in.ExpirationTime.Local().Format(time.RFC1123),
"Approximate Last Used Time": in.ApproximateLastUsedTime.Local().Format(time.RFC1123),
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Auth Token information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
return base.WrapForHelpText(ret)
}
@@ -0,0 +1,284 @@
// Code generated by "make api"; DO NOT EDIT.
package authtokenscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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 := "auth token"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("auth token")
switch c.Func {
case "read":
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"},
"delete": {"id"},
"list": {"scope-id", "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, "auth token", flagsMap[c.Func])
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "auth token"
switch c.Func {
case "list":
c.plural = "auth tokens"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []authtokens.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
authtokensClient := authtokens.NewClient(client)
switch c.FlagRecursive {
case true:
opts = append(opts, authtokens.WithRecursive(true))
}
var version uint32
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = authtokensClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = authtokensClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = authtokensClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, authtokensClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*authtokens.AuthToken)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*authtokens.AuthToken)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]authtokens.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *authtokens.Client, _ uint32, _ []authtokens.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
@@ -0,0 +1,87 @@
package authtokenscmd
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func (c *Command) printListTable(items []*authtokens.AuthToken) string {
if len(items) == 0 {
return "No auth tokens found"
}
var output []string
output = []string{
"",
"Auth Token information:",
}
for i, t := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", t.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", t.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Approximate Last Used Time: %s", t.ApproximateLastUsedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Auth Method ID: %s", t.AuthMethodId),
fmt.Sprintf(" Created Time: %s", t.CreatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Expiration Time: %s", t.ExpirationTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Updated Time: %s", t.UpdatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" User ID: %s", t.UserId),
)
}
if len(t.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, t.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *authtokens.AuthToken) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Auth Method ID": in.AuthMethodId,
"User ID": in.UserId,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Expiration Time": in.ExpirationTime.Local().Format(time.RFC1123),
"Approximate Last Used Time": in.ApproximateLastUsedTime.Local().Format(time.RFC1123),
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Auth Token information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
return base.WrapForHelpText(ret)
}
-141
View File
@@ -1,141 +0,0 @@
package groups
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api/groups"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/mitchellh/go-wordwrap"
)
func memberSynopsisFunc(inFunc string) string {
var in string
switch {
case strings.HasPrefix(inFunc, "add"):
in = "Add users to"
case strings.HasPrefix(inFunc, "set"):
in = "Set the full contents of the users on"
case strings.HasPrefix(inFunc, "remove"):
in = "Remove users from"
}
return wordwrap.WrapString(fmt.Sprintf("%s a group", in), base.TermWidth)
}
func addMembersHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary groups add-members [options] [args]",
"",
` Adds members (users) to a group given its ID. The "user" flag can be specified multiple times. Example:`,
"",
` $ boundary groups add-members -id g_1234567890 -user u_1234567890`,
"",
"",
})
}
func setMembersHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary groups set-members [options] [args]",
"",
` Sets the complete set of members (users) on a group given its ID. The "user" flag can be specified multiple times. Example:`,
"",
` $ boundary groups set-principals -id g_1234567890 -user u_anon -user u_1234567890`,
"",
"",
})
}
func removeMembersHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary groups remove-members [options] [args]",
"",
` Removes members (users) from a group given its ID. The "user" flag can be specified multiple times. Example:`,
"",
` $ boundary groups remove-members -id g_1234567890 -user u_1234567890`,
"",
"",
})
}
func populateFlags(c *Command, f *base.FlagSet, flagNames []string) {
common.PopulateCommonFlags(c.Command, f, resource.Group.String(), flagNames)
for _, name := range flagNames {
switch name {
case "member":
f.StringSliceVar(&base.StringSliceVar{
Name: "member",
Target: &c.flagMembers,
Usage: "The members (users) to add, remove, or set. May be specified multiple times.",
})
}
}
}
func generateGroupTableOutput(in *groups.Group) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
var groupMaps []map[string]interface{}
if len(in.Members) > 0 {
for _, member := range in.Members {
m := map[string]interface{}{
"ID": member.Id,
"Scope ID": member.ScopeId,
}
groupMaps = append(groupMaps, m)
}
if l := len("Scope ID"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"Group information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.Members) > 0 {
ret = append(ret,
"",
" Members:",
)
for _, m := range groupMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
return base.WrapForHelpText(ret)
}
-302
View File
@@ -1,302 +0,0 @@
package groups
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/groups"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
flagMembers []string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "add-members", "set-members", "remove-members":
return memberSynopsisFunc(c.Func)
default:
return common.SynopsisFunc(c.Func, "group")
}
}
var helpMap = func() map[string]func() string {
ret := common.HelpMap("group")
ret["add-members"] = addMembersHelp
ret["set-members"] = setMembersHelp
ret["remove-members"] = removeMembersHelp
return ret
}
var flagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
"add-members": {"id", "member", "version"},
"set-members": {"id", "member", "version"},
"remove-members": {"id", "member", "version"},
}
func (c *Command) Help() string {
hm := helpMap()
if c.Func == "" {
return hm["base"]()
}
return hm[c.Func]() + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
populateFlags(c, f, flagsMap[c.Func])
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []groups.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, groups.DefaultName())
default:
opts = append(opts, groups.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, groups.DefaultDescription())
default:
opts = append(opts, groups.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, groups.WithRecursive(true))
}
members := c.flagMembers
switch c.Func {
case "add-members", "remove-members":
if len(c.flagMembers) == 0 {
c.UI.Error("No members supplied via -member")
return 1
}
case "set-members":
switch len(c.flagMembers) {
case 0:
c.UI.Error("No members supplied via -member")
return 1
case 1:
if c.flagMembers[0] == "null" {
members = nil
}
}
}
groupClient := groups.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create", "read", "delete", "list":
// These don't udpate so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, groups.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = groupClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
result, err = groupClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
result, err = groupClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = groupClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = groupClient.List(c.Context, c.FlagScopeId, opts...)
case "add-members":
result, err = groupClient.AddMembers(c.Context, c.FlagId, version, members, opts...)
case "set-members":
result, err = groupClient.SetMembers(c.Context, c.FlagId, version, members, opts...)
case "remove-members":
result, err = groupClient.RemoveMembers(c.Context, c.FlagId, version, members, opts...)
}
plural := "group"
if c.Func == "list" {
plural = "groups"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedGroups := listResult.GetItems().([]*groups.Group)
switch base.Format(c.UI) {
case "json":
if len(listedGroups) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedGroups)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedGroups) == 0 {
c.UI.Output("No groups found")
return 0
}
var output []string
output = []string{
"",
"Group information:",
}
for i, g := range listedGroups {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", g.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", g.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", g.Version),
)
}
if g.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", g.Name),
)
}
if g.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", g.Description),
)
}
if len(g.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, g.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
group := result.GetItem().(*groups.Group)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateGroupTableOutput(group))
case "json":
b, err := base.JsonFormatter{}.Format(group)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+254
View File
@@ -0,0 +1,254 @@
package groupscmd
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/groups"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/mitchellh/go-wordwrap"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
}
type extraCmdVars struct {
flagMembers []string
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"add-members": {"id", "member", "version"},
"remove-members": {"id", "member", "version"},
"set-members": {"id", "member", "version"},
}
}
func extraSynopsisFuncImpl(c *Command) string {
switch c.Func {
case "add-members", "set-members", "remove-members":
var in string
switch {
case strings.HasPrefix(c.Func, "add"):
in = "Add members to"
case strings.HasPrefix(c.Func, "set"):
in = "Set the full contents of the users on"
case strings.HasPrefix(c.Func, "remove"):
in = "Remove users from"
}
return wordwrap.WrapString(fmt.Sprintf("%s a group", in), base.TermWidth)
default:
return ""
}
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return helpMap["base"]()
case "add-members":
return base.WrapForHelpText([]string{
"Usage: boundary groups add-members [options] [args]",
"",
` Adds members (users) to a group given its ID. The "user" flag can be specified multiple times. Example:`,
"",
` $ boundary groups add-members -id g_1234567890 -user u_1234567890`,
"",
"",
})
case "set-members":
return base.WrapForHelpText([]string{
"Usage: boundary groups set-members [options] [args]",
"",
` Sets the complete set of members (users) on a group given its ID. The "user" flag can be specified multiple times. Example:`,
"",
` $ boundary groups set-principals -id g_1234567890 -user u_anon -user u_1234567890`,
"",
"",
})
case "remove-members":
return base.WrapForHelpText([]string{
"Usage: boundary groups remove-members [options] [args]",
"",
` Removes members (users) from a group given its ID. The "user" flag can be specified multiple times. Example:`,
"",
` $ boundary groups remove-members -id g_1234567890 -user u_1234567890`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "member":
f.StringSliceVar(&base.StringSliceVar{
Name: "member",
Target: &c.flagMembers,
Usage: "The members (users) to add, remove, or set. May be specified multiple times.",
})
}
}
}
func extraFlagsHandlingFuncImpl(c *Command, opts *[]groups.Option) int {
switch c.Func {
case "add-members", "remove-members":
if len(c.flagMembers) == 0 {
c.UI.Error("No members supplied via -member")
return 1
}
case "set-members":
switch len(c.flagMembers) {
case 0:
c.UI.Error("No members supplied via -member")
return 1
case 1:
if c.flagMembers[0] == "null" {
c.flagMembers = nil
}
}
}
return 0
}
func executeExtraActionsImpl(c *Command, origResult api.GenericResult, origError error, groupClient *groups.Client, version uint32, opts []groups.Option) (api.GenericResult, error) {
switch c.Func {
case "add-members":
return groupClient.AddMembers(c.Context, c.FlagId, version, c.flagMembers, opts...)
case "set-members":
return groupClient.SetMembers(c.Context, c.FlagId, version, c.flagMembers, opts...)
case "remove-members":
return groupClient.RemoveMembers(c.Context, c.FlagId, version, c.flagMembers, opts...)
}
return origResult, origError
}
func (c *Command) printListTable(items []*groups.Group) string {
if len(items) == 0 {
return "No groups found"
}
var output []string
output = []string{
"",
"Group information:",
}
for i, g := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", g.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", g.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", g.Version),
)
}
if g.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", g.Name),
)
}
if g.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", g.Description),
)
}
if len(g.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, g.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(item *groups.Group) string {
nonAttributeMap := map[string]interface{}{
"ID": item.Id,
"Version": item.Version,
"Created Time": item.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": item.UpdatedTime.Local().Format(time.RFC1123),
}
if item.Name != "" {
nonAttributeMap["Name"] = item.Name
}
if item.Description != "" {
nonAttributeMap["Description"] = item.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
var groupMaps []map[string]interface{}
if len(item.Members) > 0 {
for _, member := range item.Members {
m := map[string]interface{}{
"ID": member.Id,
"Scope ID": member.ScopeId,
}
groupMaps = append(groupMaps, m)
}
if l := len("Scope ID"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"Group information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(item.Scope, maxLength),
}
if len(item.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, item.AuthorizedActions),
)
}
if len(item.Members) > 0 {
ret = append(ret,
"",
" Members:",
)
for _, m := range groupMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
return base.WrapForHelpText(ret)
}
@@ -0,0 +1,362 @@
// Code generated by "make api"; DO NOT EDIT.
package groupscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/groups"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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
extraCmdVars
}
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 := "group"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("group")
switch c.Func {
case "create":
helpStr = helpMap[c.Func]() + c.Flags().Help()
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"read": {"id"},
"update": {"id", "name", "description", "version"},
"delete": {"id"},
"list": {"scope-id", "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, "group", flagsMap[c.Func])
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "group"
switch c.Func {
case "list":
c.plural = "groups"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []groups.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
groupsClient := groups.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, groups.DefaultName())
default:
opts = append(opts, groups.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, groups.DefaultDescription())
default:
opts = append(opts, groups.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, groups.WithRecursive(true))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, groups.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "add-members":
switch c.FlagVersion {
case 0:
opts = append(opts, groups.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "remove-members":
switch c.FlagVersion {
case 0:
opts = append(opts, groups.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-members":
switch c.FlagVersion {
case 0:
opts = append(opts, groups.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = groupsClient.Create(c.Context, c.FlagScopeId, opts...)
case "read":
result, err = groupsClient.Read(c.Context, c.FlagId, opts...)
case "update":
result, err = groupsClient.Update(c.Context, c.FlagId, version, opts...)
case "delete":
_, err = groupsClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = groupsClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, groupsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*groups.Group)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*groups.Group)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]groups.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *groups.Client, _ uint32, _ []groups.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
@@ -1,77 +0,0 @@
package hostcatalogs
import (
"fmt"
"sort"
"time"
"github.com/hashicorp/boundary/api/hostcatalogs"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateHostCatalogTableOutput(in *hostcatalogs.HostCatalog) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Host Catalog information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.AuthorizedCollectionActions) > 0 {
keys := make([]string, 0, len(in.AuthorizedCollectionActions))
for k := range in.AuthorizedCollectionActions {
keys = append(keys, k)
}
sort.Strings(keys)
ret = append(ret, "",
" Authorized Actions on Host Catalog's Collections:",
)
for _, key := range keys {
ret = append(ret,
fmt.Sprintf(" %ss:", key),
base.WrapSlice(6, in.AuthorizedCollectionActions[key]),
)
}
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{
"address": "Address",
}
@@ -1,284 +0,0 @@
package hostcatalogs
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostcatalogs"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
}
func (c *Command) Synopsis() string {
return common.SynopsisFunc(c.Func, "host catalog")
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("host catalog")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary host-catalogs [sub command] [options] [args]",
"",
" This command allows operations on Boundary host catalog resources. Example:",
"",
" Read a host catalog:",
"",
` $ boundary host-catalogs read -id hcst_1234567890`,
"",
" Please see the host-catalogs subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host catalog resources. Example:",
"",
" Create a static-type host catalog:",
"",
` $ boundary host-catalogs create static -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host catalog resources. Example:",
"",
" Update a static-type host catalog:",
"",
` $ boundary host-catalogs update static -id hcst_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
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, resource.HostCatalog.String(), flagsMap[c.Func])
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hostcatalogs.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hostcatalogs.DefaultName())
default:
opts = append(opts, hostcatalogs.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hostcatalogs.DefaultDescription())
default:
opts = append(opts, hostcatalogs.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, hostcatalogs.WithRecursive(true))
}
hostcatalogClient := hostcatalogs.NewClient(client)
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = hostcatalogClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = hostcatalogClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = hostcatalogClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "host catalog"
if c.Func == "list" {
plural = "host catalogs"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedCatalogs := listResult.GetItems().([]*hostcatalogs.HostCatalog)
switch base.Format(c.UI) {
case "json":
if len(listedCatalogs) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedCatalogs)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedCatalogs) == 0 {
c.UI.Output("No host catalogs found")
return 0
}
var output []string
output = []string{
"",
"Host Catalog information:",
}
for i, m := range listedCatalogs {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", m.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
catalog := result.GetItem().(*hostcatalogs.HostCatalog)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostCatalogTableOutput(catalog))
case "json":
b, err := base.JsonFormatter{}.Format(catalog)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
@@ -1,174 +0,0 @@
package hostcatalogs
import (
"fmt"
"net/textproto"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostcatalogs"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*StaticCommand)(nil)
_ cli.CommandAutocomplete = (*StaticCommand)(nil)
)
type StaticCommand struct {
*base.Command
Func string
}
func (c *StaticCommand) Synopsis() string {
return fmt.Sprintf("%s a static-type host catalog", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var staticFlagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *StaticCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs create static [options] [args]",
"",
" Create a static-type host catalog. Example:",
"",
` $ boundary host-catalogs create static -name prodops -description "Static host-catalog for ProdOps"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs update static [options] [args]",
"",
" Update a static-type host catalog given its ID. Example:",
"",
` $ boundary host-catalogs update static -id hcst_1234567890 -name "devops" -description "Static host-catalog for DevOps"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *StaticCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "static-type host catalog", staticFlagsMap[c.Func])
return set
}
func (c *StaticCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *StaticCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *StaticCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hostcatalogs.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hostcatalogs.DefaultName())
default:
opts = append(opts, hostcatalogs.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hostcatalogs.DefaultDescription())
default:
opts = append(opts, hostcatalogs.WithDescription(c.FlagDescription))
}
hostcatalogClient := hostcatalogs.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, hostcatalogs.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = hostcatalogClient.Create(c.Context, "static", c.FlagScopeId, opts...)
case "update":
result, err = hostcatalogClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "static-type host-catalog"
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
catalog := result.GetItem().(*hostcatalogs.HostCatalog)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostCatalogTableOutput(catalog))
case "json":
b, err := base.JsonFormatter{}.Format(catalog)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
@@ -0,0 +1,173 @@
package hostcatalogscmd
import (
"fmt"
"sort"
"time"
"github.com/hashicorp/boundary/api/hostcatalogs"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary host-catalogs [sub command] [options] [args]",
"",
" This command allows operations on Boundary host catalog resources. Example:",
"",
" Read a host catalog:",
"",
` $ boundary host-catalogs read -id hcst_1234567890`,
"",
" Please see the host-catalogs subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host catalog resources. Example:",
"",
" Create a static-type host catalog:",
"",
` $ boundary host-catalogs create static -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host catalog resources. Example:",
"",
" Update a static-type host catalog:",
"",
` $ boundary host-catalogs update static -id hcst_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
default:
helpStr = helpMap["base"]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) printListTable(items []*hostcatalogs.HostCatalog) string {
if len(items) == 0 {
return "No host catalogs found"
}
var output []string
output = []string{
"",
"Host Catalog information:",
}
for i, m := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", m.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *hostcatalogs.HostCatalog) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Host Catalog information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.AuthorizedCollectionActions) > 0 {
keys := make([]string, 0, len(in.AuthorizedCollectionActions))
for k := range in.AuthorizedCollectionActions {
keys = append(keys, k)
}
sort.Strings(keys)
ret = append(ret, "",
" Authorized Actions on Host Catalog's Collections:",
)
for _, key := range keys {
ret = append(ret,
fmt.Sprintf(" %ss:", key),
base.WrapSlice(6, in.AuthorizedCollectionActions[key]),
)
}
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{
"address": "Address",
}
@@ -0,0 +1,288 @@
// Code generated by "make api"; DO NOT EDIT.
package hostcatalogscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostcatalogs"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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 := "host catalog"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("host catalog")
switch c.Func {
case "read":
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "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, "host catalog", 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", "update":
return cli.RunResultHelp
}
c.plural = "host catalog"
switch c.Func {
case "list":
c.plural = "host catalogs"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []hostcatalogs.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
hostcatalogsClient := hostcatalogs.NewClient(client)
switch c.FlagRecursive {
case true:
opts = append(opts, hostcatalogs.WithRecursive(true))
}
var version uint32
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = hostcatalogsClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = hostcatalogsClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = hostcatalogsClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, hostcatalogsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*hostcatalogs.HostCatalog)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*hostcatalogs.HostCatalog)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]hostcatalogs.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *hostcatalogs.Client, _ uint32, _ []hostcatalogs.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
@@ -0,0 +1,33 @@
package hostcatalogscmd
import (
"github.com/hashicorp/boundary/internal/cmd/base"
)
func (c *StaticCommand) extraStaticHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs create static [options] [args]",
"",
" Create a static-type host catalog. Example:",
"",
` $ boundary host-catalogs create static -name prodops -description "Static host-catalog for ProdOps"`,
"",
"",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs update static [options] [args]",
"",
" Update a static-type host catalog given its ID. Example:",
"",
` $ boundary host-catalogs update static -id hcst_1234567890 -name "devops" -description "Static host-catalog for DevOps"`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
@@ -0,0 +1,241 @@
// Code generated by "make api"; DO NOT EDIT.
package hostcatalogscmd
import (
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostcatalogs"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initStaticFlags() {
flagsOnce.Do(func() {
extraFlags := extraStaticActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsStaticMap[k] = append(flagsStaticMap[k], v...)
}
})
}
var (
_ cli.Command = (*StaticCommand)(nil)
_ cli.CommandAutocomplete = (*StaticCommand)(nil)
)
type StaticCommand struct {
*base.Command
Func string
plural string
}
func (c *StaticCommand) AutocompleteArgs() complete.Predictor {
initStaticFlags()
return complete.PredictAnything
}
func (c *StaticCommand) AutocompleteFlags() complete.Flags {
initStaticFlags()
return c.Flags().Completions()
}
func (c *StaticCommand) Synopsis() string {
if extra := extraStaticSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "host catalog"
synopsisStr = fmt.Sprintf("%s %s", "static-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *StaticCommand) Help() string {
initStaticFlags()
var helpStr string
helpMap := common.HelpMap("host catalog")
switch c.Func {
default:
helpStr = c.extraStaticHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsStaticMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *StaticCommand) Flags() *base.FlagSets {
if len(flagsStaticMap[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, "static-type host catalog", flagsStaticMap[c.Func])
extraStaticFlagsFunc(c, set, f)
return set
}
func (c *StaticCommand) Run(args []string) int {
initStaticFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "static-type host catalog"
switch c.Func {
case "list":
c.plural = "static-type host catalogs"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsStaticMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []hostcatalogs.Option
if strutil.StrListContains(flagsStaticMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
hostcatalogsClient := hostcatalogs.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, hostcatalogs.DefaultName())
default:
opts = append(opts, hostcatalogs.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hostcatalogs.DefaultDescription())
default:
opts = append(opts, hostcatalogs.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, hostcatalogs.WithRecursive(true))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, hostcatalogs.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraStaticFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = hostcatalogsClient.Create(c.Context, "static", c.FlagScopeId, opts...)
case "update":
result, err = hostcatalogsClient.Update(c.Context, c.FlagId, version, opts...)
}
result, err = executeExtraStaticActions(c, result, err, hostcatalogsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomStaticActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
}
item := result.GetItem().(*hostcatalogs.HostCatalog)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
var (
extraStaticActionsFlagsMapFunc = func() map[string][]string { return nil }
extraStaticSynopsisFunc = func(*StaticCommand) string { return "" }
extraStaticFlagsFunc = func(*StaticCommand, *base.FlagSets, *base.FlagSet) {}
extraStaticFlagsHandlingFunc = func(*StaticCommand, *[]hostcatalogs.Option) int { return 0 }
executeExtraStaticActions = func(_ *StaticCommand, inResult api.GenericResult, inErr error, _ *hostcatalogs.Client, _ uint32, _ []hostcatalogs.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomStaticActionOutput = func(*StaticCommand) (bool, error) { return false, nil }
)
-65
View File
@@ -1,65 +0,0 @@
package hosts
import (
"time"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateHostTableOutput(in *hosts.Host) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Host Catalog ID": in.HostCatalogId,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Host information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.HostSetIds) > 0 {
ret = append(ret,
"",
" Host Set IDs:",
base.WrapSlice(4, in.HostSetIds),
)
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{}
-271
View File
@@ -1,271 +0,0 @@
package hosts
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
}
func (c *Command) Synopsis() string {
return common.SynopsisFunc(c.Func, "host")
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"host-catalog-id"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("host")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary hosts [sub command] [options] [args]",
"",
" This command allows operations on Boundary host resources. Example:",
"",
" Read a host:",
"",
` $ boundary hosts read -id hst_1234567890`,
"",
" Please see the hosts subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host resources. Example:",
"",
" Create a static-type host:",
"",
` $ boundary hosts create static -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host resources. Example:",
"",
" Update a static-type host:",
"",
` $ boundary hosts update static -id hst_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
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, resource.Host.String(), flagsMap[c.Func])
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "host-catalog-id") && c.FlagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hosts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hosts.DefaultName())
default:
opts = append(opts, hosts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hosts.DefaultDescription())
default:
opts = append(opts, hosts.WithDescription(c.FlagDescription))
}
hostClient := hosts.NewClient(client)
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = hostClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = hostClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = hostClient.List(c.Context, c.FlagHostCatalogId, opts...)
}
plural := "host"
if c.Func == "list" {
plural = "hosts"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedHosts := listResult.GetItems().([]*hosts.Host)
switch base.Format(c.UI) {
case "json":
if len(listedHosts) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedHosts)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedHosts) == 0 {
c.UI.Output("No hosts found")
return 0
}
var output []string
output = []string{
"",
"Host information:",
}
for i, m := range listedHosts {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
host := result.GetItem().(*hosts.Host)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostTableOutput(host))
case "json":
b, err := base.JsonFormatter{}.Format(host)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
-201
View File
@@ -1,201 +0,0 @@
package hosts
import (
"fmt"
"net/textproto"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*StaticCommand)(nil)
_ cli.CommandAutocomplete = (*StaticCommand)(nil)
)
type StaticCommand struct {
*base.Command
Func string
flagAddress string
}
func (c *StaticCommand) Synopsis() string {
return fmt.Sprintf("%s a static-type host", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var staticFlagsMap = map[string][]string{
"create": {"host-catalog-id", "name", "description", "address"},
"update": {"id", "name", "description", "version", "address"},
}
func (c *StaticCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary hosts static create [options] [args]",
"",
" Create a static-type host. Example:",
"",
` $ boundary hosts static create -name prodops -description "Static host for ProdOps" -address "127.0.0.1"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary hosts update static [options] [args]",
"",
" Update a static-type host given its ID. Example:",
"",
` $ boundary hosts update static -id hst_1234567890 -name "devops" -description "Static host for DevOps" -address "10.20.30.40"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *StaticCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "static-type host", staticFlagsMap[c.Func])
f = set.NewFlagSet("Static Host Options")
for _, name := range staticFlagsMap[c.Func] {
switch name {
case "address":
f.StringVar(&base.StringVar{
Name: "address",
Target: &c.flagAddress,
Usage: "The address of the host",
})
}
}
return set
}
func (c *StaticCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *StaticCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *StaticCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "host-catalog-id") && c.FlagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
if c.Func == "create" && c.flagAddress == "" {
c.UI.Error("Address must be passed in via -address")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hosts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hosts.DefaultName())
default:
opts = append(opts, hosts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hosts.DefaultDescription())
default:
opts = append(opts, hosts.WithDescription(c.FlagDescription))
}
switch c.flagAddress {
case "":
case "null":
opts = append(opts, hosts.DefaultStaticHostAddress())
default:
opts = append(opts, hosts.WithStaticHostAddress(c.flagAddress))
}
hostClient := hosts.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, hosts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = hostClient.Create(c.Context, c.FlagHostCatalogId, opts...)
case "update":
result, err = hostClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "static-type host"
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
host := result.GetItem().(*hosts.Host)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostTableOutput(host))
case "json":
b, err := base.JsonFormatter{}.Format(host)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+153
View File
@@ -0,0 +1,153 @@
package hostscmd
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary hosts [sub command] [options] [args]",
"",
" This command allows operations on Boundary host resources. Example:",
"",
" Read a host:",
"",
` $ boundary hosts read -id hst_1234567890`,
"",
" Please see the hosts subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host resources. Example:",
"",
" Create a static-type host:",
"",
` $ boundary hosts create static -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host resources. Example:",
"",
" Update a static-type host:",
"",
` $ boundary hosts update static -id hst_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) printListTable(items []*hosts.Host) string {
if len(items) == 0 {
return "No host sets found"
}
var output []string
output = []string{
"",
"Host information:",
}
for i, item := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", item.Id),
fmt.Sprintf(" Version: %d", item.Version),
fmt.Sprintf(" Type: %s", item.Type),
)
}
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 len(item.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, item.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *hosts.Host) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Host Catalog ID": in.HostCatalogId,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Host information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.HostSetIds) > 0 {
ret = append(ret,
"",
" Host Set IDs:",
base.WrapSlice(4, in.HostSetIds),
)
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{}
+299
View File
@@ -0,0 +1,299 @@
// Code generated by "make api"; DO NOT EDIT.
package hostscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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 := "host"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("host")
switch c.Func {
case "read":
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"host-catalog-id"},
}
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, "host", 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", "update":
return cli.RunResultHelp
}
c.plural = "host"
switch c.Func {
case "list":
c.plural = "hosts"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []hosts.Option
if strutil.StrListContains(flagsMap[c.Func], "host-catalog-id") {
switch c.Func {
case "list":
if c.FlagHostCatalogId == "" {
c.UI.Error("HostCatalog ID must be passed in via -host-catalog-id or BOUNDARY_HOST_CATALOG_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
hostsClient := hosts.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, hosts.DefaultName())
default:
opts = append(opts, hosts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hosts.DefaultDescription())
default:
opts = append(opts, hosts.WithDescription(c.FlagDescription))
}
var version uint32
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = hostsClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = hostsClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = hostsClient.List(c.Context, c.FlagHostCatalogId, opts...)
}
result, err = executeExtraActions(c, result, err, hostsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*hosts.Host)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*hosts.Host)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]hosts.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *hosts.Client, _ uint32, _ []hosts.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
@@ -0,0 +1,86 @@
package hostscmd
import (
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func init() {
extraStaticActionsFlagsMapFunc = extraStaticActionsFlagsMapFuncImpl
extraStaticFlagsFunc = extraStaticFlagsFuncImpl
extraStaticFlagsHandlingFunc = extraStaticFlagsHandlingFuncImpl
}
type extraStaticCmdVars struct {
flagAddress string
}
func extraStaticActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"address"},
"update": {"address"},
}
}
func (c *StaticCommand) extraStaticHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts static create [options] [args]",
"",
" Create a static-type host. Example:",
"",
` $ boundary hosts static create -name prodops -description "Static host for ProdOps" -address "127.0.0.1"`,
"",
"",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts update static [options] [args]",
"",
" Update a static-type host given its ID. Example:",
"",
` $ boundary hosts update static -id hst_1234567890 -name "devops" -description "Static host for DevOps" -address "10.20.30.40"`,
"",
"",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func extraStaticFlagsFuncImpl(c *StaticCommand, set *base.FlagSets, _ *base.FlagSet) {
f := set.NewFlagSet("Static Host Options")
for _, name := range flagsStaticMap[c.Func] {
switch name {
case "address":
f.StringVar(&base.StringVar{
Name: "address",
Target: &c.flagAddress,
Usage: "The address of the host",
})
}
}
}
func extraStaticFlagsHandlingFuncImpl(c *StaticCommand, opts *[]hosts.Option) int {
if c.Func == "create" && c.flagAddress == "" {
c.UI.Error("Address must be provided via -address")
return 1
}
switch c.flagAddress {
case "":
case "null":
*opts = append(*opts, hosts.DefaultStaticHostAddress())
default:
*opts = append(*opts, hosts.WithStaticHostAddress(c.flagAddress))
}
return 0
}
@@ -0,0 +1,238 @@
// Code generated by "make api"; DO NOT EDIT.
package hostscmd
import (
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initStaticFlags() {
flagsOnce.Do(func() {
extraFlags := extraStaticActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsStaticMap[k] = append(flagsStaticMap[k], v...)
}
})
}
var (
_ cli.Command = (*StaticCommand)(nil)
_ cli.CommandAutocomplete = (*StaticCommand)(nil)
)
type StaticCommand struct {
*base.Command
Func string
plural string
extraStaticCmdVars
}
func (c *StaticCommand) AutocompleteArgs() complete.Predictor {
initStaticFlags()
return complete.PredictAnything
}
func (c *StaticCommand) AutocompleteFlags() complete.Flags {
initStaticFlags()
return c.Flags().Completions()
}
func (c *StaticCommand) Synopsis() string {
if extra := extraStaticSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "host"
synopsisStr = fmt.Sprintf("%s %s", "static-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *StaticCommand) Help() string {
initStaticFlags()
var helpStr string
helpMap := common.HelpMap("host")
switch c.Func {
default:
helpStr = c.extraStaticHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsStaticMap = map[string][]string{
"create": {"host-catalog-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *StaticCommand) Flags() *base.FlagSets {
if len(flagsStaticMap[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, "static-type host", flagsStaticMap[c.Func])
extraStaticFlagsFunc(c, set, f)
return set
}
func (c *StaticCommand) Run(args []string) int {
initStaticFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "static-type host"
switch c.Func {
case "list":
c.plural = "static-type hosts"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsStaticMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []hosts.Option
if strutil.StrListContains(flagsStaticMap[c.Func], "host-catalog-id") {
switch c.Func {
case "create":
if c.FlagHostCatalogId == "" {
c.UI.Error("HostCatalog ID must be passed in via -host-catalog-id or BOUNDARY_HOST_CATALOG_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
hostsClient := hosts.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, hosts.DefaultName())
default:
opts = append(opts, hosts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hosts.DefaultDescription())
default:
opts = append(opts, hosts.WithDescription(c.FlagDescription))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, hosts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraStaticFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = hostsClient.Create(c.Context, c.FlagHostCatalogId, opts...)
case "update":
result, err = hostsClient.Update(c.Context, c.FlagId, version, opts...)
}
result, err = executeExtraStaticActions(c, result, err, hostsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomStaticActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
}
item := result.GetItem().(*hosts.Host)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
var (
extraStaticActionsFlagsMapFunc = func() map[string][]string { return nil }
extraStaticSynopsisFunc = func(*StaticCommand) string { return "" }
extraStaticFlagsFunc = func(*StaticCommand, *base.FlagSets, *base.FlagSet) {}
extraStaticFlagsHandlingFunc = func(*StaticCommand, *[]hosts.Option) int { return 0 }
executeExtraStaticActions = func(_ *StaticCommand, inResult api.GenericResult, inErr error, _ *hosts.Client, _ uint32, _ []hosts.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomStaticActionOutput = func(*StaticCommand) (bool, error) { return false, nil }
)
-65
View File
@@ -1,65 +0,0 @@
package hostsets
import (
"time"
"github.com/hashicorp/boundary/api/hostsets"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateHostSetTableOutput(in *hostsets.HostSet) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Host Catalog ID": in.HostCatalogId,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Host Set information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.HostIds) > 0 {
ret = append(ret,
"",
" Host IDs:",
base.WrapSlice(4, in.HostIds),
)
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{}
-366
View File
@@ -1,366 +0,0 @@
package hostsets
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostsets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
flagHosts []string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "add-hosts":
return "Add hosts to the specified host set"
case "remove-hosts":
return "Remove hosts from the specified host set"
case "set-hosts":
return "Set the full contents of the hosts on the specified host set"
default:
return common.SynopsisFunc(c.Func, "host set")
}
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"host-catalog-id"},
"add-hosts": {"id", "host", "version"},
"set-hosts": {"id", "host", "version"},
"remove-hosts": {"id", "host", "version"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("host set")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary host-sets [sub command] [options] [args]",
"",
" This command allows operations on Boundary host set resources. Example:",
"",
" Read a host set:",
"",
` $ boundary host-sets read -id hsst_1234567890`,
"",
" Please see the host-sets subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host set resources. Example:",
"",
" Create a static-type host set:",
"",
` $ boundary host-sets create static -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host set resources. Example:",
"",
" Update a static-type host set:",
"",
` $ boundary host-sets update static -id hsst_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "add-hosts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets add-hosts [sub command] [options] [args]",
"",
" This command allows adding hosts to host set resources, if the types match and the operation is allowed by the given host set type. Example:",
"",
" Add static-type hosts to a static-type host set:",
"",
` $ boundary host-sets add-hosts -id hsst_1234567890 -host hst_1234567890 -host hst_0987654321`,
})
case "remove-hosts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets remove-hosts [sub command] [options] [args]",
"",
" This command allows removing hosts from host set resources, if the types match and the operation is allowed by the given host set type. Example:",
"",
" Remove static-type hosts from a static-type host set:",
"",
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_0987654321`,
})
case "set-hosts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets set-hosts [sub command] [options] [args]",
"",
" This command allows setting the complete set of hosts on host set resources, if the types match and the operation is allowed by the given host set type. Example:",
"",
" Set the complete set of static-type hosts on a static-type host set:",
"",
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_1234567890`,
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
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, resource.HostSet.String(), flagsMap[c.Func])
for _, name := range flagsMap[c.Func] {
switch name {
case "host":
f.StringSliceVar(&base.StringSliceVar{
Name: "host",
Target: &c.flagHosts,
Usage: "The hosts to add, remove, or set. May be specified multiple times.",
})
}
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "host-catalog-id") && c.FlagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hostsets.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hostsets.DefaultName())
default:
opts = append(opts, hostsets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hostsets.DefaultDescription())
default:
opts = append(opts, hostsets.WithDescription(c.FlagDescription))
}
hosts := c.flagHosts
switch c.Func {
case "add-hosts", "remove-hosts":
if len(c.flagHosts) == 0 {
c.UI.Error("No hosts supplied via -host")
return 1
}
case "set-hosts":
switch len(c.flagHosts) {
case 0:
c.UI.Error("No hosts supplied via -host")
return 1
case 1:
if c.flagHosts[0] == "null" {
hosts = nil
}
}
}
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "add-hosts", "remove-hosts", "set-hosts":
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
default:
// The only other one that needs it is update, handled by the static
// file
}
hostsetClient := hostsets.NewClient(client)
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = hostsetClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = hostsetClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = hostsetClient.List(c.Context, c.FlagHostCatalogId, opts...)
case "add-hosts":
result, err = hostsetClient.AddHosts(c.Context, c.FlagId, version, hosts, opts...)
case "remove-hosts":
result, err = hostsetClient.RemoveHosts(c.Context, c.FlagId, version, hosts, opts...)
case "set-hosts":
result, err = hostsetClient.SetHosts(c.Context, c.FlagId, version, hosts, opts...)
}
plural := "host set"
if c.Func == "list" {
plural = "host sets"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedSets := listResult.GetItems().([]*hostsets.HostSet)
switch base.Format(c.UI) {
case "json":
if len(listedSets) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedSets)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedSets) == 0 {
c.UI.Output("No host sets found")
return 0
}
var output []string
output = []string{
"",
"Host Set information:",
}
for i, m := range listedSets {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
set := result.GetItem().(*hostsets.HostSet)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostSetTableOutput(set))
case "json":
b, err := base.JsonFormatter{}.Format(set)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
-174
View File
@@ -1,174 +0,0 @@
package hostsets
import (
"fmt"
"net/textproto"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostsets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*StaticCommand)(nil)
_ cli.CommandAutocomplete = (*StaticCommand)(nil)
)
type StaticCommand struct {
*base.Command
Func string
}
func (c *StaticCommand) Synopsis() string {
return fmt.Sprintf("%s a static-type host set", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var staticFlagsMap = map[string][]string{
"create": {"host-catalog-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *StaticCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary host-sets create static [options] [args]",
"",
" Create a static-type host set. Example:",
"",
` $ boundary host-sets create static -name prodops -description "Static host-set for ProdOps"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary host-sets update static [options] [args]",
"",
" Update a static-type host set given its ID. Example:",
"",
` $ boundary host-sets update static -id hsst_1234567890 -name "devops" -description "Static host-set for DevOps"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *StaticCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "static-type host set", staticFlagsMap[c.Func])
return set
}
func (c *StaticCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *StaticCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *StaticCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "host-catalog-id") && c.FlagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hostsets.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hostsets.DefaultName())
default:
opts = append(opts, hostsets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hostsets.DefaultDescription())
default:
opts = append(opts, hostsets.WithDescription(c.FlagDescription))
}
hostsetClient := hostsets.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = hostsetClient.Create(c.Context, c.FlagHostCatalogId, opts...)
case "update":
result, err = hostsetClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "static-type host-set"
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
set := result.GetItem().(*hostsets.HostSet)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostSetTableOutput(set))
case "json":
b, err := base.JsonFormatter{}.Format(set)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+272
View File
@@ -0,0 +1,272 @@
package hostsetscmd
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostsets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
}
type extraCmdVars struct {
flagHosts []string
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"add-hosts": {"id", "host", "version"},
"set-hosts": {"id", "host", "version"},
"remove-hosts": {"id", "host", "version"},
}
}
func extraSynopsisFuncImpl(c *Command) string {
switch c.Func {
case "add-hosts":
return "Add hosts to the specified host set"
case "remove-hosts":
return "Remove hosts from the specified host set"
case "set-hosts":
return "Set the full contents of the hosts on the specified host set"
default:
return common.SynopsisFunc(c.Func, "host set")
}
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary host-sets [sub command] [options] [args]",
"",
" This command allows operations on Boundary host set resources. Example:",
"",
" Read a host set:",
"",
` $ boundary host-sets read -id hsst_1234567890`,
"",
" Please see the host-sets subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host set resources. Example:",
"",
" Create a static-type host set:",
"",
` $ boundary host-sets create static -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host set resources. Example:",
"",
" Update a static-type host set:",
"",
` $ boundary host-sets update static -id hsst_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "add-hosts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets add-hosts [sub command] [options] [args]",
"",
" This command allows adding hosts to host set resources, if the types match and the operation is allowed by the given host set type. Example:",
"",
" Add static-type hosts to a static-type host set:",
"",
` $ boundary host-sets add-hosts -id hsst_1234567890 -host hst_1234567890 -host hst_0987654321`,
"",
"",
})
case "remove-hosts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets remove-hosts [sub command] [options] [args]",
"",
" This command allows removing hosts from host set resources, if the types match and the operation is allowed by the given host set type. Example:",
"",
" Remove static-type hosts from a static-type host set:",
"",
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_0987654321`,
"",
"",
})
case "set-hosts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets set-hosts [sub command] [options] [args]",
"",
" This command allows setting the complete set of hosts on host set resources, if the types match and the operation is allowed by the given host set type. Example:",
"",
" Set the complete set of static-type hosts on a static-type host set:",
"",
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_1234567890`,
"",
"",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "host":
f.StringSliceVar(&base.StringSliceVar{
Name: "host",
Target: &c.flagHosts,
Usage: "The hosts to add, remove, or set. May be specified multiple times.",
})
}
}
}
func extraFlagsHandlingFuncImpl(c *Command, opts *[]hostsets.Option) int {
switch c.Func {
case "add-hosts", "remove-hosts":
if len(c.flagHosts) == 0 {
c.UI.Error("No hosts supplied via -host")
return 1
}
case "set-hosts":
switch len(c.flagHosts) {
case 0:
c.UI.Error("No hosts supplied via -host")
return 1
case 1:
if c.flagHosts[0] == "null" {
c.flagHosts = nil
}
}
}
return 0
}
func executeExtraActionsImpl(c *Command, origResult api.GenericResult, origError error, hostsetClient *hostsets.Client, version uint32, opts []hostsets.Option) (api.GenericResult, error) {
switch c.Func {
case "add-hosts":
return hostsetClient.AddHosts(c.Context, c.FlagId, version, c.flagHosts, opts...)
case "remove-hosts":
return hostsetClient.RemoveHosts(c.Context, c.FlagId, version, c.flagHosts, opts...)
case "set-hosts":
return hostsetClient.SetHosts(c.Context, c.FlagId, version, c.flagHosts, opts...)
}
return origResult, origError
}
func (c *Command) printListTable(items []*hostsets.HostSet) string {
if len(items) == 0 {
return "No host sets found"
}
var output []string
output = []string{
"",
"Host Set information:",
}
for i, m := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *hostsets.HostSet) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Host Catalog ID": in.HostCatalogId,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
ret := []string{
"",
"Host Set information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.HostIds) > 0 {
ret = append(ret,
"",
" Host IDs:",
base.WrapSlice(4, in.HostIds),
)
}
if len(in.Attributes) > 0 {
ret = append(ret,
"",
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{}
@@ -0,0 +1,329 @@
// Code generated by "make api"; DO NOT EDIT.
package hostsetscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostsets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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
extraCmdVars
}
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 := "host set"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("host set")
switch c.Func {
case "read":
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"host-catalog-id"},
}
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, "host set", 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", "update":
return cli.RunResultHelp
}
c.plural = "host set"
switch c.Func {
case "list":
c.plural = "host sets"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []hostsets.Option
if strutil.StrListContains(flagsMap[c.Func], "host-catalog-id") {
switch c.Func {
case "list":
if c.FlagHostCatalogId == "" {
c.UI.Error("HostCatalog ID must be passed in via -host-catalog-id or BOUNDARY_HOST_CATALOG_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
hostsetsClient := hostsets.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, hostsets.DefaultName())
default:
opts = append(opts, hostsets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hostsets.DefaultDescription())
default:
opts = append(opts, hostsets.WithDescription(c.FlagDescription))
}
var version uint32
switch c.Func {
case "add-hosts":
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-hosts":
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "remove-hosts":
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = hostsetsClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = hostsetsClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = hostsetsClient.List(c.Context, c.FlagHostCatalogId, opts...)
}
result, err = executeExtraActions(c, result, err, hostsetsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*hostsets.HostSet)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*hostsets.HostSet)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]hostsets.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *hostsets.Client, _ uint32, _ []hostsets.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
@@ -0,0 +1,35 @@
package hostsetscmd
import (
"github.com/hashicorp/boundary/internal/cmd/base"
)
func (c *StaticCommand) extraStaticHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets create static [options] [args]",
"",
" Create a static-type host set. Example:",
"",
` $ boundary host-sets create static -name prodops -description "Static host-set for ProdOps"`,
"",
"",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets update static [options] [args]",
"",
" Update a static-type host set given its ID. Example:",
"",
` $ boundary host-sets update static -id hsst_1234567890 -name "devops" -description "Static host-set for DevOps"`,
"",
"",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
@@ -0,0 +1,236 @@
// Code generated by "make api"; DO NOT EDIT.
package hostsetscmd
import (
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hostsets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initStaticFlags() {
flagsOnce.Do(func() {
extraFlags := extraStaticActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsStaticMap[k] = append(flagsStaticMap[k], v...)
}
})
}
var (
_ cli.Command = (*StaticCommand)(nil)
_ cli.CommandAutocomplete = (*StaticCommand)(nil)
)
type StaticCommand struct {
*base.Command
Func string
plural string
}
func (c *StaticCommand) AutocompleteArgs() complete.Predictor {
initStaticFlags()
return complete.PredictAnything
}
func (c *StaticCommand) AutocompleteFlags() complete.Flags {
initStaticFlags()
return c.Flags().Completions()
}
func (c *StaticCommand) Synopsis() string {
if extra := extraStaticSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "host set"
synopsisStr = fmt.Sprintf("%s %s", "static-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *StaticCommand) Help() string {
initStaticFlags()
var helpStr string
helpMap := common.HelpMap("host set")
switch c.Func {
default:
helpStr = c.extraStaticHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsStaticMap = map[string][]string{
"create": {"host-catalog-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *StaticCommand) Flags() *base.FlagSets {
if len(flagsStaticMap[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, "static-type host set", flagsStaticMap[c.Func])
extraStaticFlagsFunc(c, set, f)
return set
}
func (c *StaticCommand) Run(args []string) int {
initStaticFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "static-type host set"
switch c.Func {
case "list":
c.plural = "static-type host sets"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsStaticMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []hostsets.Option
if strutil.StrListContains(flagsStaticMap[c.Func], "host-catalog-id") {
switch c.Func {
case "create":
if c.FlagHostCatalogId == "" {
c.UI.Error("HostCatalog ID must be passed in via -host-catalog-id or BOUNDARY_HOST_CATALOG_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
hostsetsClient := hostsets.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, hostsets.DefaultName())
default:
opts = append(opts, hostsets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hostsets.DefaultDescription())
default:
opts = append(opts, hostsets.WithDescription(c.FlagDescription))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraStaticFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = hostsetsClient.Create(c.Context, c.FlagHostCatalogId, opts...)
case "update":
result, err = hostsetsClient.Update(c.Context, c.FlagId, version, opts...)
}
result, err = executeExtraStaticActions(c, result, err, hostsetsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomStaticActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
}
item := result.GetItem().(*hostsets.HostSet)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
var (
extraStaticActionsFlagsMapFunc = func() map[string][]string { return nil }
extraStaticSynopsisFunc = func(*StaticCommand) string { return "" }
extraStaticFlagsFunc = func(*StaticCommand, *base.FlagSets, *base.FlagSet) {}
extraStaticFlagsHandlingFunc = func(*StaticCommand, *[]hostsets.Option) int { return 0 }
executeExtraStaticActions = func(_ *StaticCommand, inResult api.GenericResult, inErr error, _ *hostsets.Client, _ uint32, _ []hostsets.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomStaticActionOutput = func(*StaticCommand) (bool, error) { return false, nil }
)
-151
View File
@@ -1,151 +0,0 @@
package roles
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/mitchellh/go-wordwrap"
)
func principalsGrantsSynopsisFunc(inFunc string, principals bool) string {
var in string
switchStr := "principals (users, groups)"
if !principals {
switchStr = "grants"
}
switch {
case strings.HasPrefix(inFunc, "add"):
in = fmt.Sprintf("Add %s to", switchStr)
case strings.HasPrefix(inFunc, "set"):
in = fmt.Sprintf("Set the full contents of the %s on", switchStr)
case strings.HasPrefix(inFunc, "remove"):
in = fmt.Sprintf("Remove %s from", switchStr)
}
return wordwrap.WrapString(fmt.Sprintf("%s a role", in), base.TermWidth)
}
func addPrincipalsHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary roles add-principals [options] [args]",
"",
` Adds principals (users, groups) to a role given its ID. The "principal" flag can be specified multiple times. Example:`,
"",
` $ boundary roles add-principals -id r_1234567890 -principal u_1234567890`,
})
}
func setPrincipalsHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary roles set-principals [options] [args]",
"",
` Sets the complete set of principals (users, groups) on a role given its ID. The "principal" flag can be specified multiple times. Example:`,
"",
` $ boundary roles set-principals -id r_1234567890 -principal u_anon -principal sg_1234567890`,
})
}
func removePrincipalsHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary roles remove-principals [options] [args]",
"",
` Removes principals (users, groups) from a role given its ID. The "principal" flags can be specified multiple times. Example:`,
"",
` $ boundary roles remove-principals -id r_1234567890 -principal sg_1234567890`,
})
}
func populateFlags(c *Command, f *base.FlagSet, flagNames []string) {
common.PopulateCommonFlags(c.Command, f, resource.Role.String(), flagNames)
for _, name := range flagNames {
switch name {
case "grantscopeid":
f.StringVar(&base.StringVar{
Name: "grant-scope-id",
Target: &c.flagGrantScopeId,
Usage: "The scope ID for grants set on the role",
})
case "principal":
f.StringSliceVar(&base.StringSliceVar{
Name: "principal",
Target: &c.flagPrincipals,
Usage: "The principals (users or groups) to add, remove, or set. May be specified multiple times.",
})
case "grant":
f.StringSliceVar(&base.StringSliceVar{
Name: "grant",
Target: &c.flagGrants,
Usage: "The grants to add, remove, or set. May be specified multiple times. Can be in compact string format or JSON (be sure to escape JSON properly).",
})
}
}
}
func generateRoleTableOutput(in *roles.Role) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
if in.GrantScopeId != "" {
nonAttributeMap["Grant Scope ID"] = in.GrantScopeId
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Role information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.Principals) > 0 {
ret = append(ret,
"",
fmt.Sprintf(" Principals: %s", ""),
)
}
for _, principal := range in.Principals {
ret = append(ret,
fmt.Sprintf(" ID: %s", principal.Id),
fmt.Sprintf(" Type: %s", principal.Type),
fmt.Sprintf(" Scope ID: %s", principal.ScopeId),
)
}
if len(in.Grants) > 0 {
ret = append(ret,
"",
fmt.Sprintf(" Canonical Grants: %s", ""),
)
}
for _, grant := range in.Grants {
ret = append(ret,
fmt.Sprintf(" %s", grant.Canonical),
)
}
return base.WrapForHelpText(ret)
}
-356
View File
@@ -1,356 +0,0 @@
package roles
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/perms"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
flagGrantScopeId string
flagPrincipals []string
flagGrants []string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "", "create", "update", "read", "delete", "list":
return common.SynopsisFunc(c.Func, "role")
case "add-principals", "set-principals", "remove-principals":
return principalsGrantsSynopsisFunc(c.Func, true)
case "add-grants", "set-grants", "remove-grants":
return principalsGrantsSynopsisFunc(c.Func, false)
}
return ""
}
var helpMap = func() map[string]func() string {
ret := common.HelpMap("role")
ret["add-principals"] = addPrincipalsHelp
ret["set-principals"] = setPrincipalsHelp
ret["remove-principals"] = removePrincipalsHelp
ret["add-grants"] = addPrincipalsHelp
ret["set-grants"] = setPrincipalsHelp
ret["remove-grants"] = removePrincipalsHelp
return ret
}
var flagsMap = map[string][]string{
"create": {"scope-id", "name", "description", "grantscopeid"},
"update": {"id", "name", "description", "grantscopeid", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
"add-principals": {"id", "principal", "version"},
"set-principals": {"id", "principal", "version"},
"remove-principals": {"id", "principal", "version"},
"add-grants": {"id", "grant", "version"},
"set-grants": {"id", "grant", "version"},
"remove-grants": {"id", "grant", "version"},
}
func (c *Command) Help() string {
hm := helpMap()
if c.Func == "" {
return hm["base"]()
}
return hm[c.Func]() + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
populateFlags(c, f, flagsMap[c.Func])
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []roles.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, roles.DefaultName())
default:
opts = append(opts, roles.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, roles.DefaultDescription())
default:
opts = append(opts, roles.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, roles.WithRecursive(true))
}
switch c.flagGrantScopeId {
case "":
case "null":
opts = append(opts, roles.DefaultGrantScopeId())
default:
opts = append(opts, roles.WithGrantScopeId(c.flagGrantScopeId))
}
principals := c.flagPrincipals
grants := c.flagGrants
switch c.Func {
case "add-principals", "remove-principals":
if len(c.flagPrincipals) == 0 {
c.UI.Error("No principals supplied via -principal")
return 1
}
case "add-grants", "remove-grants":
if len(c.flagGrants) == 0 {
c.UI.Error("No grants supplied via -grant")
return 1
}
case "set-principals":
switch len(c.flagPrincipals) {
case 0:
c.UI.Error("No principals supplied via -principal")
return 1
case 1:
if c.flagPrincipals[0] == "null" {
principals = nil
}
}
case "set-grants":
switch len(c.flagGrants) {
case 0:
c.UI.Error("No grants supplied via -grant")
return 1
case 1:
if c.flagGrants[0] == "null" {
grants = nil
}
}
}
if len(grants) > 0 {
for _, grant := range grants {
_, err := perms.Parse("global", grant)
if err != nil {
c.UI.Error(fmt.Errorf("Grant %q could not be parsed successfully: %w", grant, err).Error())
return 1
}
}
}
roleClient := roles.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create", "read", "delete", "list":
// These don't udpate so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = roleClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
result, err = roleClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
result, err = roleClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = roleClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = roleClient.List(c.Context, c.FlagScopeId, opts...)
case "add-principals":
result, err = roleClient.AddPrincipals(c.Context, c.FlagId, version, principals, opts...)
case "set-principals":
result, err = roleClient.SetPrincipals(c.Context, c.FlagId, version, principals, opts...)
case "remove-principals":
result, err = roleClient.RemovePrincipals(c.Context, c.FlagId, version, principals, opts...)
case "add-grants":
result, err = roleClient.AddGrants(c.Context, c.FlagId, version, grants, opts...)
case "set-grants":
result, err = roleClient.SetGrants(c.Context, c.FlagId, version, grants, opts...)
case "remove-grants":
result, err = roleClient.RemoveGrants(c.Context, c.FlagId, version, grants, opts...)
}
plural := "role"
if c.Func == "list" {
plural = "roles"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedRoles := listResult.GetItems().([]*roles.Role)
switch base.Format(c.UI) {
case "json":
if len(listedRoles) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedRoles)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedRoles) == 0 {
c.UI.Output("No roles found")
return 0
}
var output []string
output = []string{
"",
"Role information:",
}
for i, r := range listedRoles {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", r.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", r.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", r.Version),
)
}
if r.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", r.Name),
)
}
if r.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", r.Description),
)
}
if len(r.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, r.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
role := result.GetItem().(*roles.Role)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateRoleTableOutput(role))
case "json":
b, err := base.JsonFormatter{}.Format(role)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+359
View File
@@ -0,0 +1,359 @@
package rolescmd
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/perms"
"github.com/mitchellh/go-wordwrap"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
}
type extraCmdVars struct {
flagGrantScopeId string
flagPrincipals []string
flagGrants []string
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"grant-scope-id"},
"update": {"grant-scope-id"},
"add-principals": {"id", "principal", "version"},
"set-principals": {"id", "principal", "version"},
"remove-principals": {"id", "principal", "version"},
"add-grants": {"id", "grant", "version"},
"set-grants": {"id", "grant", "version"},
"remove-grants": {"id", "grant", "version"},
}
}
func extraSynopsisFuncImpl(c *Command) string {
switch c.Func {
case "add-principals", "set-principals", "remove-principals":
return c.principalsGrantsSynopsisFunc(c.Func, true)
case "add-grants", "set-grants", "remove-grants":
return c.principalsGrantsSynopsisFunc(c.Func, false)
}
return ""
}
func (c *Command) principalsGrantsSynopsisFunc(inFunc string, principals bool) string {
var in string
switchStr := "principals (users, groups)"
if !principals {
switchStr = "grants"
}
switch {
case strings.HasPrefix(inFunc, "add"):
in = fmt.Sprintf("Add %s to", switchStr)
case strings.HasPrefix(inFunc, "set"):
in = fmt.Sprintf("Set the full contents of the %s on", switchStr)
case strings.HasPrefix(inFunc, "remove"):
in = fmt.Sprintf("Remove %s from", switchStr)
}
return wordwrap.WrapString(fmt.Sprintf("%s a role", in), base.TermWidth)
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "add-principals":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles add-principals [options] [args]",
"",
` Adds principals (users, groups) to a role given its ID. The "principal" flag can be specified multiple times. Example:`,
"",
` $ boundary roles add-principals -id r_1234567890 -principal u_1234567890`,
"",
"",
})
case "set-principals":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles set-principals [options] [args]",
"",
` Sets the complete set of principals (users, groups) on a role given its ID. The "principal" flag can be specified multiple times. Example:`,
"",
` $ boundary roles set-principals -id r_1234567890 -principal u_anon -principal sg_1234567890`,
"",
"",
})
case "remove-principals":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles remove-principals [options] [args]",
"",
` Removes principals (users, groups) from a role given its ID. The "principal" flags can be specified multiple times. Example:`,
"",
` $ boundary roles remove-principals -id r_1234567890 -principal sg_1234567890`,
"",
"",
})
case "add-grants":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles add-grants [options] [args]",
"",
` Adds grants to a role given its ID. The "grant" flag can be specified multiple times. Example:`,
"",
` $ boundary roles add-grants -id r_1234567890 -grant "id=*;type=*;actions=read"`,
"",
"",
})
case "set-grants":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles set-grants [options] [args]",
"",
` Sets the complete set of grants on a role given its ID. The "grant" flag can be specified multiple times. Example:`,
"",
` $ boundary roles set-grants -id r_1234567890 -grant "id=*;type=*;actions=read" -grant "id=*;type=*;actions=list"`,
"",
"",
})
case "remove-grants":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles remove-grants [options] [args]",
"",
` Removes grants from a role given its ID. The "grant" flags can be specified multiple times. Example:`,
"",
` $ boundary roles remove-grants -id r_1234567890 -grant "id=*;type=*;actions=read"`,
"",
"",
})
default:
helpStr = helpMap["base"]()
}
return helpStr + c.Flags().Help()
}
func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "grant-scope-id":
f.StringVar(&base.StringVar{
Name: "grant-scope-id",
Target: &c.flagGrantScopeId,
Usage: "The scope ID for grants set on the role",
})
case "principal":
f.StringSliceVar(&base.StringSliceVar{
Name: "principal",
Target: &c.flagPrincipals,
Usage: "The principals (users or groups) to add, remove, or set. May be specified multiple times.",
})
case "grant":
f.StringSliceVar(&base.StringSliceVar{
Name: "grant",
Target: &c.flagGrants,
Usage: "The grants to add, remove, or set. May be specified multiple times. Can be in compact string format or JSON (be sure to escape JSON properly).",
})
}
}
}
func extraFlagsHandlingFuncImpl(c *Command, opts *[]roles.Option) int {
switch c.flagGrantScopeId {
case "":
case "null":
*opts = append(*opts, roles.DefaultGrantScopeId())
default:
*opts = append(*opts, roles.WithGrantScopeId(c.flagGrantScopeId))
}
switch c.Func {
case "add-principals", "remove-principals":
if len(c.flagPrincipals) == 0 {
c.UI.Error("No principals supplied via -principal")
return 1
}
case "add-grants", "remove-grants":
if len(c.flagGrants) == 0 {
c.UI.Error("No grants supplied via -grant")
return 1
}
case "set-principals":
switch len(c.flagPrincipals) {
case 0:
c.UI.Error("No principals supplied via -principal")
return 1
case 1:
if c.flagPrincipals[0] == "null" {
c.flagPrincipals = nil
}
}
case "set-grants":
switch len(c.flagGrants) {
case 0:
c.UI.Error("No grants supplied via -grant")
return 1
case 1:
if c.flagGrants[0] == "null" {
c.flagGrants = nil
}
}
}
if len(c.flagGrants) > 0 {
for _, grant := range c.flagGrants {
_, err := perms.Parse("global", grant)
if err != nil {
c.UI.Error(fmt.Errorf("Grant %q could not be parsed successfully: %w", grant, err).Error())
return 1
}
}
}
return 0
}
func executeExtraActionsImpl(c *Command, origResult api.GenericResult, origError error, roleClient *roles.Client, version uint32, opts []roles.Option) (api.GenericResult, error) {
switch c.Func {
case "add-principals":
return roleClient.AddPrincipals(c.Context, c.FlagId, version, c.flagPrincipals, opts...)
case "set-principals":
return roleClient.SetPrincipals(c.Context, c.FlagId, version, c.flagPrincipals, opts...)
case "remove-principals":
return roleClient.RemovePrincipals(c.Context, c.FlagId, version, c.flagPrincipals, opts...)
case "add-grants":
return roleClient.AddGrants(c.Context, c.FlagId, version, c.flagGrants, opts...)
case "set-grants":
return roleClient.SetGrants(c.Context, c.FlagId, version, c.flagGrants, opts...)
case "remove-grants":
return roleClient.RemoveGrants(c.Context, c.FlagId, version, c.flagGrants, opts...)
}
return origResult, origError
}
func (c *Command) printListTable(items []*roles.Role) string {
if len(items) == 0 {
return "No roles found"
}
var output []string
output = []string{
"",
"Role information:",
}
for i, item := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", item.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", item.Scope.Id),
)
}
if true {
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 len(item.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, item.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *roles.Role) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
if in.GrantScopeId != "" {
nonAttributeMap["Grant Scope ID"] = in.GrantScopeId
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Role information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.Principals) > 0 {
ret = append(ret,
"",
fmt.Sprintf(" Principals: %s", ""),
)
}
for _, principal := range in.Principals {
ret = append(ret,
fmt.Sprintf(" ID: %s", principal.Id),
fmt.Sprintf(" Type: %s", principal.Type),
fmt.Sprintf(" Scope ID: %s", principal.ScopeId),
)
}
if len(in.Grants) > 0 {
ret = append(ret,
"",
fmt.Sprintf(" Canonical Grants: %s", ""),
)
}
for _, grant := range in.Grants {
ret = append(ret,
fmt.Sprintf(" %s", grant.Canonical),
)
}
return base.WrapForHelpText(ret)
}
+386
View File
@@ -0,0 +1,386 @@
// Code generated by "make api"; DO NOT EDIT.
package rolescmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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
extraCmdVars
}
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 := "role"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("role")
switch c.Func {
case "create":
helpStr = helpMap[c.Func]() + c.Flags().Help()
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"read": {"id"},
"update": {"id", "name", "description", "version"},
"delete": {"id"},
"list": {"scope-id", "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, "role", flagsMap[c.Func])
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "role"
switch c.Func {
case "list":
c.plural = "roles"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []roles.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
rolesClient := roles.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, roles.DefaultName())
default:
opts = append(opts, roles.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, roles.DefaultDescription())
default:
opts = append(opts, roles.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, roles.WithRecursive(true))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "add-grants":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "remove-grants":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-grants":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "add-principals":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "remove-principals":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-principals":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = rolesClient.Create(c.Context, c.FlagScopeId, opts...)
case "read":
result, err = rolesClient.Read(c.Context, c.FlagId, opts...)
case "update":
result, err = rolesClient.Update(c.Context, c.FlagId, version, opts...)
case "delete":
_, err = rolesClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = rolesClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, rolesClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*roles.Role)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*roles.Role)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]roles.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *roles.Client, _ uint32, _ []roles.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
-63
View File
@@ -1,63 +0,0 @@
package scopes
import (
"fmt"
"sort"
"time"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateScopeTableOutput(in *scopes.Scope) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Scope information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope (parent):",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
"",
)
}
if len(in.AuthorizedCollectionActions) > 0 {
keys := make([]string, 0, len(in.AuthorizedCollectionActions))
for k := range in.AuthorizedCollectionActions {
keys = append(keys, k)
}
sort.Strings(keys)
ret = append(ret, " Authorized Actions on Scope's Collections:")
for _, key := range keys {
ret = append(ret,
fmt.Sprintf(" %s:", key),
base.WrapSlice(6, in.AuthorizedCollectionActions[key]),
)
}
}
return base.WrapForHelpText(ret)
}
-282
View File
@@ -1,282 +0,0 @@
package scopes
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
flagSkipAdminRoleCreation bool
flagSkipDefaultRoleCreation bool
}
func (c *Command) Synopsis() string {
return common.SynopsisFunc(c.Func, "scope")
}
var flagsMap = map[string][]string{
"create": {"scope-id", "name", "description", "skip-admin-role-creation", "skip-default-role-creation"},
"update": {"id", "name", "description", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("scope")
if c.Func == "" {
return helpMap["base"]()
}
return helpMap[c.Func]() + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, resource.Scope.String(), flagsMap[c.Func])
if c.Func == "create" {
f.BoolVar(&base.BoolVar{
Name: "skip-admin-role-creation",
Target: &c.flagSkipAdminRoleCreation,
Usage: "If set, a role granting the current user access to administer the newly-created scope will not automatically be created",
})
f.BoolVar(&base.BoolVar{
Name: "skip-default-role-creation",
Target: &c.flagSkipDefaultRoleCreation,
Usage: "If set, a role granting the anonymous user access to log into auth methods and a few other actions within the newly-created scope will not automatically be created",
})
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []scopes.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, scopes.DefaultName())
default:
opts = append(opts, scopes.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, scopes.DefaultDescription())
default:
opts = append(opts, scopes.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, scopes.WithRecursive(true))
}
if c.flagSkipAdminRoleCreation {
opts = append(opts, scopes.WithSkipAdminRoleCreation(c.flagSkipAdminRoleCreation))
}
if c.flagSkipDefaultRoleCreation {
opts = append(opts, scopes.WithSkipDefaultRoleCreation(c.flagSkipDefaultRoleCreation))
}
scopeClient := scopes.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create", "read", "delete", "list":
// These don't udpate so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, scopes.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = scopeClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
result, err = scopeClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
result, err = scopeClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = scopeClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = scopeClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "scope"
if c.Func == "list" {
plural = "scopes"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedScopes := listResult.GetItems().([]*scopes.Scope)
switch base.Format(c.UI) {
case "json":
if len(listedScopes) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedScopes)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedScopes) == 0 {
c.UI.Output("No child scopes found")
return 0
}
var output []string
output = []string{
"",
"Scope information:",
}
for i, s := range listedScopes {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", s.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", s.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", s.Version),
)
}
if s.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", s.Name),
)
}
if s.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", s.Description),
)
}
if len(s.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, s.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
scope := result.GetItem().(*scopes.Scope)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateScopeTableOutput(scope))
case "json":
b, err := base.JsonFormatter{}.Format(scope)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+159
View File
@@ -0,0 +1,159 @@
package scopescmd
import (
"fmt"
"sort"
"time"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"skip-admin-role-creation", "skip-default-role-creation"},
}
}
type extraCmdVars struct {
flagSkipAdminRoleCreation bool
flagSkipDefaultRoleCreation bool
}
func extraFlagsFuncImpl(c *Command, set *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "skip-admin-role-creation":
f.BoolVar(&base.BoolVar{
Name: "skip-admin-role-creation",
Target: &c.flagSkipAdminRoleCreation,
Usage: "If set, a role granting the current user access to administer the newly-created scope will not automatically be created",
})
case "skip-default-role-creation":
f.BoolVar(&base.BoolVar{
Name: "skip-default-role-creation",
Target: &c.flagSkipDefaultRoleCreation,
Usage: "If set, a role granting the anonymous user access to log into auth methods and a few other actions within the newly-created scope will not automatically be created",
})
}
}
}
func extraFlagsHandlingFuncImpl(c *Command, opts *[]scopes.Option) int {
if c.flagSkipAdminRoleCreation {
*opts = append(*opts, scopes.WithSkipAdminRoleCreation(c.flagSkipAdminRoleCreation))
}
if c.flagSkipDefaultRoleCreation {
*opts = append(*opts, scopes.WithSkipDefaultRoleCreation(c.flagSkipDefaultRoleCreation))
}
return 0
}
func (c *Command) printListTable(items []*scopes.Scope) string {
if len(items) == 0 {
return "No child scopes found"
}
var output []string
output = []string{
"",
"Scope information:",
}
for i, item := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", item.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", item.Scope.Id),
)
}
if true {
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 len(item.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, item.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *scopes.Scope) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
ret := []string{
"",
"Scope information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope (parent):",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
"",
)
}
if len(in.AuthorizedCollectionActions) > 0 {
keys := make([]string, 0, len(in.AuthorizedCollectionActions))
for k := range in.AuthorizedCollectionActions {
keys = append(keys, k)
}
sort.Strings(keys)
ret = append(ret, " Authorized Actions on Scope's Collections:")
for _, key := range keys {
ret = append(ret,
fmt.Sprintf(" %s:", key),
base.WrapSlice(6, in.AuthorizedCollectionActions[key]),
)
}
}
return base.WrapForHelpText(ret)
}
@@ -0,0 +1,336 @@
// Code generated by "make api"; DO NOT EDIT.
package scopescmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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
extraCmdVars
}
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 := "scope"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("scope")
switch c.Func {
case "create":
helpStr = helpMap[c.Func]() + c.Flags().Help()
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{
"create": {"scope-id", "name", "description"},
"read": {"id"},
"update": {"id", "name", "description", "version"},
"delete": {"id"},
"list": {"scope-id", "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, "scope", flagsMap[c.Func])
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "scope"
switch c.Func {
case "list":
c.plural = "scopes"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []scopes.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
scopesClient := scopes.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, scopes.DefaultName())
default:
opts = append(opts, scopes.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, scopes.DefaultDescription())
default:
opts = append(opts, scopes.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, scopes.WithRecursive(true))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, scopes.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = scopesClient.Create(c.Context, c.FlagScopeId, opts...)
case "read":
result, err = scopesClient.Read(c.Context, c.FlagId, opts...)
case "update":
result, err = scopesClient.Update(c.Context, c.FlagId, version, opts...)
case "delete":
_, err = scopesClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = scopesClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, scopesClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*scopes.Scope)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*scopes.Scope)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]scopes.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *scopes.Client, _ uint32, _ []scopes.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
-107
View File
@@ -1,107 +0,0 @@
package sessions
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api/sessions"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateSessionTableOutput(in *sessions.Session) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Target ID": in.TargetId,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Expiration Time": in.ExpirationTime.Local().Format(time.RFC1123),
"Version": in.Version,
"Type": in.Type,
"Auth Token ID": in.AuthTokenId,
"User ID": in.UserId,
"Host Set ID": in.HostSetId,
"Host ID": in.HostId,
"Endpoint": in.Endpoint,
"Status": in.Status,
}
if len(strings.TrimSpace(in.TerminationReason)) > 0 {
nonAttributeMap["Termination Reason"] = in.TerminationReason
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
var statesMaps []map[string]interface{}
if len(in.States) > 0 {
for _, state := range in.States {
m := map[string]interface{}{
"Status": state.Status,
"Start Time": state.StartTime.Local().Format(time.RFC1123),
}
if !state.EndTime.IsZero() {
m["End Time"] = state.EndTime.Local().Format(time.RFC1123)
}
statesMaps = append(statesMaps, m)
}
if l := len("Start Time"); l > maxLength {
maxLength = l
}
}
var workerInfoMaps []map[string]interface{}
if len(in.WorkerInfo) > 0 {
for _, wi := range in.WorkerInfo {
m := map[string]interface{}{
"Address": wi.Address,
}
workerInfoMaps = append(workerInfoMaps, m)
}
if l := len("Address"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"Session information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.States) > 0 {
ret = append(ret,
"",
" States:",
)
for _, m := range statesMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
if len(in.WorkerInfo) > 0 {
ret = append(ret,
fmt.Sprintf(" Worker Info: %s", ""),
)
for _, m := range workerInfoMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
return base.WrapForHelpText(ret)
}
-223
View File
@@ -1,223 +0,0 @@
package sessions
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/sessions"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
}
func (c *Command) Synopsis() string {
return common.SynopsisFunc(c.Func, "session")
}
var flagsMap = map[string][]string{
"read": {"id"},
"cancel": {"id"},
"list": {"scope-id", "recursive"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("session")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary sessions [sub command] [options] [args]",
"",
" This command allows operations on Boundary sessions.",
"",
" Read a session:",
"",
` $ boundary sessions read -id s_1234567890`,
"",
" Please see the sessions subcommand help for detailed usage information.",
})
case "cancel":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary sessions cancel [options] [args]",
"",
" Cancel the session specified by ID. Example:",
"",
` $ boundary sessions cancel -id s_1234567890`,
"",
"",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, resource.Session.String(), flagsMap[c.Func])
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
sessionClient := sessions.NewClient(client)
var opts []sessions.Option
switch c.FlagRecursive {
case true:
opts = append(opts, sessions.WithRecursive(true))
}
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = sessionClient.Read(c.Context, c.FlagId, opts...)
case "cancel":
result, err = sessionClient.Cancel(c.Context, c.FlagId, 0, append(opts, sessions.WithAutomaticVersioning(true))...)
case "list":
listResult, err = sessionClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "session"
if c.Func == "list" {
plural = "sessions"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "list":
listedSessions := listResult.GetItems().([]*sessions.Session)
switch base.Format(c.UI) {
case "json":
if len(listedSessions) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedSessions)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedSessions) == 0 {
c.UI.Output("No sessions found")
return 0
}
var output []string
output = []string{
"",
"Session information:",
}
for i, t := range listedSessions {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", t.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", t.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Status: %s", t.Status),
fmt.Sprintf(" Created Time: %s", t.CreatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Expiration Time: %s", t.ExpirationTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Updated Time: %s", t.UpdatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" User ID: %s", t.UserId),
fmt.Sprintf(" Target ID: %s", t.TargetId),
)
}
if len(t.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, t.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
sess := result.GetItem().(*sessions.Session)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateSessionTableOutput(sess))
case "json":
b, err := base.JsonFormatter{}.Format(sess)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+205
View File
@@ -0,0 +1,205 @@
package sessionscmd
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/sessions"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
executeExtraActions = executeExtraActionsImpl
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"cancel": {"id"},
}
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary sessions [sub command] [options] [args]",
"",
" This command allows operations on Boundary sessions.",
"",
" Read a session:",
"",
` $ boundary sessions read -id s_1234567890`,
"",
" Please see the sessions subcommand help for detailed usage information.",
})
case "cancel":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary sessions cancel [options] [args]",
"",
" Cancel the session specified by ID. If the session is already canceled, this command succeeds with no effect. Example:",
"",
` $ boundary sessions cancel -id s_1234567890`,
"",
"",
})
default:
helpStr = helpMap["base"]()
}
return helpStr + c.Flags().Help()
}
func executeExtraActionsImpl(c *Command, origResult api.GenericResult, origError error, sessionClient *sessions.Client, version uint32, opts []sessions.Option) (api.GenericResult, error) {
switch c.Func {
case "cancel":
return sessionClient.Cancel(c.Context, c.FlagId, version, opts...)
}
return origResult, origError
}
func (c *Command) printListTable(items []*sessions.Session) string {
if len(items) == 0 {
return "No sessions found"
}
var output []string
output = []string{
"",
"Session information:",
}
for i, item := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", item.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", item.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Status: %s", item.Status),
fmt.Sprintf(" Created Time: %s", item.CreatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Expiration Time: %s", item.ExpirationTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" Updated Time: %s", item.UpdatedTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" User ID: %s", item.UserId),
fmt.Sprintf(" Target ID: %s", item.TargetId),
)
}
if len(item.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, item.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *sessions.Session) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Target ID": in.TargetId,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Expiration Time": in.ExpirationTime.Local().Format(time.RFC1123),
"Version": in.Version,
"Type": in.Type,
"Auth Token ID": in.AuthTokenId,
"User ID": in.UserId,
"Host Set ID": in.HostSetId,
"Host ID": in.HostId,
"Endpoint": in.Endpoint,
"Status": in.Status,
}
if len(strings.TrimSpace(in.TerminationReason)) > 0 {
nonAttributeMap["Termination Reason"] = in.TerminationReason
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
var statesMaps []map[string]interface{}
if len(in.States) > 0 {
for _, state := range in.States {
m := map[string]interface{}{
"Status": state.Status,
"Start Time": state.StartTime.Local().Format(time.RFC1123),
}
if !state.EndTime.IsZero() {
m["End Time"] = state.EndTime.Local().Format(time.RFC1123)
}
statesMaps = append(statesMaps, m)
}
if l := len("Start Time"); l > maxLength {
maxLength = l
}
}
var workerInfoMaps []map[string]interface{}
if len(in.WorkerInfo) > 0 {
for _, wi := range in.WorkerInfo {
m := map[string]interface{}{
"Address": wi.Address,
}
workerInfoMaps = append(workerInfoMaps, m)
}
if l := len("Address"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"Session information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.States) > 0 {
ret = append(ret,
"",
" States:",
)
for _, m := range statesMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
if len(in.WorkerInfo) > 0 {
ret = append(ret,
fmt.Sprintf(" Worker Info: %s", ""),
)
for _, m := range workerInfoMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
return base.WrapForHelpText(ret)
}
@@ -0,0 +1,259 @@
// Code generated by "make api"; DO NOT EDIT.
package sessionscmd
import (
"fmt"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/sessions"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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 := "session"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("session")
switch c.Func {
case "read":
helpStr = helpMap[c.Func]() + c.Flags().Help()
case "list":
helpStr = helpMap[c.Func]() + c.Flags().Help()
default:
helpStr = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"list": {"scope-id", "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, "session", flagsMap[c.Func])
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "session"
switch c.Func {
case "list":
c.plural = "sessions"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []sessions.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
sessionsClient := sessions.NewClient(client)
switch c.FlagRecursive {
case true:
opts = append(opts, sessions.WithRecursive(true))
}
var version uint32
switch c.Func {
case "cancel":
switch c.FlagVersion {
case 0:
opts = append(opts, sessions.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = sessionsClient.Read(c.Context, c.FlagId, opts...)
case "list":
listResult, err = sessionsClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, sessionsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "list":
listedItems := listResult.GetItems().([]*sessions.Session)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*sessions.Session)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]sessions.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *sessions.Client, _ uint32, _ []sessions.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
-169
View File
@@ -1,169 +0,0 @@
package targets
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/mitchellh/go-wordwrap"
)
func hostSetSynopsisFunc(inFunc string) string {
var in string
switch {
case strings.HasPrefix(inFunc, "add"):
in = "Add host sets to"
case strings.HasPrefix(inFunc, "set"):
in = "Set the full contents of the host sets on"
case strings.HasPrefix(inFunc, "remove"):
in = "Remove host sets from"
}
return wordwrap.WrapString(fmt.Sprintf("%s a target", in), base.TermWidth)
}
func generateTargetTableOutput(in *targets.Target) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
"Session Connection Limit": in.SessionConnectionLimit,
"Session Max Seconds": in.SessionMaxSeconds,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
if in.WorkerFilter != "" {
nonAttributeMap["Worker Filter"] = in.WorkerFilter
}
maxLength := base.MaxAttributesLength(nonAttributeMap, in.Attributes, keySubstMap)
var hostSetMaps []map[string]interface{}
if len(in.HostSets) > 0 {
for _, set := range in.HostSets {
m := map[string]interface{}{
"ID": set.Id,
"Host Catalog ID": set.HostCatalogId,
}
hostSetMaps = append(hostSetMaps, m)
}
if l := len("Host Catalog ID"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"Target information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.HostSets) > 0 {
ret = append(ret,
"",
" Host Sets:",
)
for _, m := range hostSetMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
if len(in.Attributes) > 0 {
ret = append(ret,
" Attributes:",
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
func generateAuthorizationTableOutput(in *targets.SessionAuthorization) string {
var ret []string
nonAttributeMap := map[string]interface{}{
"Session ID": in.SessionId,
"Target ID": in.TargetId,
"Scope ID": in.Scope.Id,
"User ID": in.UserId,
"Host ID": in.HostId,
"Endpoint": in.Endpoint,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Type": in.Type,
"Authorization Token": in.AuthorizationToken,
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
ret = append(ret, "", "Target information:")
ret = append(ret,
// We do +2 because there is another +2 offset for host sets below
base.WrapMap(2, maxLength+2, nonAttributeMap),
)
return base.WrapForHelpText(ret)
}
var keySubstMap = map[string]string{
"default_port": "Default Port",
}
func exampleOutput() string {
in := &targets.Target{
Id: "ttcp_1234567890",
ScopeId: "global",
Scope: &scopes.ScopeInfo{
Id: "global",
},
Name: "foo",
Description: "The bar of foos",
CreatedTime: time.Now().Add(-5 * time.Minute),
UpdatedTime: time.Now(),
Version: 3,
Type: "tcp",
HostSetIds: []string{"hsst_1234567890", "hsst_0987654321"},
HostSets: []*targets.HostSet{
{
Id: "hsst_1234567890",
HostCatalogId: "hcst_1234567890",
},
{
Id: "hsst_0987654321",
HostCatalogId: "hcst_1234567890",
},
},
Attributes: map[string]interface{}{
"default_port": 22,
},
}
return generateTargetTableOutput(in)
}
-498
View File
@@ -1,498 +0,0 @@
package targets
import (
"fmt"
"net/http"
"os"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
flagHostSets []string
flagHostId string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "add-host-sets", "set-host-sets", "remove-host-sets":
return hostSetSynopsisFunc(c.Func)
case "authorize-session":
return "Request session authorization against the target"
default:
return common.SynopsisFunc(c.Func, "target")
}
}
var flagsMap = map[string][]string{
"authorize-session": {"id", "host-id"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
"add-host-sets": {"id", "host-set", "version"},
"remove-host-sets": {"id", "host-set", "version"},
"set-host-sets": {"id", "host-set", "version"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("target")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary targets [sub command] [options] [args]",
"",
" This command allows operations on Boundary target resources. Example:",
"",
" Read a target:",
"",
` $ boundary targets read -id ttcp_1234567890`,
"",
" Please see the targets subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary target resources. Example:",
"",
" Create a tcp-type target:",
"",
` $ boundary targets create tcp -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary target resources. Example:",
"",
" Update a tcp-type target:",
"",
` $ boundary targets update tcp -id ttcp_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "add-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target add-host-sets [options] [args]",
"",
" This command allows adding host-set resources to target resources. Example:",
"",
" Add host-set resources to a tcp-type target:",
"",
` $ boundary targets add-host-sets -id ttcp_1234567890 -host-set hsst_1234567890 -host-set hsst_0987654321`,
"",
"",
})
case "remove-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target remove-host-sets [options] [args]",
"",
" This command allows removing host-set resources from target resources. Example:",
"",
" Remove host-set resources from a tcp-type target:",
"",
` $ boundary targets add-host-sets -id ttcp_1234567890 -host hsst_1234567890 -host-set hsst_0987654321`,
"",
"",
})
case "set-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target set-host-sets [options] [args]",
"",
" This command allows setting the complete set of host-set resources on a target resource. Example:",
"",
" Set host-set resources on a tcp-type target:",
"",
` $ boundary targets set-host-sets -id ttcp_1234567890 -host-set hsst_1234567890`,
"",
"",
})
case "authorize-session":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target authorize-session [options] [args]",
"",
" This command allows fetching session authorization credentials against a target. Example:",
"",
" Request an authorized session using the target ID:",
"",
` $ boundary targets authorize-session -id ttcp_1234567890`,
"",
" Request an authorized session using the scope ID and target name:",
"",
` $ boundary targets authorize-session -scope-id o_1234567890 -name prod-ssh`,
"",
"",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
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, resource.Target.String(), flagsMap[c.Func])
for _, name := range flagsMap[c.Func] {
switch name {
case "host-set":
f.StringSliceVar(&base.StringSliceVar{
Name: "host-set",
Target: &c.flagHostSets,
Usage: "The host-set resources to add, remove, or set. May be specified multiple times.",
})
case "host-id":
f.StringVar(&base.StringVar{
Name: "host-id",
Target: &c.flagHostId,
Usage: "The ID of a specific host to connect to out of the hosts from the target's host sets. If not specified, one is chosen at random.",
})
}
}
if c.Func == "authorize-session" {
flagsMap[c.Func] = append(flagsMap[c.Func], "name", "scope-id", "scope-name")
// We put these here to change usage and change defaults (don't want
// them populated by default)
f.StringVar(&base.StringVar{
Name: "name",
Target: &c.FlagName,
Usage: "Target name, if authorizing the session via scope parameters and target name.",
})
f.StringVar(&base.StringVar{
Name: "scope-id",
Target: &c.FlagScopeId,
EnvVar: "BOUNDARY_SCOPE_ID",
Completion: complete.PredictAnything,
Usage: "Target scope ID, if authorizing the session via scope parameters and target name. Mutually exclusive with -scope-name.",
})
f.StringVar(&base.StringVar{
Name: "scope-name",
Target: &c.FlagScopeName,
EnvVar: "BOUNDARY_SCOPE_NAME",
Completion: complete.PredictAnything,
Usage: "Target scope name, if authorizing the session via scope parameters and target name. Mutually exclusive with -scope-id.",
})
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if os.Getenv("BOUNDARY_EXAMPLE_CLI_OUTPUT") != "" {
c.UI.Output(exampleOutput())
return 0
}
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
var opts []targets.Option
if strutil.StrListContains(flagsMap[c.Func], "id") {
switch c.Func {
case "authorize-session":
if c.FlagId == "" &&
(c.FlagName == "" ||
(c.FlagScopeId == "" && c.FlagScopeName == "")) {
c.UI.Error("ID was not passed in, but no combination of name and scope ID/name was passed in either")
return 1
}
if c.FlagId != "" &&
(c.FlagName != "" || c.FlagScopeId != "" || c.FlagScopeName != "") {
c.UI.Error("Cannot specify a target ID and also other lookup parameters")
return 1
}
default:
if c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
}
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
default:
if c.FlagScopeId != "" {
opts = append(opts, targets.WithScopeId(c.FlagScopeId))
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
switch c.FlagName {
case "":
case "null":
opts = append(opts, targets.DefaultName())
default:
opts = append(opts, targets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, targets.DefaultDescription())
default:
opts = append(opts, targets.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, targets.WithRecursive(true))
}
switch c.FlagScopeName {
case "":
default:
opts = append(opts, targets.WithScopeName(c.FlagScopeName))
}
hostSets := c.flagHostSets
switch c.Func {
case "add-host-sets", "remove-host-sets":
if len(c.flagHostSets) == 0 {
c.UI.Error("No host-sets supplied via -host-set")
return 1
}
case "set-host-sets":
switch len(c.flagHostSets) {
case 0:
c.UI.Error("No host-sets supplied via -host-set")
return 1
case 1:
if c.flagHostSets[0] == "null" {
hostSets = nil
}
}
case "authorize-session":
if len(c.flagHostId) != 0 {
opts = append(opts, targets.WithHostId(c.flagHostId))
}
}
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "add-host-sets", "remove-host-sets", "set-host-sets":
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
default:
// The only other one that needs it is update, handled by the static
// file
}
targetClient := targets.NewClient(client)
existed := true
var result api.GenericResult
var listResult api.GenericListResult
var sar *targets.SessionAuthorizationResult
switch c.Func {
case "read":
result, err = targetClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = targetClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = targetClient.List(c.Context, c.FlagScopeId, opts...)
case "add-host-sets":
result, err = targetClient.AddHostSets(c.Context, c.FlagId, version, hostSets, opts...)
case "remove-host-sets":
result, err = targetClient.RemoveHostSets(c.Context, c.FlagId, version, hostSets, opts...)
case "set-host-sets":
result, err = targetClient.SetHostSets(c.Context, c.FlagId, version, hostSets, opts...)
case "authorize-session":
sar, err = targetClient.AuthorizeSession(c.Context, c.FlagId, opts...)
}
plural := "target"
switch c.Func {
case "list":
plural = "targets"
case "authorize-session":
plural = "a session against target"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedTargets := listResult.GetItems().([]*targets.Target)
switch base.Format(c.UI) {
case "json":
if len(listedTargets) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedTargets)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedTargets) == 0 {
c.UI.Output("No targets found")
return 0
}
var output []string
output = []string{
"",
"Target information:",
}
for i, m := range listedTargets {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", m.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
case "authorize-session":
sa := sar.GetItem().(*targets.SessionAuthorization)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAuthorizationTableOutput(sa))
case "json":
b, err := base.JsonFormatter{}.Format(sa)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
target := result.GetItem().(*targets.Target)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateTargetTableOutput(target))
case "json":
b, err := base.JsonFormatter{}.Format(target)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
-268
View File
@@ -1,268 +0,0 @@
package targets
import (
"fmt"
"net/textproto"
"strconv"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/hashicorp/go-bexpr"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*TcpCommand)(nil)
_ cli.CommandAutocomplete = (*TcpCommand)(nil)
)
type TcpCommand struct {
*base.Command
Func string
flagDefaultPort string
flagSessionMaxSeconds string
flagSessionConnectionLimit string
flagWorkerFilter string
}
func (c *TcpCommand) Synopsis() string {
return fmt.Sprintf("%s a tcp-type target", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var tcpFlagsMap = map[string][]string{
"create": {"scope-id", "name", "description", "default-port", "session-max-seconds", "session-connection-limit", "worker-filter"},
"update": {"id", "name", "description", "version", "default-port", "session-max-seconds", "session-connection-limit", "worker-filter"},
}
func (c *TcpCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary targets create tcp [options] [args]",
"",
" Create a tcp-type target. Example:",
"",
` $ boundary targets create tcp -name prodops -description "Tcp target for ProdOps"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary targets tcp update [options] [args]",
"",
" Update a tcp-type target given its ID. Example:",
"",
` $ boundary targets tcp update -id ttcp_1234567890 -name "devops" -description "Tcp target for DevOps"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *TcpCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "tcp-type target", tcpFlagsMap[c.Func])
for _, name := range tcpFlagsMap[c.Func] {
switch name {
case "default-port":
f.StringVar(&base.StringVar{
Name: "default-port",
Target: &c.flagDefaultPort,
Usage: "The default port to set on the target.",
})
case "session-max-seconds":
f.StringVar(&base.StringVar{
Name: "session-max-seconds",
Target: &c.flagSessionMaxSeconds,
Usage: `The maximum lifetime of the session, including all connections. Can be specified as an integer number of seconds or a duration string.`,
})
case "session-connection-limit":
f.StringVar(&base.StringVar{
Name: "session-connection-limit",
Target: &c.flagSessionConnectionLimit,
Usage: "The maximum number of connections allowed for a session. -1 means unlimited.",
})
case "worker-filter":
f.StringVar(&base.StringVar{
Name: "worker-filter",
Target: &c.flagWorkerFilter,
Usage: "A boolean expression to filter which workers can handle sessions for this target.",
})
}
}
return set
}
func (c *TcpCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *TcpCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *TcpCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(tcpFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(tcpFlagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []targets.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, targets.DefaultName())
default:
opts = append(opts, targets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, targets.DefaultDescription())
default:
opts = append(opts, targets.WithDescription(c.FlagDescription))
}
switch c.flagDefaultPort {
case "":
case "null":
opts = append(opts, targets.DefaultTcpTargetDefaultPort())
default:
port, err := strconv.ParseUint(c.flagDefaultPort, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagDefaultPort, err))
return 1
}
opts = append(opts, targets.WithTcpTargetDefaultPort(uint32(port)))
}
switch c.flagSessionMaxSeconds {
case "":
case "null":
opts = append(opts, targets.DefaultSessionMaxSeconds())
default:
var final uint32
dur, err := strconv.ParseUint(c.flagSessionMaxSeconds, 10, 32)
if err == nil {
final = uint32(dur)
} else {
dur, err := time.ParseDuration(c.flagSessionMaxSeconds)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagSessionMaxSeconds, err))
return 1
}
final = uint32(dur.Seconds())
}
opts = append(opts, targets.WithSessionMaxSeconds(final))
}
switch c.flagSessionConnectionLimit {
case "":
case "null":
opts = append(opts, targets.DefaultSessionConnectionLimit())
default:
limit, err := strconv.ParseInt(c.flagSessionConnectionLimit, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagSessionConnectionLimit, err))
return 1
}
opts = append(opts, targets.WithSessionConnectionLimit(int32(limit)))
}
switch c.flagWorkerFilter {
case "":
case "null":
opts = append(opts, targets.DefaultWorkerFilter())
default:
if _, err := bexpr.CreateEvaluator(c.flagWorkerFilter); err != nil {
c.UI.Error(fmt.Sprintf("Unable to successfully parse filter expression: %s", err))
return 1
}
opts = append(opts, targets.WithWorkerFilter(c.flagWorkerFilter))
}
targetClient := targets.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = targetClient.Create(c.Context, "tcp", c.FlagScopeId, opts...)
case "update":
result, err = targetClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "tcp-type target"
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
target := result.GetItem().(*targets.Target)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateTargetTableOutput(target))
case "json":
b, err := base.JsonFormatter{}.Format(target)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+492
View File
@@ -0,0 +1,492 @@
package targetscmd
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/go-wordwrap"
"github.com/posener/complete"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
printCustomActionOutput = printCustomActionOutputImpl
}
type extraCmdVars struct {
flagHostSets []string
flagHostId string
sar *targets.SessionAuthorizationResult
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"authorize-session": {"id", "host-id"},
"add-host-sets": {"id", "host-set", "version"},
"remove-host-sets": {"id", "host-set", "version"},
"set-host-sets": {"id", "host-set", "version"},
}
}
func extraSynopsisFuncImpl(c *Command) string {
switch c.Func {
case "add-host-sets", "set-host-sets", "remove-host-sets":
var in string
switch {
case strings.HasPrefix(c.Func, "add"):
in = "Add host sets to"
case strings.HasPrefix(c.Func, "set"):
in = "Set the full contents of the host sets on"
case strings.HasPrefix(c.Func, "remove"):
in = "Remove host sets from"
}
return wordwrap.WrapString(fmt.Sprintf("%s a target", in), base.TermWidth)
case "authorize-session":
return "Request session authorization against the target"
default:
return ""
}
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary targets [sub command] [options] [args]",
"",
" This command allows operations on Boundary target resources. Example:",
"",
" Read a target:",
"",
` $ boundary targets read -id ttcp_1234567890`,
"",
" Please see the targets subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary target resources. Example:",
"",
" Create a tcp-type target:",
"",
` $ boundary targets create tcp -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary target resources. Example:",
"",
" Update a tcp-type target:",
"",
` $ boundary targets update tcp -id ttcp_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "add-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target add-host-sets [options] [args]",
"",
" This command allows adding host-set resources to target resources. Example:",
"",
" Add host-set resources to a tcp-type target:",
"",
` $ boundary targets add-host-sets -id ttcp_1234567890 -host-set hsst_1234567890 -host-set hsst_0987654321`,
"",
"",
})
case "remove-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target remove-host-sets [options] [args]",
"",
" This command allows removing host-set resources from target resources. Example:",
"",
" Remove host-set resources from a tcp-type target:",
"",
` $ boundary targets add-host-sets -id ttcp_1234567890 -host hsst_1234567890 -host-set hsst_0987654321`,
"",
"",
})
case "set-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target set-host-sets [options] [args]",
"",
" This command allows setting the complete set of host-set resources on a target resource. Example:",
"",
" Set host-set resources on a tcp-type target:",
"",
` $ boundary targets set-host-sets -id ttcp_1234567890 -host-set hsst_1234567890`,
"",
"",
})
case "authorize-session":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target authorize-session [options] [args]",
"",
" This command allows fetching session authorization credentials against a target. Example:",
"",
" Request an authorized session using the target ID:",
"",
` $ boundary targets authorize-session -id ttcp_1234567890`,
"",
" Request an authorized session using the scope ID and target name:",
"",
` $ boundary targets authorize-session -scope-id o_1234567890 -name prod-ssh`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "host-set":
f.StringSliceVar(&base.StringSliceVar{
Name: "host-set",
Target: &c.flagHostSets,
Usage: "The host-set resources to add, remove, or set. May be specified multiple times.",
})
case "host-id":
f.StringVar(&base.StringVar{
Name: "host-id",
Target: &c.flagHostId,
Usage: "The ID of a specific host to connect to out of the hosts from the target's host sets. If not specified, one is chosen at random.",
})
}
}
if c.Func == "authorize-session" {
flagsMap[c.Func] = append(flagsMap[c.Func], "name", "scope-id", "scope-name")
// We put these here to change usage and change defaults (don't want
// them populated by default). Otherwise the common flags function will
// populate these values, and they can't be changed after-the-fact.
f.StringVar(&base.StringVar{
Name: "name",
Target: &c.FlagName,
Usage: "Target name, if authorizing the session via scope parameters and target name.",
})
f.StringVar(&base.StringVar{
Name: "scope-id",
Target: &c.FlagScopeId,
EnvVar: "BOUNDARY_SCOPE_ID",
Completion: complete.PredictAnything,
Usage: "Target scope ID, if authorizing the session via scope parameters and target name. Mutually exclusive with -scope-name.",
})
f.StringVar(&base.StringVar{
Name: "scope-name",
Target: &c.FlagScopeName,
EnvVar: "BOUNDARY_SCOPE_NAME",
Completion: complete.PredictAnything,
Usage: "Target scope name, if authorizing the session via scope parameters and target name. Mutually exclusive with -scope-id.",
})
}
}
func extraFlagsHandlingFuncImpl(c *Command, opts *[]targets.Option) int {
// This is custom logic because of the authorized-session handling. If we
// support all resources to be looked up by name + scope info we can
// eventually graduate this out to the main template.
if strutil.StrListContains(flagsMap[c.Func], "id") {
switch c.Func {
case "authorize-session":
if c.FlagId == "" &&
(c.FlagName == "" ||
(c.FlagScopeId == "" && c.FlagScopeName == "")) {
c.UI.Error("ID was not passed in, but no combination of name and scope ID/name was passed in either")
return 1
}
if c.FlagId != "" &&
(c.FlagName != "" || c.FlagScopeId != "" || c.FlagScopeName != "") {
c.UI.Error("Cannot specify a target ID and also other lookup parameters")
return 1
}
default:
if c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
}
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId != "" {
*opts = append(*opts, targets.WithScopeId(c.FlagScopeId))
}
switch c.Func {
case "add-host-sets", "remove-host-sets":
if len(c.flagHostSets) == 0 {
c.UI.Error("No host-sets supplied via -host-set")
return 1
}
case "set-host-sets":
switch len(c.flagHostSets) {
case 0:
c.UI.Error("No host-sets supplied via -host-set")
return 1
case 1:
if c.flagHostSets[0] == "null" {
c.flagHostSets = nil
}
}
case "authorize-session":
if len(c.flagHostId) != 0 {
*opts = append(*opts, targets.WithHostId(c.flagHostId))
}
}
return 0
}
func executeExtraActionsImpl(c *Command, origResult api.GenericResult, origError error, targetClient *targets.Client, version uint32, opts []targets.Option) (api.GenericResult, error) {
switch c.Func {
case "add-host-sets":
return targetClient.AddHostSets(c.Context, c.FlagId, version, c.flagHostSets, opts...)
case "remove-host-sets":
return targetClient.RemoveHostSets(c.Context, c.FlagId, version, c.flagHostSets, opts...)
case "set-host-sets":
return targetClient.SetHostSets(c.Context, c.FlagId, version, c.flagHostSets, opts...)
case "authorize-session":
var err error
c.plural = "a session against target"
c.sar, err = targetClient.AuthorizeSession(c.Context, c.FlagId, opts...)
return nil, err
}
return origResult, origError
}
func (c *Command) printListTable(items []*targets.Target) string {
if len(items) == 0 {
return "No targets found"
}
var output []string
output = []string{
"",
"Target information:",
}
for i, m := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", m.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
if len(m.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, m.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(item *targets.Target) string {
nonAttributeMap := map[string]interface{}{
"ID": item.Id,
"Version": item.Version,
"Type": item.Type,
"Created Time": item.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": item.UpdatedTime.Local().Format(time.RFC1123),
"Session Connection Limit": item.SessionConnectionLimit,
"Session Max Seconds": item.SessionMaxSeconds,
}
if item.Name != "" {
nonAttributeMap["Name"] = item.Name
}
if item.Description != "" {
nonAttributeMap["Description"] = item.Description
}
if item.WorkerFilter != "" {
nonAttributeMap["Worker Filter"] = item.WorkerFilter
}
maxLength := base.MaxAttributesLength(nonAttributeMap, item.Attributes, keySubstMap)
var hostSetMaps []map[string]interface{}
if len(item.HostSets) > 0 {
for _, set := range item.HostSets {
m := map[string]interface{}{
"ID": set.Id,
"Host Catalog ID": set.HostCatalogId,
}
hostSetMaps = append(hostSetMaps, m)
}
if l := len("Host Catalog ID"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"Target information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(item.Scope, maxLength),
}
if len(item.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, item.AuthorizedActions),
)
}
ret = append(ret,
"",
)
if len(item.HostSets) > 0 {
ret = append(ret,
" Host Sets:",
)
for _, m := range hostSetMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
if len(item.Attributes) > 0 {
ret = append(ret,
" Attributes:",
base.WrapMap(4, maxLength, item.Attributes),
)
}
return base.WrapForHelpText(ret)
}
func printCustomActionOutputImpl(c *Command) (bool, error) {
switch c.Func {
case "authorize-session":
item := c.sar.GetItem().(*targets.SessionAuthorization)
switch base.Format(c.UI) {
case "table":
var ret []string
nonAttributeMap := map[string]interface{}{
"Session ID": item.SessionId,
"Target ID": item.TargetId,
"Scope ID": item.Scope.Id,
"User ID": item.UserId,
"Host ID": item.HostId,
"Endpoint": item.Endpoint,
"Created Time": item.CreatedTime.Local().Format(time.RFC1123),
"Type": item.Type,
"Authorization Token": item.AuthorizationToken,
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
ret = append(ret, "", "Target information:")
ret = append(ret,
// We do +2 because there is another +2 offset for host sets below
base.WrapMap(2, maxLength+2, nonAttributeMap),
)
c.UI.Output(base.WrapForHelpText(ret))
return true, nil
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
return false, fmt.Errorf("Error formatting as JSON: %w", err)
}
c.UI.Output(string(b))
return true, nil
}
}
return false, nil
}
var keySubstMap = map[string]string{
"default_port": "Default Port",
}
func exampleOutput() string {
in := &targets.Target{
Id: "ttcp_1234567890",
ScopeId: "global",
Scope: &scopes.ScopeInfo{
Id: "global",
},
Name: "foo",
Description: "The bar of foos",
CreatedTime: time.Now().Add(-5 * time.Minute),
UpdatedTime: time.Now(),
Version: 3,
Type: "tcp",
HostSetIds: []string{"hsst_1234567890", "hsst_0987654321"},
HostSets: []*targets.HostSet{
{
Id: "hsst_1234567890",
HostCatalogId: "hcst_1234567890",
},
{
Id: "hsst_0987654321",
HostCatalogId: "hcst_1234567890",
},
},
Attributes: map[string]interface{}{
"default_port": 22,
},
}
return printItemTable(in)
}
@@ -0,0 +1,335 @@
// Code generated by "make api"; DO NOT EDIT.
package targetscmd
import (
"fmt"
"net/http"
"os"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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
extraCmdVars
}
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 := "target"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("target")
switch c.Func {
case "read":
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "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, "target", flagsMap[c.Func])
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
if os.Getenv("BOUNDARY_EXAMPLE_CLI_OUTPUT") != "" {
c.UI.Output(exampleOutput())
return 0
}
switch c.Func {
case "":
return cli.RunResultHelp
case "create", "update":
return cli.RunResultHelp
}
c.plural = "target"
switch c.Func {
case "list":
c.plural = "targets"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
var opts []targets.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
targetsClient := targets.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, targets.DefaultName())
default:
opts = append(opts, targets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, targets.DefaultDescription())
default:
opts = append(opts, targets.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, targets.WithRecursive(true))
}
var version uint32
switch c.Func {
case "add-host-sets":
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "remove-host-sets":
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-host-sets":
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "read":
result, err = targetsClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = targetsClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = targetsClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, targetsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*targets.Target)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*targets.Target)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]targets.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *targets.Client, _ uint32, _ []targets.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
@@ -0,0 +1,154 @@
package targetscmd
import (
"fmt"
"strconv"
"time"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/go-bexpr"
)
func init() {
extraTcpActionsFlagsMapFunc = extraTcpActionsFlagsMapFuncImpl
extraTcpFlagsFunc = extraTcpFlagsFuncImpl
extraTcpFlagsHandlingFunc = extraTcpFlagsHandlingFuncImpl
}
func extraTcpActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"default-port", "session-max-seconds", "session-connection-limit", "worker-filter"},
"update": {"default-port", "session-max-seconds", "session-connection-limit", "worker-filter"},
}
}
type extraTcpCmdVars struct {
flagDefaultPort string
flagSessionMaxSeconds string
flagSessionConnectionLimit string
flagWorkerFilter string
}
func (c *TcpCommand) extraTcpHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets create tcp [options] [args]",
"",
" Create a tcp-type target. Example:",
"",
` $ boundary targets create tcp -name prodops -description "Tcp target for ProdOps"`,
"",
"",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets tcp update [options] [args]",
"",
" Update a tcp-type target given its ID. Example:",
"",
` $ boundary targets tcp update -id ttcp_1234567890 -name "devops" -description "Tcp target for DevOps"`,
"",
"",
})
}
return helpStr + c.Flags().Help()
}
func extraTcpFlagsFuncImpl(c *TcpCommand, set *base.FlagSets, f *base.FlagSet) {
f = set.NewFlagSet("TCP Target Options")
for _, name := range flagsTcpMap[c.Func] {
switch name {
case "default-port":
f.StringVar(&base.StringVar{
Name: "default-port",
Target: &c.flagDefaultPort,
Usage: "The default port to set on the target.",
})
case "session-max-seconds":
f.StringVar(&base.StringVar{
Name: "session-max-seconds",
Target: &c.flagSessionMaxSeconds,
Usage: `The maximum lifetime of the session, including all connections. Can be specified as an integer number of seconds or a duration string.`,
})
case "session-connection-limit":
f.StringVar(&base.StringVar{
Name: "session-connection-limit",
Target: &c.flagSessionConnectionLimit,
Usage: "The maximum number of connections allowed for a session. -1 means unlimited.",
})
case "worker-filter":
f.StringVar(&base.StringVar{
Name: "worker-filter",
Target: &c.flagWorkerFilter,
Usage: "A boolean expression to filter which workers can handle sessions for this target.",
})
}
}
}
func extraTcpFlagsHandlingFuncImpl(c *TcpCommand, opts *[]targets.Option) int {
switch c.flagDefaultPort {
case "":
case "null":
*opts = append(*opts, targets.DefaultTcpTargetDefaultPort())
default:
port, err := strconv.ParseUint(c.flagDefaultPort, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagDefaultPort, err))
return 1
}
*opts = append(*opts, targets.WithTcpTargetDefaultPort(uint32(port)))
}
switch c.flagSessionMaxSeconds {
case "":
case "null":
*opts = append(*opts, targets.DefaultSessionMaxSeconds())
default:
var final uint32
dur, err := strconv.ParseUint(c.flagSessionMaxSeconds, 10, 32)
if err == nil {
final = uint32(dur)
} else {
dur, err := time.ParseDuration(c.flagSessionMaxSeconds)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagSessionMaxSeconds, err))
return 1
}
final = uint32(dur.Seconds())
}
*opts = append(*opts, targets.WithSessionMaxSeconds(final))
}
switch c.flagSessionConnectionLimit {
case "":
case "null":
*opts = append(*opts, targets.DefaultSessionConnectionLimit())
default:
limit, err := strconv.ParseInt(c.flagSessionConnectionLimit, 10, 32)
if err != nil {
c.UI.Error(fmt.Sprintf("Error parsing %q: %s", c.flagSessionConnectionLimit, err))
return 1
}
*opts = append(*opts, targets.WithSessionConnectionLimit(int32(limit)))
}
switch c.flagWorkerFilter {
case "":
case "null":
*opts = append(*opts, targets.DefaultWorkerFilter())
default:
if _, err := bexpr.CreateEvaluator(c.flagWorkerFilter); err != nil {
c.UI.Error(fmt.Sprintf("Unable to successfully parse filter expression: %s", err))
return 1
}
*opts = append(*opts, targets.WithWorkerFilter(c.flagWorkerFilter))
}
return 0
}
@@ -0,0 +1,243 @@
// Code generated by "make api"; DO NOT EDIT.
package targetscmd
import (
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func initTcpFlags() {
flagsOnce.Do(func() {
extraFlags := extraTcpActionsFlagsMapFunc()
for k, v := range extraFlags {
flagsTcpMap[k] = append(flagsTcpMap[k], v...)
}
})
}
var (
_ cli.Command = (*TcpCommand)(nil)
_ cli.CommandAutocomplete = (*TcpCommand)(nil)
)
type TcpCommand struct {
*base.Command
Func string
plural string
extraTcpCmdVars
}
func (c *TcpCommand) AutocompleteArgs() complete.Predictor {
initTcpFlags()
return complete.PredictAnything
}
func (c *TcpCommand) AutocompleteFlags() complete.Flags {
initTcpFlags()
return c.Flags().Completions()
}
func (c *TcpCommand) Synopsis() string {
if extra := extraTcpSynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "target"
synopsisStr = fmt.Sprintf("%s %s", "tcp-type", synopsisStr)
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *TcpCommand) Help() string {
initTcpFlags()
var helpStr string
helpMap := common.HelpMap("target")
switch c.Func {
default:
helpStr = c.extraTcpHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsTcpMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *TcpCommand) Flags() *base.FlagSets {
if len(flagsTcpMap[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, "tcp-type target", flagsTcpMap[c.Func])
extraTcpFlagsFunc(c, set, f)
return set
}
func (c *TcpCommand) Run(args []string) int {
initTcpFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "tcp-type target"
switch c.Func {
case "list":
c.plural = "tcp-type targets"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsTcpMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []targets.Option
if strutil.StrListContains(flagsTcpMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
targetsClient := targets.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, targets.DefaultName())
default:
opts = append(opts, targets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, targets.DefaultDescription())
default:
opts = append(opts, targets.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, targets.WithRecursive(true))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraTcpFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
var result api.GenericResult
switch c.Func {
case "create":
result, err = targetsClient.Create(c.Context, "tcp", c.FlagScopeId, opts...)
case "update":
result, err = targetsClient.Update(c.Context, c.FlagId, version, opts...)
}
result, err = executeExtraTcpActions(c, result, err, targetsClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomTcpActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
}
item := result.GetItem().(*targets.Target)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
var (
extraTcpActionsFlagsMapFunc = func() map[string][]string { return nil }
extraTcpSynopsisFunc = func(*TcpCommand) string { return "" }
extraTcpFlagsFunc = func(*TcpCommand, *base.FlagSets, *base.FlagSet) {}
extraTcpFlagsHandlingFunc = func(*TcpCommand, *[]targets.Option) int { return 0 }
executeExtraTcpActions = func(_ *TcpCommand, inResult api.GenericResult, inErr error, _ *targets.Client, _ uint32, _ []targets.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomTcpActionOutput = func(*TcpCommand) (bool, error) { return false, nil }
)
-135
View File
@@ -1,135 +0,0 @@
package users
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api/users"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/mitchellh/go-wordwrap"
)
func accountSynopsisFunc(inFunc string) string {
var in string
switch {
case strings.HasPrefix(inFunc, "add"):
in = "Add accounts to"
case strings.HasPrefix(inFunc, "set"):
in = "Set the full contents of the accounts on"
case strings.HasPrefix(inFunc, "remove"):
in = "Remove accounts from"
}
return wordwrap.WrapString(fmt.Sprintf("%s a user within Boundary", in), base.TermWidth)
}
func addAccountsHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary users add-accounts [options] [args]",
"",
` Associates accounts to a user given its ID. The "account" flag can be specified multiple times. Example:`,
"",
` $ boundary users add-accounts -id u_1234567890 -account a_1234567890`,
})
}
func setAccountsHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary users set-accounts [options] [args]",
"",
` Sets the complete set of associated accounts on a user given its ID. The "account" flag can be specified multiple times. Example:`,
"",
` $ boundary users set-principals -id u_1234567890 -account a_0987654321 -account a_1234567890`,
})
}
func removeAccountsHelp() string {
return base.WrapForHelpText([]string{
"Usage: boundary users remove-accounts [options] [args]",
"",
` Disassociates accounts from a user given its ID. The "account" flag can be specified multiple times. Example:`,
"",
` $ boundary users remove-accounts -id u_1234567890 -account a_1234567890`,
})
}
func populateFlags(c *Command, f *base.FlagSet, flagNames []string) {
common.PopulateCommonFlags(c.Command, f, resource.User.String(), flagNames)
for _, name := range flagNames {
switch name {
case "account":
f.StringSliceVar(&base.StringSliceVar{
Name: "account",
Target: &c.flagAccounts,
Usage: "The accounts to add, remove, or set. May be specified multiple times.",
})
}
}
}
func generateUserTableOutput(in *users.User) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
var userMaps []map[string]interface{}
if len(in.Accounts) > 0 {
for _, account := range in.Accounts {
a := map[string]interface{}{
"ID": account.Id,
"Scope ID": account.ScopeId,
}
userMaps = append(userMaps, a)
}
if l := len("Scope ID"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"User information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.Accounts) > 0 {
ret = append(ret,
"",
" Accounts:",
)
for _, m := range userMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
return base.WrapForHelpText(ret)
}
-302
View File
@@ -1,302 +0,0 @@
package users
import (
"fmt"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/users"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var (
_ cli.Command = (*Command)(nil)
_ cli.CommandAutocomplete = (*Command)(nil)
)
type Command struct {
*base.Command
Func string
flagAccounts []string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "add-accounts", "set-accounts", "remove-accounts":
return accountSynopsisFunc(c.Func)
default:
return common.SynopsisFunc(c.Func, "user")
}
}
var helpMap = func() map[string]func() string {
ret := common.HelpMap("user")
ret["add-accounts"] = addAccountsHelp
ret["set-accounts"] = setAccountsHelp
ret["remove-accounts"] = removeAccountsHelp
return ret
}
var flagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id", "recursive"},
"add-accounts": {"id", "account", "version"},
"set-accounts": {"id", "account", "version"},
"remove-accounts": {"id", "account", "version"},
}
func (c *Command) Help() string {
hm := helpMap()
if c.Func == "" {
return hm["base"]()
}
return hm[c.Func]() + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
populateFlags(c, f, flagsMap[c.Func])
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []users.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, users.DefaultName())
default:
opts = append(opts, users.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, users.DefaultDescription())
default:
opts = append(opts, users.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, users.WithRecursive(true))
}
accounts := c.flagAccounts
switch c.Func {
case "add-accounts", "remove-accounts":
if len(c.flagAccounts) == 0 {
c.UI.Error("No accounts supplied via -account")
return 1
}
case "set-accounts":
switch len(c.flagAccounts) {
case 0:
c.UI.Error("No accounts supplied via -account")
return 1
case 1:
if c.flagAccounts[0] == "null" {
accounts = nil
}
}
}
userClient := users.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create", "read", "delete", "list":
// These don't udpate so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, users.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = userClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
result, err = userClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
result, err = userClient.Read(c.Context, c.FlagId, opts...)
case "delete":
_, err = userClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = userClient.List(c.Context, c.FlagScopeId, opts...)
case "add-accounts":
result, err = userClient.AddAccounts(c.Context, c.FlagId, version, accounts, opts...)
case "set-accounts":
result, err = userClient.SetAccounts(c.Context, c.FlagId, version, accounts, opts...)
case "remove-accounts":
result, err = userClient.RemoveAccounts(c.Context, c.FlagId, version, accounts, opts...)
}
plural := "user"
if c.Func == "list" {
plural = "users"
}
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedUsers := listResult.GetItems().([]*users.User)
switch base.Format(c.UI) {
case "json":
if len(listedUsers) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedUsers)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedUsers) == 0 {
c.UI.Output("No users found")
return 0
}
var output []string
output = []string{
"",
"User information:",
}
for i, u := range listedUsers {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", u.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", u.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", u.Version),
)
}
if u.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", u.Name),
)
}
if u.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", u.Description),
)
}
if len(u.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, u.AuthorizedActions),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
user := result.GetItem().(*users.User)
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateUserTableOutput(user))
case "json":
b, err := base.JsonFormatter{}.Format(user)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+255
View File
@@ -0,0 +1,255 @@
package userscmd
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/users"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/mitchellh/go-wordwrap"
)
func init() {
extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl
extraSynopsisFunc = extraSynopsisFuncImpl
extraFlagsFunc = extraFlagsFuncImpl
extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl
executeExtraActions = executeExtraActionsImpl
}
type extraCmdVars struct {
flagAccounts []string
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"add-accounts": {"id", "account", "version"},
"set-accounts": {"id", "account", "version"},
"remove-accounts": {"id", "account", "version"},
}
}
func extraSynopsisFuncImpl(c *Command) string {
switch c.Func {
case "add-accounts", "set-accounts", "remove-accounts":
var in string
switch {
case strings.HasPrefix(c.Func, "add"):
in = "Add accounts to"
case strings.HasPrefix(c.Func, "set"):
in = "Set the full contents of the accounts on"
case strings.HasPrefix(c.Func, "remove"):
in = "Remove accounts from"
}
return wordwrap.WrapString(fmt.Sprintf("%s a user within Boundary", in), base.TermWidth)
}
return ""
}
func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
var helpStr string
switch c.Func {
case "add-accounts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary users add-accounts [options] [args]",
"",
` Associates accounts to a user given its ID. The "account" flag can be specified multiple times. Example:`,
"",
` $ boundary users add-accounts -id u_1234567890 -account a_1234567890`,
"",
"",
})
case "set-accounts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary users set-accounts [options] [args]",
"",
` Sets the complete set of associated accounts on a user given its ID. The "account" flag can be specified multiple times. Example:`,
"",
` $ boundary users set-principals -id u_1234567890 -account a_0987654321 -account a_1234567890`,
"",
"",
})
case "remove-accounts":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary users remove-accounts [options] [args]",
"",
` Disassociates accounts from a user given its ID. The "account" flag can be specified multiple times. Example:`,
"",
` $ boundary users remove-accounts -id u_1234567890 -account a_1234567890`,
"",
"",
})
default:
helpStr = helpMap["base"]()
}
return helpStr + c.Flags().Help()
}
func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "account":
f.StringSliceVar(&base.StringSliceVar{
Name: "account",
Target: &c.flagAccounts,
Usage: "The accounts to add, remove, or set. May be specified multiple times.",
})
}
}
}
func extraFlagsHandlingFuncImpl(c *Command, opts *[]users.Option) int {
switch c.Func {
case "add-accounts", "remove-accounts":
if len(c.flagAccounts) == 0 {
c.UI.Error("No accounts supplied via -account")
return 1
}
case "set-accounts":
switch len(c.flagAccounts) {
case 0:
c.UI.Error("No accounts supplied via -account")
return 1
case 1:
if c.flagAccounts[0] == "null" {
c.flagAccounts = nil
}
}
}
return 0
}
func executeExtraActionsImpl(c *Command, origResult api.GenericResult, origError error, userClient *users.Client, version uint32, opts []users.Option) (api.GenericResult, error) {
switch c.Func {
case "add-accounts":
return userClient.AddAccounts(c.Context, c.FlagId, version, c.flagAccounts, opts...)
case "set-accounts":
return userClient.SetAccounts(c.Context, c.FlagId, version, c.flagAccounts, opts...)
case "remove-accounts":
return userClient.RemoveAccounts(c.Context, c.FlagId, version, c.flagAccounts, opts...)
}
return origResult, origError
}
func (c *Command) printListTable(items []*users.User) string {
if len(items) == 0 {
return "No users found"
}
var output []string
output = []string{
"",
"User information:",
}
for i, u := range items {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", u.Id),
)
}
if c.FlagRecursive {
output = append(output,
fmt.Sprintf(" Scope ID: %s", u.Scope.Id),
)
}
if true {
output = append(output,
fmt.Sprintf(" Version: %d", u.Version),
)
}
if u.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", u.Name),
)
}
if u.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", u.Description),
)
}
if len(u.AuthorizedActions) > 0 {
output = append(output,
" Authorized Actions:",
base.WrapSlice(6, u.AuthorizedActions),
)
}
}
return base.WrapForHelpText(output)
}
func printItemTable(in *users.User) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC1123),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC1123),
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
var userMaps []map[string]interface{}
if len(in.Accounts) > 0 {
for _, account := range in.Accounts {
a := map[string]interface{}{
"ID": account.Id,
"Scope ID": account.ScopeId,
}
userMaps = append(userMaps, a)
}
if l := len("Scope ID"); l > maxLength {
maxLength = l
}
}
ret := []string{
"",
"User information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
"",
" Scope:",
base.ScopeInfoForOutput(in.Scope, maxLength),
}
if len(in.AuthorizedActions) > 0 {
ret = append(ret,
"",
" Authorized Actions:",
base.WrapSlice(4, in.AuthorizedActions),
)
}
if len(in.Accounts) > 0 {
ret = append(ret,
"",
" Accounts:",
)
for _, m := range userMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
return base.WrapForHelpText(ret)
}
+362
View File
@@ -0,0 +1,362 @@
// Code generated by "make api"; DO NOT EDIT.
package userscmd
import (
"fmt"
"net/http"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/users"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/sdk/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
extraCmdVars
}
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 := "user"
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *Command) Help() string {
initFlags()
var helpStr string
helpMap := common.HelpMap("user")
switch c.Func {
case "create":
helpStr = helpMap[c.Func]() + c.Flags().Help()
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 = c.extraHelpFunc(helpMap)
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"read": {"id"},
"update": {"id", "name", "description", "version"},
"delete": {"id"},
"list": {"scope-id", "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, "user", flagsMap[c.Func])
extraFlagsFunc(c, set, f)
return set
}
func (c *Command) Run(args []string) int {
initFlags()
switch c.Func {
case "":
return cli.RunResultHelp
}
c.plural = "user"
switch c.Func {
case "list":
c.plural = "users"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
var opts []users.Option
if strutil.StrListContains(flagsMap[c.Func], "scope-id") {
switch c.Func {
case "create":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
case "list":
if c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id or BOUNDARY_SCOPE_ID")
return 1
}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
usersClient := users.NewClient(client)
switch c.FlagName {
case "":
case "null":
opts = append(opts, users.DefaultName())
default:
opts = append(opts, users.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, users.DefaultDescription())
default:
opts = append(opts, users.WithDescription(c.FlagDescription))
}
switch c.FlagRecursive {
case true:
opts = append(opts, users.WithRecursive(true))
}
var version uint32
switch c.Func {
case "update":
switch c.FlagVersion {
case 0:
opts = append(opts, users.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "add-accounts":
switch c.FlagVersion {
case 0:
opts = append(opts, users.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "remove-accounts":
switch c.FlagVersion {
case 0:
opts = append(opts, users.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-accounts":
switch c.FlagVersion {
case 0:
opts = append(opts, users.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ret := extraFlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
existed := true
var result api.GenericResult
var listResult api.GenericListResult
switch c.Func {
case "create":
result, err = usersClient.Create(c.Context, c.FlagScopeId, opts...)
case "read":
result, err = usersClient.Read(c.Context, c.FlagId, opts...)
case "update":
result, err = usersClient.Update(c.Context, c.FlagId, version, opts...)
case "delete":
_, err = usersClient.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
case "list":
listResult, err = usersClient.List(c.Context, c.FlagScopeId, opts...)
}
result, err = executeExtraActions(c, result, err, usersClient, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustomActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
listedItems := listResult.GetItems().([]*users.User)
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
}
item := result.GetItem().(*users.User)
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
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, *[]users.Option) int { return 0 }
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *users.Client, _ uint32, _ []users.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
)
+12
View File
@@ -0,0 +1,12 @@
# Determine this makefile's path.
# Be sure to place this BEFORE `include` directives, if any.
THIS_FILE := $(lastword $(MAKEFILE_LIST))
export CLI_GEN_BASEPATH := ${GEN_BASEPATH}/internal/cmd/commands
cli:
go run .
goimports -w ${CLI_GEN_BASEPATH}
gofumpt -w ${CLI_GEN_BASEPATH}
.PHONY: cli
+308
View File
@@ -0,0 +1,308 @@
package main
import (
"github.com/hashicorp/boundary/internal/types/resource"
)
type cmdInfo struct {
// The type of the resource, e.g. "target"
ResourceType string
// The API package under the api path
Pkg string
// Standard actions (with standard parameters) used by this resource
StdActions []string
// HasExtraCommandVars controls whether to generate an embedded struct with
// extra command variables
HasExtraCommandVars bool
// SkipNormalHelp indicates skipping the normal help case for when it needs
// to be only custom (mainly for subactions)
SkipNormalHelp bool
// HasExtraHelpFunc controls whether to include a default statement chaining
// to an extra help function
HasExtraHelpFunc bool
// HasExampleCliOutput controls whether to generate code to look for a CLI
// 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.
HasId bool
// Container controls what to generate for a required container (scope ID,
// auth method ID, etc.)
Container string
// HasName controls whether to add name options
HasName bool
// HasDescription controls whether to add description options
HasDescription bool
// HasScopeName controls whether to add scope name options
HasScopeName bool
// VersionedActions controls which actions to add a case for version checking
VersionedActions []string
// SubActionPrefix specifies the prefix to use when generating sub-action
// commands (e.g. "targets update tcp")
SubActionPrefix string
// NeedsSubTypeInCreate controls whether the sub-type must be passed in as
// an argument to a create call. Targets need this, accounts do not, etc.
NeedsSubTypeInCreate bool
}
var inputStructs = map[string][]*cmdInfo{
"accounts": {
{
ResourceType: resource.Account.String(),
Pkg: "accounts",
StdActions: []string{"read", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
IsAbstractType: true,
Container: "AuthMethod",
HasId: true,
HasName: true,
HasDescription: true,
VersionedActions: []string{"change-password", "set-password"},
},
{
ResourceType: resource.Account.String(),
Pkg: "accounts",
StdActions: []string{"create", "update"},
SubActionPrefix: "password",
HasExtraCommandVars: true,
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
Container: "AuthMethod",
HasDescription: true,
VersionedActions: []string{"update"},
},
},
"authmethods": {
{
ResourceType: resource.AuthMethod.String(),
Pkg: "authmethods",
StdActions: []string{"read", "delete", "list"},
IsAbstractType: true,
HasExtraHelpFunc: true,
Container: "Scope",
HasId: true,
},
{
ResourceType: resource.AuthMethod.String(),
Pkg: "authmethods",
StdActions: []string{"create", "update"},
SubActionPrefix: "password",
HasExtraCommandVars: true,
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
HasDescription: true,
Container: "Scope",
VersionedActions: []string{"update"},
NeedsSubTypeInCreate: true,
},
},
"authtokens": {
{
ResourceType: resource.AuthToken.String(),
Pkg: "authtokens",
StdActions: []string{"read", "delete", "list"},
Container: "Scope",
HasId: true,
},
},
"groups": {
{
ResourceType: resource.Group.String(),
Pkg: "groups",
StdActions: []string{"create", "read", "update", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
HasId: true,
Container: "Scope",
HasName: true,
HasDescription: true,
VersionedActions: []string{"update", "add-members", "remove-members", "set-members"},
},
},
"hostcatalogs": {
{
ResourceType: resource.HostCatalog.String(),
Pkg: "hostcatalogs",
StdActions: []string{"read", "delete", "list"},
IsAbstractType: true,
HasExtraHelpFunc: true,
Container: "Scope",
HasId: true,
},
{
ResourceType: resource.HostCatalog.String(),
Pkg: "hostcatalogs",
StdActions: []string{"create", "update"},
SubActionPrefix: "static",
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
HasDescription: true,
Container: "Scope",
VersionedActions: []string{"update"},
NeedsSubTypeInCreate: true,
},
},
"hostsets": {
{
ResourceType: resource.HostSet.String(),
Pkg: "hostsets",
StdActions: []string{"read", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
IsAbstractType: true,
Container: "HostCatalog",
HasId: true,
HasName: true,
HasDescription: true,
VersionedActions: []string{"add-hosts", "set-hosts", "remove-hosts"},
},
{
ResourceType: resource.HostSet.String(),
Pkg: "hostsets",
StdActions: []string{"create", "update"},
SubActionPrefix: "static",
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
Container: "HostCatalog",
HasDescription: true,
VersionedActions: []string{"update"},
},
},
"hosts": {
{
ResourceType: resource.Host.String(),
Pkg: "hosts",
StdActions: []string{"read", "delete", "list"},
HasExtraHelpFunc: true,
IsAbstractType: true,
Container: "HostCatalog",
HasId: true,
HasName: true,
HasDescription: true,
},
{
ResourceType: resource.Host.String(),
Pkg: "hosts",
StdActions: []string{"create", "update"},
SubActionPrefix: "static",
HasExtraCommandVars: true,
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
Container: "HostCatalog",
HasDescription: true,
VersionedActions: []string{"update"},
},
},
"roles": {
{
ResourceType: resource.Role.String(),
Pkg: "roles",
StdActions: []string{"create", "read", "update", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
HasId: true,
Container: "Scope",
HasName: true,
HasDescription: true,
VersionedActions: []string{"update", "add-grants", "remove-grants", "set-grants", "add-principals", "remove-principals", "set-principals"},
},
},
"scopes": {
{
ResourceType: resource.Scope.String(),
Pkg: "scopes",
StdActions: []string{"create", "read", "update", "delete", "list"},
HasExtraCommandVars: true,
HasId: true,
Container: "Scope",
HasName: true,
HasDescription: true,
VersionedActions: []string{"update"},
},
},
"sessions": {
{
ResourceType: resource.Session.String(),
Pkg: "sessions",
StdActions: []string{"read", "list"},
Container: "Scope",
HasExtraHelpFunc: true,
HasId: true,
VersionedActions: []string{"cancel"},
},
},
"targets": {
{
ResourceType: resource.Target.String(),
Pkg: "targets",
StdActions: []string{"read", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
HasExampleCliOutput: true,
IsAbstractType: true,
HasName: true,
HasDescription: true,
Container: "Scope",
VersionedActions: []string{"add-host-sets", "remove-host-sets", "set-host-sets"},
},
{
ResourceType: resource.Target.String(),
Pkg: "targets",
StdActions: []string{"create", "update"},
SubActionPrefix: "tcp",
HasExtraCommandVars: true,
SkipNormalHelp: true,
HasExtraHelpFunc: true,
HasId: true,
HasName: true,
Container: "Scope",
HasDescription: true,
VersionedActions: []string{"update"},
NeedsSubTypeInCreate: true,
},
},
"users": {
{
ResourceType: resource.User.String(),
Pkg: "users",
StdActions: []string{"create", "read", "update", "delete", "list"},
HasExtraCommandVars: true,
HasExtraHelpFunc: true,
HasId: true,
Container: "Scope",
HasName: true,
HasDescription: true,
VersionedActions: []string{"update", "add-accounts", "remove-accounts", "set-accounts"},
},
},
}
+5
View File
@@ -0,0 +1,5 @@
package main
func main() {
fillTemplates()
}
+463
View File
@@ -0,0 +1,463 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"text/template"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/iancoleman/strcase"
)
func fillTemplates() {
for pkg, structs := range inputStructs {
for _, data := range structs {
outBuf := new(bytes.Buffer)
if err := cmdTemplate.Execute(outBuf, data); err != nil {
fmt.Printf("error executing struct template for resource %s: %v\n", pkg, err)
os.Exit(1)
}
fName := pkg
if data.SubActionPrefix != "" {
fName = fmt.Sprintf("%s_%s", data.SubActionPrefix, fName)
}
outFile, err := filepath.Abs(fmt.Sprintf("%s/%scmd/%s.gen.go", os.Getenv("CLI_GEN_BASEPATH"), pkg, fName))
if err != nil {
fmt.Printf("error opening file for package %s: %v\n", pkg, err)
os.Exit(1)
}
outDir := filepath.Dir(outFile)
if _, err := os.Stat(outDir); os.IsNotExist(err) {
_ = os.Mkdir(outDir, os.ModePerm)
}
if err := ioutil.WriteFile(outFile, outBuf.Bytes(), 0o644); err != nil {
fmt.Printf("error writing file %q: %v\n", outFile, err)
os.Exit(1)
}
}
}
}
func camelCase(in string) string {
return strcase.ToCamel(in)
}
func envCase(in string) string {
return strcase.ToScreamingSnake(in)
}
func snakeCase(in string) string {
return strcase.ToSnake(in)
}
func kebabCase(in string) string {
return strcase.ToKebab(in)
}
func lowerSpaceCase(in string) string {
return strcase.ToDelimited(in, ' ')
}
func hasAction(in []string, action string) bool {
return strutil.StrListContains(in, action)
}
var cmdTemplate = template.Must(template.New("").Funcs(
template.FuncMap{
"camelCase": camelCase,
"envCase": envCase,
"snakeCase": snakeCase,
"kebabCase": kebabCase,
"lowerSpaceCase": lowerSpaceCase,
"hasAction": hasAction,
},
).Parse(`{{ $input := . }}
// Code generated by "make api"; DO NOT EDIT.
package {{ .Pkg }}cmd
import (
"fmt"
"net/http"
"os"
"sync"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/{{ .Pkg }}"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/sdk/strutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
func init{{ camelCase .SubActionPrefix }}Flags() {
flagsOnce.Do(func() {
extraFlags := extra{{ camelCase .SubActionPrefix }}ActionsFlagsMapFunc()
for k, v := range extraFlags {
flags{{ camelCase .SubActionPrefix }}Map[k] = append(flags{{ camelCase .SubActionPrefix }}Map[k], v...)
}
})
}
var (
_ cli.Command = (*{{ camelCase .SubActionPrefix }}Command)(nil)
_ cli.CommandAutocomplete = (*{{ camelCase .SubActionPrefix }}Command)(nil)
)
type {{ camelCase .SubActionPrefix }}Command struct {
*base.Command
Func string
plural string
{{ if .HasExtraCommandVars }}
extra{{ camelCase .SubActionPrefix }}CmdVars
{{ end }}
}
func (c *{{ camelCase .SubActionPrefix }}Command) AutocompleteArgs() complete.Predictor {
init{{ camelCase .SubActionPrefix }}Flags()
return complete.PredictAnything
}
func (c *{{ camelCase .SubActionPrefix }}Command) AutocompleteFlags() complete.Flags {
init{{ camelCase .SubActionPrefix }}Flags()
return c.Flags().Completions()
}
func (c *{{ camelCase .SubActionPrefix }}Command) Synopsis() string {
if extra := extra{{ camelCase .SubActionPrefix }}SynopsisFunc(c); extra != "" {
return extra
}
synopsisStr := "{{ lowerSpaceCase .ResourceType }}"
{{ if .SubActionPrefix }}
synopsisStr = fmt.Sprintf("%s %s", "{{ .SubActionPrefix }}-type", synopsisStr)
{{ end }}
return common.SynopsisFunc(c.Func, synopsisStr)
}
func (c *{{ camelCase .SubActionPrefix }}Command) Help() string {
init{{ camelCase .SubActionPrefix }}Flags()
var helpStr string
helpMap := common.HelpMap("{{ lowerSpaceCase .ResourceType }}")
switch c.Func {
{{ if not .SkipNormalHelp }}
{{ range $i, $action := .StdActions }}
case "{{ $action }}":
helpStr = helpMap[c.Func]() + c.Flags().Help()
{{ end }}
{{ end }}
default:
{{ if .HasExtraHelpFunc }}
helpStr = c.extra{{ camelCase .SubActionPrefix }}HelpFunc(helpMap)
{{ else }}
helpStr = helpMap["base"]()
{{ end }}
}
// Keep linter from complaining if we don't actually generate code using it
_ = helpMap
return helpStr
}
var flags{{ camelCase .SubActionPrefix }}Map = map[string][]string{
{{ range $i, $action := .StdActions }}
{{ if eq $action "create" }}
"create": { "{{ kebabCase $input.Container }}-id", "name", "description" },
{{ end }}
{{ if eq $action "read" }}
"read": {"id"},
{{ end }}
{{ if eq $action "update" }}
"update": {"id", "name", "description" {{ if hasAction $input.VersionedActions "update" }}, "version" {{ end }} },
{{ end }}
{{ if eq $action "delete" }}
"delete": {"id"},
{{ end }}
{{ if eq $action "list" }}
"list": { "{{ kebabCase $input.Container }}-id" {{ if (eq $input.Container "Scope") }}, "recursive"{{ end }} },
{{ end }}
{{ end }}
}
func (c *{{ camelCase .SubActionPrefix }}Command) Flags() *base.FlagSets {
if len(flags{{ camelCase .SubActionPrefix }}Map[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, "{{ if .SubActionPrefix }}{{ .SubActionPrefix }}-type {{ end }}{{ lowerSpaceCase .ResourceType }}", flags{{ camelCase .SubActionPrefix }}Map[c.Func])
extra{{ camelCase .SubActionPrefix }}FlagsFunc(c, set, f)
return set
}
func (c *{{ camelCase .SubActionPrefix }}Command) Run(args []string) int {
init{{ camelCase .SubActionPrefix }}Flags()
{{ if .HasExampleCliOutput }}
if os.Getenv("BOUNDARY_EXAMPLE_CLI_OUTPUT") != "" {
c.UI.Output(exampleOutput())
return 0
}
{{ end }}
switch c.Func {
case "":
return cli.RunResultHelp
{{ if .IsAbstractType }}
case "create", "update":
return cli.RunResultHelp
{{ end }}
}
c.plural = "{{ if .SubActionPrefix }}{{ .SubActionPrefix }}-type {{ end }}{{ lowerSpaceCase .ResourceType }}"
switch c.Func {
case "list":
c.plural = "{{ if .SubActionPrefix }}{{ .SubActionPrefix }}-type {{ end }}{{ lowerSpaceCase .ResourceType }}s"
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
{{ if .HasId }}
if strutil.StrListContains(flags{{ camelCase .SubActionPrefix }}Map[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
{{ end }}
var opts []{{ .Pkg }}.Option
if strutil.StrListContains(flags{{ camelCase .SubActionPrefix }}Map[c.Func], "{{ kebabCase .Container }}-id") {
switch c.Func {
{{ if hasAction .StdActions "create" }}
case "create":
if c.Flag{{ .Container }}Id == "" {
c.UI.Error("{{ .Container }} ID must be passed in via -{{ kebabCase .Container }}-id or BOUNDARY_{{ envCase .Container }}_ID")
return 1
}
{{ end }}
{{ if hasAction .StdActions "list" }}
case "list":
if c.Flag{{ .Container }}Id == "" {
c.UI.Error("{{ .Container }} ID must be passed in via -{{ kebabCase .Container }}-id or BOUNDARY_{{ envCase .Container }}_ID")
return 1
}
{{ end }}
}
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
{{ .Pkg }}Client := {{ .Pkg }}.NewClient(client)
{{ if .HasName }}
switch c.FlagName {
case "":
case "null":
opts = append(opts, {{ .Pkg }}.DefaultName())
default:
opts = append(opts, {{ .Pkg }}.WithName(c.FlagName))
}
{{ end }}
{{ if .HasDescription }}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, {{ .Pkg }}.DefaultDescription())
default:
opts = append(opts, {{ .Pkg }}.WithDescription(c.FlagDescription))
}
{{ end }}
{{ if (eq .Container "Scope") }}
switch c.FlagRecursive {
case true:
opts = append(opts, {{ .Pkg }}.WithRecursive(true))
}
{{ end }}
{{ if .HasScopeName }}
switch c.FlagScopeName {
case "":
default:
opts = append(opts, {{ .Pkg }}.WithScopeName(c.FlagScopeName))
}
{{ end }}
var version uint32
{{ if .VersionedActions }}
switch c.Func {
{{ range $i, $action := .VersionedActions }}
case "{{ $action }}":
switch c.FlagVersion {
case 0:
opts = append(opts, {{ $input.Pkg }}.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
{{ end }}
}
{{ end }}
if ret := extra{{ camelCase .SubActionPrefix }}FlagsHandlingFunc(c, &opts); ret != 0 {
return ret
}
{{ if hasAction .StdActions "delete" }}
existed := true
{{ end }}
var result api.GenericResult
{{ if hasAction .StdActions "list" }}
var listResult api.GenericListResult
{{ end }}
switch c.Func {
{{ range $i, $action := $input.StdActions }}
{{ if eq $action "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 }}
{{ if eq $action "read" }}
case "read":
result, err = {{ $input.Pkg }}Client.Read(c.Context, c.FlagId, opts...)
{{ end }}
{{ if eq $action "update" }}
case "update":
result, err = {{ $input.Pkg }}Client.Update(c.Context, c.FlagId, version, opts...)
{{ end }}
{{ if eq $action "delete" }}
case "delete":
_, err = {{ $input.Pkg}}Client.Delete(c.Context, c.FlagId, opts...)
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.ResponseStatus() == http.StatusNotFound {
existed = false
err = nil
}
{{ end }}
{{ if eq $action "list" }}
case "list":
listResult, err = {{ $input.Pkg}}Client.List(c.Context, c.Flag{{ $input.Container }}Id, opts...)
{{ end }}
{{ end }}
}
result, err = executeExtra{{ camelCase .SubActionPrefix }}Actions(c, result, err, {{ .Pkg }}Client, version, opts)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, c.plural, base.PrintApiError(apiErr)))
return 1
}
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
return 2
}
output, err := printCustom{{ camelCase .SubActionPrefix }}ActionOutput(c)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if output {
return 0
}
switch c.Func {
{{ range $i, $action := .StdActions }}
{{ if eq $action "delete" }}
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output(fmt.Sprintf("{ \"existed\": %t }", existed))
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
{{ end }}
{{ if eq $action "list" }}
case "list":
listedItems := listResult.GetItems().([]*{{ $input.Pkg }}.{{ camelCase $input.ResourceType }})
switch base.Format(c.UI) {
case "json":
switch {
case len(listedItems) == 0:
c.UI.Output("null")
default:
b, err := base.JsonFormatter{}.Format(listedItems)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
case "table":
c.UI.Output(c.printListTable(listedItems))
}
return 0
{{ end }}
{{ end }}
}
item := result.GetItem().(*{{ .Pkg }}.{{ camelCase .ResourceType }})
switch base.Format(c.UI) {
case "table":
c.UI.Output(printItemTable(item))
case "json":
b, err := base.JsonFormatter{}.Format(item)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
var (
{{ if not .SubActionPrefix }}
flagsOnce = new(sync.Once)
{{ end }}
extra{{ camelCase .SubActionPrefix }}ActionsFlagsMapFunc = func() map[string][]string { return nil }
extra{{ camelCase .SubActionPrefix }}SynopsisFunc = func(*{{ camelCase .SubActionPrefix }}Command) string { return "" }
extra{{ camelCase .SubActionPrefix }}FlagsFunc = func(*{{ camelCase .SubActionPrefix }}Command, *base.FlagSets, *base.FlagSet) {}
extra{{ camelCase .SubActionPrefix }}FlagsHandlingFunc = func(*{{ camelCase .SubActionPrefix }}Command, *[]{{ .Pkg }}.Option) int { return 0 }
executeExtra{{ camelCase .SubActionPrefix }}Actions = func(_ *{{ camelCase .SubActionPrefix }}Command, inResult api.GenericResult, inErr error, _ *{{ .Pkg }}.Client, _ uint32, _ []{{ .Pkg }}.Option) (api.GenericResult, error) {
return inResult, inErr
}
printCustom{{ camelCase .SubActionPrefix }}ActionOutput = func(*{{ camelCase .SubActionPrefix }}Command) (bool, error) { return false, nil }
)
`))
+3 -1
View File
@@ -74,8 +74,10 @@ load _helpers
[ "$status" -eq 0 ]
run read_session $id
[ "$status" -eq 0 ]
echo $output
run cancel_session $id
[ "$status" -eq 0 ]
echo $output
}
@test "boundary/session: verify read and cancelation permissions on unpriv session" {
@@ -101,4 +103,4 @@ load _helpers
[ "$status" -eq 0 ]
run cancel_session $id
[ "$status" -eq 0 ]
}
}
+23 -21
View File
@@ -8,7 +8,7 @@ description: |-
# Boundary Desktop
-> Boundary Desktop is currently an Alpha release still undergoing final testing before its official release. Should you experience any bugs or lack of desired functionality, please let us know so that we can evaluate a fix. You can open an issue at https://github.com/hashicorp/boundary/issues/new/choose. Your help is greatly appreciated!
-> Boundary Desktop is currently an Alpha release still undergoing final testing before its official release. Should you experience any bugs or lack of desired functionality, please let us know so that we can evaluate a fix. You can open an issue at https://github.com/hashicorp/boundary/issues/new/choose. Your help is greatly appreciated!
Boundary Desktop is a standalone application that provides a simple interface
for browsing and connecting to targets on your local computer (macOS currently
@@ -18,7 +18,7 @@ using your favorite tooling!
## Getting Started
-> If you're running Boundary for the first time, [download the latest binary](https://www.boundaryproject.io/downloads)
and run it in `dev` mode locally so you can have a server to run against:
and run it in `dev` mode locally so you can have a server to run against:
```shell-session
$ boundary dev
@@ -29,34 +29,35 @@ $ boundary dev
1. Download the latest .dmg installer from our [releases page](https://releases.hashicorp.com/boundary-desktop)
1. Double-click the downloaded .dmg to run the installer
1. Drag and drop Boundary into the applications folder
![](/img/boundary-desktop-drag-to-install.png)
![](/img/boundary-desktop-drag-to-install.png)
### Run Boundary Desktop
1. Open the Boundary Desktop application
![](/img/boundary-desktop-open.png)
![](/img/boundary-desktop-open.png)
1. You'll be prompted for the Boundary server origin, this is the URL for the client
to connect to the Boundary API. If you are running a local `dev` mode server, this
URL will be `http://localhost:9200`
![](/img/boundary-desktop-origin.png)
1. You can now login to Boundary. We're using a `dev` mode server in this example with the
username `admin` and the password `password`
![](/img/boundary-desktop-login.png)
to connect to the Boundary API. If you are running a local `dev` mode server, this
URL will be `http://localhost:9200`
![](/img/boundary-desktop-origin.png)
1. You can now login to Boundary. We're using a `dev` mode server in this example with the
username `admin` and the password `password`
![](/img/boundary-desktop-login.png)
1. After logging in, you should see the targets your user is authorized to connect to. Since
we are using a `dev` mode server we see the default generated target for `127.0.0.1:22`
![](/img/boundary-desktop-landing.png)
we are using a `dev` mode server we see the default generated target for `127.0.0.1:22`
![](/img/boundary-desktop-landing.png)
### Connect!
-> The rest of this example assumes you're running Boundary in `dev` mode.
1. Click on `connect` next to the default target. A pop-up window will display the local
address of the proxy and the ephemeral port for the session
![](/img/boundary-desktop-connect.png)
1. Click on `connect` next to the default target. A pop-up window will display the local
address of the proxy and the ephemeral port for the session
![](/img/boundary-desktop-connect.png)
1. Navigate to the `Sessions` pane and you'll see this session is in `pending` state because we
haven't made a connection to it yet (but will!)
![](/img/boundary-desktop-pending.png)
haven't made a connection to it yet (but will!)
![](/img/boundary-desktop-pending.png)
-> The next step assumes you have a SSH server running that the default target will connect to.
-> The next step assumes you have a SSH server running that the default target will connect to.
1. On the CLI, `ssh` to the target using the local ephemeral port created in the previous step
@@ -68,10 +69,11 @@ Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[127.0.0.1]:49250' (ECDSA) to the list of known hosts.
Password:
Last login: Thu Feb 11 17:49:09 2021
$
$
```
1. Navigate back to the sessions view and you'll see this session is now active
![](/img/boundary-desktop-active.png)
![](/img/boundary-desktop-active.png)
1. Click `Cancel` to cancel the session and you'll see the status go to `cancelling` briefly, then `terminated`
![](/img/boundary-desktop-terminated.png)
![](/img/boundary-desktop-terminated.png)
1. Navigate back to the CLI and you'll see your SSH session has closed
File diff suppressed because it is too large. Load diff
+12 -12
View File
@@ -19,18 +19,18 @@ worker {
```
- `name` - Specifies a unique name of this worker within the Boundary worker
cluster.
cluster.
- `description` - Specifies a friendly description of this worker.
- `public_addr` - Specifies the public host or IP address (and optionally port)
at which the worker can be reached _by clients for proxying_. This defaults to
the address of the listener marked for `proxy` purpose. This is especially
useful for cloud environments that do not bind a publicly accessible IP to a NIC
on the host directly, such as an Amazon EIP.
at which the worker can be reached _by clients for proxying_. This defaults to
the address of the listener marked for `proxy` purpose. This is especially
useful for cloud environments that do not bind a publicly accessible IP to a NIC
on the host directly, such as an Amazon EIP.
- `controllers` - A list of hosts/IP addresses and optionally ports for reaching
controllers. The port will default to :9201 if not specified.
controllers. The port will default to :9201 if not specified.
- `tags` - A map of key-value pairs where values are an array of strings. Most commonly used for [filtering](/docs/concepts/filtering) targets a worker can proxy via [worker tags](/docs/concepts/filtering/worker-tags).
@@ -39,7 +39,7 @@ controllers. The port will default to :9201 if not specified.
Workers require a KMS block designated for `worker-auth`. This is the KMS configuration for
authentication between the workers and controllers and must be present. Example (not safe for production!):
```hcl
```hcl
kms "aead" {
purpose = "worker-auth"
aead_type = "aes-gcm"
@@ -48,13 +48,13 @@ authentication between the workers and controllers and must be present. Example
}
```
This configuration must be the same for the worker-auth configuration for the controller if you're
This configuration must be the same for the worker-auth configuration for the controller if you're
running the controller and worker as separate servers.
And optionally, a KMS stanza for configuration encryption purpose:
```hcl
# Configuration encryption block: decrypts sensitive values in the
# Configuration encryption block: decrypts sensitive values in the
# configuration file. See `boundary config [encrypt|decrypt] -h`.
kms "aead" {
purpose = "config"`
@@ -64,7 +64,7 @@ kms "aead" {
```
Boundary supports many kinds of KMS integrations. For a complete guide to all available
KMS types, see our [KMS documentation](/docs/configuration/kms).
KMS types, see our [KMS documentation](/docs/configuration/kms).
# Complete Configuration Example
@@ -88,11 +88,11 @@ worker {
]
public_addr = "myhost.mycompany.com"
tags {
type = ["prod", "webservers"]
region = ["us-east-1"]
}
}
}
# must be same key as used on controller config
@@ -1,6 +1,6 @@
---
layout: docs
page_title: Running Boundary in Non-Dev Environments
page_title: Running Boundary in Non-Dev Environments
sidebar_title: Non-Dev Environments
description: |-
How to install boundary in non-dev environments.
@@ -10,11 +10,11 @@ description: |-
What are generated resources? When you run `boundary dev` or `boundary database init`, Boundary automatically
generates a number of resources to make getting started easier. Default scopes, auth methods, user, account, and
targets are just some of the resources Boundary will generate unless you tell it not to.
targets are just some of the resources Boundary will generate unless you tell it not to.
In a production or long-running environment, these resoures are not neccessary, but without them, managing
Boundary from scratch isn't straight forward. How do you create your first user and login to administer a Boundary
deployment that has no authentication methods, users, accounts, etc? This section describes how to get your freshly
In a production or long-running environment, these resoures are not neccessary, but without them, managing
Boundary from scratch isn't straight forward. How do you create your first user and login to administer a Boundary
deployment that has no authentication methods, users, accounts, etc? This section describes how to get your freshly
deployed Boundary installation off the ground for non-dev environments.
## Recovery KMS Workflow
@@ -102,7 +102,6 @@ EOT
</Tab>
</Tabs>
## Initialize the Database
Before you can start Boundary, the database must be initialized. It's useful to look at the help output for the init command:
@@ -178,8 +177,6 @@ resource "boundary_scope" "project" {
</Tab>
</Tabs>
### Create an Auth Method
Create an auth method in the organization scope.
@@ -277,7 +274,6 @@ resource "boundary_user" "myuser" {
</Tab>
</Tabs>
### Create Roles to Manage Scopes
The following describes the four baseline roles you'll need to create to manage resources within the org and project
@@ -286,6 +282,7 @@ allows you to manage them independently and fully within Terraform or on the CLI
them down more or have control over them in a declarative way.
The following example creates 4 roles:
1. To allow anonymouns (unauthenticated) users the ability to list scopes and auth methods in the global scope.
1. To allow anonymouns (unauthenticated) users the ability to list scopes and auth methods in the orgnaization scope.
1. To allow `myuser` user administration grants at the org scope.
@@ -370,10 +367,10 @@ resource "boundary_role" "org_anon_listing" {
principal_ids = ["u_anon"]
}
```
</Tab>
</Tabs>
#### Org admin role for myuser
<Tabs>
@@ -409,10 +406,10 @@ resource "boundary_role" "org_admin" {
principal_ids = [boundary_user.myuser.id]
}
```
</Tab>
</Tabs>
#### Project admin for myuser
<Tabs>
@@ -452,7 +449,6 @@ resource "boundary_role" "project_admin" {
</Tab>
</Tabs>
### Login as Your New User
```bash