CLI Generation (#953)
This commit is contained in:
1 parent
282bbe619e
commit
341e7aff0d
77 files changed
+10303
-6861
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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",
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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{}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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{}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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{}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
@@ -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
|
||||
@@ -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"},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
fillTemplates()
|
||||
}
|
||||
@@ -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 }
|
||||
)
|
||||
`))
|
||||
@@ -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 ]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||

|
||||

|
||||
|
||||
### Run Boundary Desktop
|
||||
|
||||
1. Open the Boundary Desktop application
|
||||

|
||||

|
||||
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`
|
||||

|
||||
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`
|
||||

|
||||
to connect to the Boundary API. If you are running a local `dev` mode server, this
|
||||
URL will be `http://localhost:9200`
|
||||

|
||||
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`
|
||||

|
||||
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`
|
||||

|
||||
we are using a `dev` mode server we see the default generated target for `127.0.0.1:22`
|
||||

|
||||
|
||||
### 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
|
||||

|
||||
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
|
||||

|
||||
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!)
|
||||

|
||||
haven't made a connection to it yet (but will!)
|
||||

|
||||
|
||||
-> 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
|
||||

|
||||

|
||||
1. Click `Cancel` to cancel the session and you'll see the status go to `cancelling` briefly, then `terminated`
|
||||

|
||||

|
||||
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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user