From b6df5693b53b6d3f3e12e6328b19199b756884cb Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 15 Nov 2023 19:55:46 -0500 Subject: [PATCH] Add generic read/update/delete commands (#3992) * Add generic read/update/delete commands This adds three generic commands that use the resource prefix to determine the subcommand to run and pass through args over to that subcommand. Since this occurs very early on and to avoid loading essentially every internal resource package, I moved subtype definitions to globals. This replaces #3967 Co-authored-by: Johan Brandhorst-Satzkorn * De-duplicate Subtype code (#4031) Co-authored-by: Timothy Messier --------- Co-authored-by: Johan Brandhorst-Satzkorn Co-authored-by: Timothy Messier --- CHANGELOG.md | 19 + cmd/boundary/main.go | 3 - globals/prefixes.go | 269 ++++++++-- globals/prefixes_test.go | 8 +- globals/subtypes.go | 16 + internal/auth/ldap/ids.go | 10 +- internal/auth/oidc/ids.go | 10 +- internal/auth/password/public_ids.go | 10 +- internal/cmd/base/base.go | 4 +- internal/cmd/base/option.go | 9 + internal/cmd/commands.go | 460 +++++++++--------- .../cmd/commands/authenticate/authenticate.go | 2 +- internal/cmd/commands/config/config.go | 2 +- internal/cmd/commands/genericcmd/generic.go | 44 ++ internal/cmd/common/flags.go | 7 +- internal/cmd/main.go | 113 ++++- internal/cmd/main_test.go | 73 +++ internal/credential/public_ids.go | 21 +- internal/credential/static/public_ids.go | 9 +- .../static/repository_credential.go | 6 +- internal/credential/vault/public_ids.go | 21 +- internal/daemon/controller/auth/auth.go | 3 +- .../handlers/accounts/account_service.go | 32 +- .../handlers/accounts/account_service_test.go | 3 +- .../authmethods/authmethod_service.go | 58 +-- .../credentiallibrary_service.go | 42 +- .../credentials/credential_service.go | 4 +- .../credentialstore_service.go | 24 +- .../host_catalogs/host_catalog_service.go | 34 +- .../host_catalog_service_test.go | 3 +- .../handlers/host_sets/host_set_service.go | 36 +- .../host_sets/host_set_service_test.go | 3 +- .../controller/handlers/hosts/host_service.go | 28 +- .../handlers/hosts/host_service_test.go | 3 +- .../managed_groups/managed_group_service.go | 28 +- .../handlers/targets/credentials.go | 3 +- .../controller/handlers/targets/registry.go | 12 +- .../handlers/targets/target_service.go | 6 +- .../targets/tcp/target_service_test.go | 2 +- internal/host/plugin/ids.go | 13 +- internal/host/static/public_ids.go | 10 +- internal/perms/acl.go | 4 +- internal/perms/grants.go | 6 +- internal/storage/plugin/ids.go | 8 +- internal/target/options.go | 6 +- internal/target/options_test.go | 4 +- internal/target/registry.go | 43 +- .../target/repository_credential_source.go | 4 +- internal/target/target.go | 8 +- internal/target/targettest/target.go | 5 +- internal/target/tcp/target.go | 6 +- .../types/subtypes/attribute_transform.go | 5 +- internal/types/subtypes/attributes.go | 9 +- internal/types/subtypes/attributes_test.go | 9 +- internal/types/subtypes/interceptor.go | 33 +- internal/types/subtypes/interceptor_test.go | 6 +- internal/types/subtypes/registry.go | 35 +- internal/types/subtypes/registry_global.go | 156 ------ internal/types/subtypes/registry_test.go | 79 --- 59 files changed, 1032 insertions(+), 857 deletions(-) create mode 100644 globals/subtypes.go create mode 100644 internal/cmd/commands/genericcmd/generic.go create mode 100644 internal/cmd/main_test.go delete mode 100644 internal/types/subtypes/registry_global.go delete mode 100644 internal/types/subtypes/registry_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 365cd034d..353d5b891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. +## Next + +### Deprecations/Changes + +* Per the note in Boundary 0.12.0, the `vault` credential library subtype has + now been removed in favor of `vault-generic`. For example, instead of + `boundary credential-libraries create vault`, you must use `boundary + credential-libraries create vault-generic`. + +### New and Improved + +* cli: New generic commands `read`, `update`, and `delete` have been added. + These allow operating on resources by directly specifying the ID of the + resource as the next parameter (e.g. `boundary update ttcp_1234567890`). + Subtypes do not need to be specified (e.g. that command is equivalent to + `boundary targets update tcp -id ttcp_1234567890`), and any flags given after + the ID are passed through to the type-specific subcommand. Once the ID has + been entered, autocomplete is also supported. + ## 0.14.2 (2023/11/2) ### New and Improved diff --git a/cmd/boundary/main.go b/cmd/boundary/main.go index b3bc548ff..774a8aedd 100644 --- a/cmd/boundary/main.go +++ b/cmd/boundary/main.go @@ -4,14 +4,11 @@ package main import ( - "math/rand" "os" - "time" "github.com/hashicorp/boundary/internal/cmd" ) func main() { - rand.Seed(time.Now().UnixNano()) os.Exit(cmd.Run(os.Args[1:])) } diff --git a/globals/prefixes.go b/globals/prefixes.go index 6f2ecaa90..93e859194 100644 --- a/globals/prefixes.go +++ b/globals/prefixes.go @@ -4,6 +4,7 @@ package globals import ( + "fmt" "strings" "github.com/hashicorp/boundary/internal/types/resource" @@ -125,57 +126,231 @@ const ( ChannelRecordingPrefix = "chr" ) -var prefixToResourceType = map[string]resource.Type{ - AuthTokenPrefix: resource.AuthToken, - PasswordAuthMethodPrefix: resource.AuthMethod, - PasswordAccountPrefix: resource.Account, - PasswordAccountPreviousPrefix: resource.Account, - OidcAuthMethodPrefix: resource.AuthMethod, - OidcAccountPrefix: resource.Account, - OidcManagedGroupPrefix: resource.ManagedGroup, - GlobalPrefix: resource.Scope, - ProjectPrefix: resource.Scope, - OrgPrefix: resource.Scope, - UserPrefix: resource.User, - GroupPrefix: resource.Group, - RolePrefix: resource.Role, - StaticCredentialStorePrefix: resource.CredentialStore, - StaticCredentialStorePreviousPrefix: resource.CredentialStore, - VaultCredentialStorePrefix: resource.CredentialStore, - VaultCredentialLibraryPrefix: resource.CredentialLibrary, - VaultSshCertificateCredentialLibraryPrefix: resource.CredentialLibrary, - UsernamePasswordCredentialPrefix: resource.Credential, - UsernamePasswordCredentialPreviousPrefix: resource.Credential, - SshPrivateKeyCredentialPrefix: resource.Credential, - JsonCredentialPrefix: resource.Credential, - StaticHostCatalogPrefix: resource.HostCatalog, - StaticHostSetPrefix: resource.HostSet, - StaticHostPrefix: resource.Host, - PluginHostCatalogPrefix: resource.HostCatalog, - PluginHostCatalogPreviousPrefix: resource.HostCatalog, - PluginHostSetPrefix: resource.HostSet, - PluginHostSetPreviousPrefix: resource.HostSet, - PluginHostPrefix: resource.Host, - PluginHostPreviousPrefix: resource.Host, - SessionPrefix: resource.Session, - TcpTargetPrefix: resource.Target, - SshTargetPrefix: resource.Target, - WorkerPrefix: resource.Worker, - PluginStorageBucketPrefix: resource.StorageBucket, - SessionRecordingPrefix: resource.SessionRecording, +type ResourceInfo struct { + Type resource.Type + Domain string + Subtype Subtype +} + +var prefixToResourceType = map[string]ResourceInfo{ + AuthTokenPrefix: { + Type: resource.AuthToken, + Subtype: UnknownSubtype, + }, + + PasswordAuthMethodPrefix: { + Type: resource.AuthMethod, + Subtype: UnknownSubtype, + }, + PasswordAccountPrefix: { + Type: resource.Account, + Subtype: UnknownSubtype, + }, + PasswordAccountPreviousPrefix: { + Type: resource.Account, + Subtype: UnknownSubtype, + }, + + OidcAuthMethodPrefix: { + Type: resource.AuthMethod, + Subtype: UnknownSubtype, + }, + OidcAccountPrefix: { + Type: resource.Account, + Subtype: UnknownSubtype, + }, + OidcManagedGroupPrefix: { + Type: resource.ManagedGroup, + Subtype: UnknownSubtype, + }, + + LdapManagedGroupPrefix: { + Type: resource.ManagedGroup, + Subtype: UnknownSubtype, + }, + LdapAuthMethodPrefix: { + Type: resource.AuthMethod, + Subtype: UnknownSubtype, + }, + LdapAccountPrefix: { + Type: resource.Account, + Subtype: UnknownSubtype, + }, + + ProjectPrefix: { + Type: resource.Scope, + Subtype: UnknownSubtype, + }, + OrgPrefix: { + Type: resource.Scope, + Subtype: UnknownSubtype, + }, + GlobalPrefix: { + Type: resource.Scope, + Subtype: UnknownSubtype, + }, + + UserPrefix: { + Type: resource.User, + Subtype: UnknownSubtype, + }, + GroupPrefix: { + Type: resource.Group, + Subtype: UnknownSubtype, + }, + RolePrefix: { + Type: resource.Role, + Subtype: UnknownSubtype, + }, + + StaticCredentialStorePrefix: { + Type: resource.CredentialStore, + Subtype: UnknownSubtype, + }, + StaticCredentialStorePreviousPrefix: { + Type: resource.CredentialStore, + Subtype: UnknownSubtype, + }, + + VaultCredentialStorePrefix: { + Type: resource.CredentialStore, + Subtype: UnknownSubtype, + }, + VaultCredentialLibraryPrefix: { + Type: resource.CredentialLibrary, + Subtype: UnknownSubtype, + }, + VaultSshCertificateCredentialLibraryPrefix: { + Type: resource.CredentialLibrary, + Subtype: UnknownSubtype, + }, + VaultDynamicCredentialPrefix: { + Type: resource.Credential, + Subtype: UnknownSubtype, + }, + + UsernamePasswordCredentialPrefix: { + Type: resource.Credential, + Subtype: UnknownSubtype, + }, + UsernamePasswordCredentialPreviousPrefix: { + Type: resource.Credential, + Subtype: UnknownSubtype, + }, + SshPrivateKeyCredentialPrefix: { + Type: resource.Credential, + Subtype: UnknownSubtype, + }, + JsonCredentialPrefix: { + Type: resource.Credential, + Subtype: UnknownSubtype, + }, + + StaticHostCatalogPrefix: { + Type: resource.HostCatalog, + Subtype: UnknownSubtype, + }, + StaticHostSetPrefix: { + Type: resource.HostSet, + Subtype: UnknownSubtype, + }, + StaticHostPrefix: { + Type: resource.Host, + Subtype: UnknownSubtype, + }, + + PluginHostCatalogPrefix: { + Type: resource.HostCatalog, + Subtype: UnknownSubtype, + }, + PluginHostCatalogPreviousPrefix: { + Type: resource.HostCatalog, + Subtype: UnknownSubtype, + }, + PluginHostSetPrefix: { + Type: resource.HostSet, + Subtype: UnknownSubtype, + }, + PluginHostSetPreviousPrefix: { + Type: resource.HostSet, + Subtype: UnknownSubtype, + }, + PluginHostPrefix: { + Type: resource.Host, + Subtype: UnknownSubtype, + }, + PluginHostPreviousPrefix: { + Type: resource.Host, + Subtype: UnknownSubtype, + }, + + SessionPrefix: { + Type: resource.Session, + Subtype: UnknownSubtype, + }, + + TcpTargetPrefix: { + Type: resource.Target, + Subtype: UnknownSubtype, + }, + SshTargetPrefix: { + Type: resource.Target, + Subtype: UnknownSubtype, + }, + + WorkerPrefix: { + Type: resource.Worker, + Subtype: UnknownSubtype, + }, + + PluginStorageBucketPrefix: { + Type: resource.StorageBucket, + Subtype: UnknownSubtype, + }, + + SessionRecordingPrefix: { + Type: resource.SessionRecording, + Subtype: UnknownSubtype, + }, } var resourceTypeToPrefixes map[resource.Type][]string = func() map[resource.Type][]string { ret := make(map[resource.Type][]string) for k, v := range prefixToResourceType { - ret[v] = append(ret[v], k) + ret[v.Type] = append(ret[v.Type], k) } return ret }() -// ResourceTypeFromPrefix takes in a resource ID (or a prefix) and returns the -// corresponding resource typ -func ResourceTypeFromPrefix(in string) resource.Type { +// RegisterPrefixToResourceInfo is called from various packages to register +// which prefixes belong to them, what types those represent, and any +// domain and subtype information. This lets the subtypes stay in different +// packages (important for the reflection introspection we do) while not +// creating import loops. +// +// If called more than once for the same prefix, this function will panic. +func RegisterPrefixToResourceInfo(prefix string, res resource.Type, domain string, subtype Subtype) { + if subtype == UnknownSubtype { + panic("cannot be called with a subtype of Unknown") + } + resInfo, ok := prefixToResourceType[prefix] + if !ok && domain != "test" { + panic(fmt.Sprintf("prefix %q being registered to domain %q type %q subtype %q but did not already exist in map", prefix, domain, res.String(), subtype.String())) + } + if domain != "test" && + (resInfo.Domain != "" || + resInfo.Subtype != UnknownSubtype) { + panic(fmt.Sprintf("prefix %q being registered to domain %q type %q subtype %q but was already registered to domain %q type %q subtype %q", prefix, domain, res.String(), subtype.String(), resInfo.Domain, resInfo.Type.String(), resInfo.Subtype.String())) + } + resInfo.Type = res + resInfo.Subtype = subtype + resInfo.Domain = domain + prefixToResourceType[prefix] = resInfo +} + +// ResourceInfoFromPrefix takes in a resource ID (or a prefix) and returns the +// corresponding resource info +func ResourceInfoFromPrefix(in string) ResourceInfo { // If full ID, trim to just prefix in, _, _ = strings.Cut(in, "_") return prefixToResourceType[in] @@ -186,3 +361,13 @@ func ResourceTypeFromPrefix(in string) resource.Type { func ResourcePrefixesFromType(in resource.Type) []string { return resourceTypeToPrefixes[in] } + +func PrefixesFromDomain(domain string) []string { + res := make([]string, 0, 8) + for k, v := range prefixToResourceType { + if v.Domain == domain { + res = append(res, k) + } + } + return res +} diff --git a/globals/prefixes_test.go b/globals/prefixes_test.go index 94c3f2a94..97b12438c 100644 --- a/globals/prefixes_test.go +++ b/globals/prefixes_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestResourceTypeFromPrefix(t *testing.T) { +func TestResourceInfoFromPrefix(t *testing.T) { // Test a random sampling vals := map[string]resource.Type{ VaultCredentialLibraryPrefix: resource.CredentialLibrary, @@ -21,8 +21,8 @@ func TestResourceTypeFromPrefix(t *testing.T) { } for prefix, typ := range vals { - assert.Equal(t, typ, ResourceTypeFromPrefix(prefix)) - assert.Equal(t, typ, ResourceTypeFromPrefix(fmt.Sprintf("%s_foobar", prefix))) - assert.Equal(t, resource.Unknown, ResourceTypeFromPrefix(fmt.Sprintf("%sfoobar", prefix))) + assert.Equal(t, typ, ResourceInfoFromPrefix(prefix).Type) + assert.Equal(t, typ, ResourceInfoFromPrefix(fmt.Sprintf("%s_foobar", prefix)).Type) + assert.Equal(t, resource.Unknown, ResourceInfoFromPrefix(fmt.Sprintf("%sfoobar", prefix)).Type) } } diff --git a/globals/subtypes.go b/globals/subtypes.go new file mode 100644 index 000000000..bc3be1146 --- /dev/null +++ b/globals/subtypes.go @@ -0,0 +1,16 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package globals + +// Subtype variables identify a boundary resource subtype. +type Subtype string + +const ( + UnknownSubtype Subtype = "unknown" +) + +// String returns the string representation of a Subtype +func (t Subtype) String() string { + return string(t) +} diff --git a/internal/auth/ldap/ids.go b/internal/auth/ldap/ids.go index 29aa69113..1b4e807cc 100644 --- a/internal/auth/ldap/ids.go +++ b/internal/auth/ldap/ids.go @@ -10,17 +10,17 @@ import ( "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(auth.Domain, Subtype, globals.LdapAuthMethodPrefix, globals.LdapAccountPrefix, globals.LdapManagedGroupPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.LdapAuthMethodPrefix, resource.AuthMethod, auth.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.LdapAccountPrefix, resource.Account, auth.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.LdapManagedGroupPrefix, resource.ManagedGroup, auth.Domain, Subtype) } const ( - Subtype = subtypes.Subtype("ldap") + Subtype = globals.Subtype("ldap") ) func newAuthMethodId(ctx context.Context) (string, error) { diff --git a/internal/auth/oidc/ids.go b/internal/auth/oidc/ids.go index 7c1e63a5d..7635d5744 100644 --- a/internal/auth/oidc/ids.go +++ b/internal/auth/oidc/ids.go @@ -10,17 +10,17 @@ import ( "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(auth.Domain, Subtype, globals.OidcAuthMethodPrefix, globals.OidcAccountPrefix, globals.OidcManagedGroupPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.OidcAuthMethodPrefix, resource.AuthMethod, auth.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.OidcAccountPrefix, resource.Account, auth.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.OidcManagedGroupPrefix, resource.ManagedGroup, auth.Domain, Subtype) } const ( - Subtype = subtypes.Subtype("oidc") + Subtype = globals.Subtype("oidc") ) func newAuthMethodId(ctx context.Context) (string, error) { diff --git a/internal/auth/password/public_ids.go b/internal/auth/password/public_ids.go index 505dc529e..49d1aed35 100644 --- a/internal/auth/password/public_ids.go +++ b/internal/auth/password/public_ids.go @@ -10,18 +10,18 @@ import ( "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(auth.Domain, Subtype, globals.PasswordAuthMethodPrefix, globals.PasswordAccountPreviousPrefix, globals.PasswordAccountPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.PasswordAuthMethodPrefix, resource.AuthMethod, auth.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.PasswordAccountPreviousPrefix, resource.Account, auth.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.PasswordAccountPrefix, resource.Account, auth.Domain, Subtype) } // PublicId prefixes for the resources in the password package. const ( - Subtype = subtypes.Subtype("password") + Subtype = globals.Subtype("password") ) func newAuthMethodId(ctx context.Context) (string, error) { diff --git a/internal/cmd/base/base.go b/internal/cmd/base/base.go index 2a9321ad5..6772d4ab9 100644 --- a/internal/cmd/base/base.go +++ b/internal/cmd/base/base.go @@ -142,12 +142,14 @@ type Command struct { } // New returns a new instance of a base.Command type -func NewCommand(ui cli.Ui) *Command { +func NewCommand(ui cli.Ui, opt ...Option) *Command { + opts := getOpts(opt...) ctx, cancel := context.WithCancel(context.Background()) ret := &Command{ UI: ui, ShutdownCh: MakeShutdownCh(), Context: ctx, + FlagId: opts.withImplicitId, } go func() { <-ret.ShutdownCh diff --git a/internal/cmd/base/option.go b/internal/cmd/base/option.go index 68f69df0b..a748018b4 100644 --- a/internal/cmd/base/option.go +++ b/internal/cmd/base/option.go @@ -44,6 +44,7 @@ type Options struct { withStatusCode int withHostPlugin func() (string, plugin.HostPluginServiceClient) withEventGating bool + withImplicitId string } func getDefaultOptions() Options { @@ -200,3 +201,11 @@ func WithEventGating(with bool) Option { o.withEventGating = with } } + +// WithImplicitId is used when creating the command if we are implicitly +// overriding the ID via a top-level read/update/delete command +func WithImplicitId(with string) Option { + return func(o *Options) { + o.withImplicitId = with + } +} diff --git a/internal/cmd/commands.go b/internal/cmd/commands.go index c158c5d7d..922f40c31 100644 --- a/internal/cmd/commands.go +++ b/internal/cmd/commands.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/boundary/internal/cmd/commands/credentialstorescmd" "github.com/hashicorp/boundary/internal/cmd/commands/database" "github.com/hashicorp/boundary/internal/cmd/commands/dev" + "github.com/hashicorp/boundary/internal/cmd/commands/genericcmd" "github.com/hashicorp/boundary/internal/cmd/commands/groupscmd" "github.com/hashicorp/boundary/internal/cmd/commands/hostcatalogscmd" "github.com/hashicorp/boundary/internal/cmd/commands/hostscmd" @@ -40,6 +41,10 @@ import ( var Commands map[string]cli.CommandFactory func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) { + var opts []base.Option + if runOpts.ImplicitId != "" { + opts = append(opts, base.WithImplicitId(runOpts.ImplicitId)) + } Commands = map[string]cli.CommandFactory{ "server": func() (cli.Command, error) { return &server.Command{ @@ -57,1268 +62,1277 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) { }, "version": func() (cli.Command, error) { return &version.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "authenticate": func() (cli.Command, error) { return &authenticate.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "authenticate password": func() (cli.Command, error) { return &authenticate.PasswordCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "authenticate oidc": func() (cli.Command, error) { return &authenticate.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "authenticate ldap": func() (cli.Command, error) { return &authenticate.LdapCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "accounts": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "accounts read": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "accounts delete": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "accounts list": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "accounts set-password": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-password", }, nil }, "accounts change-password": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "change-password", }, nil }, "accounts create": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "accounts create password": func() (cli.Command, error) { return &accountscmd.PasswordCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "accounts create oidc": func() (cli.Command, error) { return &accountscmd.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "accounts create ldap": func() (cli.Command, error) { return &accountscmd.LdapCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "accounts update": func() (cli.Command, error) { return &accountscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "accounts update password": func() (cli.Command, error) { return &accountscmd.PasswordCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "accounts update oidc": func() (cli.Command, error) { return &accountscmd.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "accounts update ldap": func() (cli.Command, error) { return &accountscmd.LdapCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "auth-methods": func() (cli.Command, error) { return &authmethodscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "auth-methods read": func() (cli.Command, error) { return &authmethodscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "auth-methods delete": func() (cli.Command, error) { return &authmethodscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "auth-methods list": func() (cli.Command, error) { return &authmethodscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "auth-methods create": func() (cli.Command, error) { return &authmethodscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "auth-methods create password": func() (cli.Command, error) { return &authmethodscmd.PasswordCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "auth-methods create oidc": func() (cli.Command, error) { return &authmethodscmd.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "auth-methods create ldap": func() (cli.Command, error) { return &authmethodscmd.LdapCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "auth-methods update": func() (cli.Command, error) { return &authmethodscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "auth-methods update password": func() (cli.Command, error) { return &authmethodscmd.PasswordCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "auth-methods update oidc": func() (cli.Command, error) { return &authmethodscmd.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "auth-methods update ldap": func() (cli.Command, error) { return &authmethodscmd.LdapCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "auth-methods change-state oidc": func() (cli.Command, error) { return &authmethodscmd.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "change-state", }, nil }, "auth-tokens": func() (cli.Command, error) { return &authtokenscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "auth-tokens read": func() (cli.Command, error) { return &authtokenscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "auth-tokens delete": func() (cli.Command, error) { return &authtokenscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "auth-tokens list": func() (cli.Command, error) { return &authtokenscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "config": func() (cli.Command, error) { return &config.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "config encrypt": func() (cli.Command, error) { return &config.EncryptDecryptCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "encrypt", }, nil }, "config decrypt": func() (cli.Command, error) { return &config.EncryptDecryptCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "decrypt", }, nil }, "config get-token": func() (cli.Command, error) { return &config.TokenCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "get-token", }, nil }, "config autocomplete": func() (cli.Command, error) { return &config.AutocompleteCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "base", }, nil }, "config autocomplete install": func() (cli.Command, error) { return &config.AutocompleteCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "install", }, nil }, "config autocomplete uninstall": func() (cli.Command, error) { return &config.AutocompleteCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "uninstall", }, nil }, "connect": func() (cli.Command, error) { return &connect.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "connect", }, nil }, "connect http": func() (cli.Command, error) { return &connect.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "http", }, nil }, "connect kube": func() (cli.Command, error) { return &connect.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "kube", }, nil }, "connect postgres": func() (cli.Command, error) { return &connect.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "postgres", }, nil }, "connect rdp": func() (cli.Command, error) { return &connect.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "rdp", }, nil }, "connect ssh": func() (cli.Command, error) { return &connect.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "ssh", }, nil }, "database": func() (cli.Command, error) { return &database.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "database init": func() (cli.Command, error) { return &database.InitCommand{ - Server: base.NewServer(base.NewCommand(ui)), + Server: base.NewServer(base.NewCommand(ui, opts...)), }, nil }, "database migrate": func() (cli.Command, error) { return &database.MigrateCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "credential-libraries": func() (cli.Command, error) { return &credentiallibrariescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "credential-libraries read": func() (cli.Command, error) { return &credentiallibrariescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "credential-libraries delete": func() (cli.Command, error) { return &credentiallibrariescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "credential-libraries list": func() (cli.Command, error) { return &credentiallibrariescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "credential-libraries create": func() (cli.Command, error) { return &credentiallibrariescmd.Command{ - Command: base.NewCommand(ui), - Func: "create", - }, nil - }, - "credential-libraries create vault": func() (cli.Command, error) { - return &credentiallibrariescmd.VaultCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credential-libraries create vault-generic": func() (cli.Command, error) { return &credentiallibrariescmd.VaultGenericCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credential-libraries create vault-ssh-certificate": func() (cli.Command, error) { return &credentiallibrariescmd.VaultSshCertificateCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credential-libraries update": func() (cli.Command, error) { return &credentiallibrariescmd.Command{ - Command: base.NewCommand(ui), - Func: "update", - }, nil - }, - "credential-libraries update vault": func() (cli.Command, error) { - return &credentiallibrariescmd.VaultGenericCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credential-libraries update vault-generic": func() (cli.Command, error) { return &credentiallibrariescmd.VaultGenericCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credential-libraries update vault-ssh-certificate": func() (cli.Command, error) { return &credentiallibrariescmd.VaultSshCertificateCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credential-stores": func() (cli.Command, error) { return &credentialstorescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "credential-stores read": func() (cli.Command, error) { return &credentialstorescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "credential-stores delete": func() (cli.Command, error) { return &credentialstorescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "credential-stores list": func() (cli.Command, error) { return &credentialstorescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "credential-stores create": func() (cli.Command, error) { return &credentialstorescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credential-stores create vault": func() (cli.Command, error) { return &credentialstorescmd.VaultCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credential-stores create static": func() (cli.Command, error) { return &credentialstorescmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credential-stores update": func() (cli.Command, error) { return &credentialstorescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credential-stores update vault": func() (cli.Command, error) { return &credentialstorescmd.VaultCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credential-stores update static": func() (cli.Command, error) { return &credentialstorescmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credentials": func() (cli.Command, error) { return &credentialscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "credentials read": func() (cli.Command, error) { return &credentialscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "credentials delete": func() (cli.Command, error) { return &credentialscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "credentials list": func() (cli.Command, error) { return &credentialscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "credentials create": func() (cli.Command, error) { return &credentialscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credentials create username-password": func() (cli.Command, error) { return &credentialscmd.UsernamePasswordCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credentials create ssh-private-key": func() (cli.Command, error) { return &credentialscmd.SshPrivateKeyCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credentials create json": func() (cli.Command, error) { return &credentialscmd.JsonCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "credentials update": func() (cli.Command, error) { return &credentialscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credentials update username-password": func() (cli.Command, error) { return &credentialscmd.UsernamePasswordCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credentials update ssh-private-key": func() (cli.Command, error) { return &credentialscmd.SshPrivateKeyCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "credentials update json": func() (cli.Command, error) { return &credentialscmd.JsonCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, + "delete": func() (cli.Command, error) { + return &genericcmd.Command{ + Command: base.NewCommand(ui, opts...), + Func: "delete", + }, nil + }, + "groups": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "groups create": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "groups update": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "groups read": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "groups delete": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "groups list": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "groups add-members": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-members", }, nil }, "groups set-members": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-members", }, nil }, "groups remove-members": func() (cli.Command, error) { return &groupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-members", }, nil }, "host-catalogs": func() (cli.Command, error) { return &hostcatalogscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "host-catalogs read": func() (cli.Command, error) { return &hostcatalogscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "host-catalogs delete": func() (cli.Command, error) { return &hostcatalogscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "host-catalogs list": func() (cli.Command, error) { return &hostcatalogscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "host-catalogs create": func() (cli.Command, error) { return &hostcatalogscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "host-catalogs create static": func() (cli.Command, error) { return &hostcatalogscmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "host-catalogs create plugin": func() (cli.Command, error) { return &hostcatalogscmd.PluginCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "host-catalogs update": func() (cli.Command, error) { return &hostcatalogscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "host-catalogs update static": func() (cli.Command, error) { return &hostcatalogscmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "host-catalogs update plugin": func() (cli.Command, error) { return &hostcatalogscmd.PluginCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "host-sets": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "host-sets read": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "host-sets delete": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "host-sets list": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "host-sets create": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "host-sets create static": func() (cli.Command, error) { return &hostsetscmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "host-sets create plugin": func() (cli.Command, error) { return &hostsetscmd.PluginCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "host-sets update": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "host-sets update static": func() (cli.Command, error) { return &hostsetscmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "host-sets update plugin": func() (cli.Command, error) { return &hostsetscmd.PluginCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "host-sets add-hosts": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-hosts", }, nil }, "host-sets remove-hosts": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-hosts", }, nil }, "host-sets set-hosts": func() (cli.Command, error) { return &hostsetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-hosts", }, nil }, "hosts": func() (cli.Command, error) { return &hostscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "hosts read": func() (cli.Command, error) { return &hostscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "hosts delete": func() (cli.Command, error) { return &hostscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "hosts list": func() (cli.Command, error) { return &hostscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "hosts create": func() (cli.Command, error) { return &hostscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "hosts create static": func() (cli.Command, error) { return &hostscmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "hosts update": func() (cli.Command, error) { return &hostscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "hosts update static": func() (cli.Command, error) { return &hostscmd.StaticCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "logout": func() (cli.Command, error) { return &logout.LogoutCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "managed-groups": func() (cli.Command, error) { return &managedgroupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "managed-groups read": func() (cli.Command, error) { return &managedgroupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "managed-groups delete": func() (cli.Command, error) { return &managedgroupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "managed-groups list": func() (cli.Command, error) { return &managedgroupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "managed-groups create": func() (cli.Command, error) { return &managedgroupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "managed-groups create oidc": func() (cli.Command, error) { return &managedgroupscmd.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "managed-groups create ldap": func() (cli.Command, error) { return &managedgroupscmd.LdapCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "managed-groups update": func() (cli.Command, error) { return &managedgroupscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "managed-groups update oidc": func() (cli.Command, error) { return &managedgroupscmd.OidcCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "managed-groups update ldap": func() (cli.Command, error) { return &managedgroupscmd.LdapCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, + "read": func() (cli.Command, error) { + return &genericcmd.Command{ + Command: base.NewCommand(ui, opts...), + Func: "read", + }, nil + }, + "roles": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "roles create": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "roles update": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "roles read": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "roles delete": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "roles list": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "roles add-principals": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-principals", }, nil }, "roles set-principals": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-principals", }, nil }, "roles remove-principals": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-principals", }, nil }, "roles add-grants": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-grants", }, nil }, "roles set-grants": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-grants", }, nil }, "roles remove-grants": func() (cli.Command, error) { return &rolescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-grants", }, nil }, "scopes": func() (cli.Command, error) { return &scopescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "scopes create": func() (cli.Command, error) { return &scopescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "scopes read": func() (cli.Command, error) { return &scopescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "scopes update": func() (cli.Command, error) { return &scopescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "scopes delete": func() (cli.Command, error) { return &scopescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "scopes list": func() (cli.Command, error) { return &scopescmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "scopes list-keys": func() (cli.Command, error) { return &scopescmd.ListKeysCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "scopes rotate-keys": func() (cli.Command, error) { return &scopescmd.RotateKeysCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "scopes list-key-version-destruction-jobs": func() (cli.Command, error) { return &scopescmd.ListKeyVersionDestructionJobsCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "scopes destroy-key-version": func() (cli.Command, error) { return &scopescmd.DestroyKeyVersionCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "sessions": func() (cli.Command, error) { return &sessionscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "sessions read": func() (cli.Command, error) { return &sessionscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "sessions list": func() (cli.Command, error) { return &sessionscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "sessions cancel": func() (cli.Command, error) { return &sessionscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "cancel", }, nil }, "session-recordings": func() (cli.Command, error) { return &sessionrecordingscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "session-recordings read": func() (cli.Command, error) { return &sessionrecordingscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "session-recordings list": func() (cli.Command, error) { return &sessionrecordingscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "session-recordings download": func() (cli.Command, error) { return &sessionrecordingscmd.DownloadCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "storage-buckets": func() (cli.Command, error) { return &storagebucketscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "storage-buckets read": func() (cli.Command, error) { return &storagebucketscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "storage-buckets delete": func() (cli.Command, error) { return &storagebucketscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "storage-buckets list": func() (cli.Command, error) { return &storagebucketscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "storage-buckets create": func() (cli.Command, error) { return &storagebucketscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "storage-buckets update": func() (cli.Command, error) { return &storagebucketscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "targets": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "targets authorize-session": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "authorize-session", }, nil }, "targets read": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "targets delete": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "targets list": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "targets create": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "targets create tcp": func() (cli.Command, error) { return &targetscmd.TcpCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "targets create ssh": func() (cli.Command, error) { return &targetscmd.SshCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "targets update": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "targets update tcp": func() (cli.Command, error) { return &targetscmd.TcpCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "targets update ssh": func() (cli.Command, error) { return &targetscmd.SshCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "targets add-host-sources": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-host-sources", }, nil }, "targets remove-host-sources": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-host-sources", }, nil }, "targets set-host-sources": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-host-sources", }, nil }, "targets add-credential-sources": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-credential-sources", }, nil }, "targets remove-credential-sources": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-credential-sources", }, nil }, "targets set-credential-sources": func() (cli.Command, error) { return &targetscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-credential-sources", }, nil }, + "update": func() (cli.Command, error) { + return &genericcmd.Command{ + Command: base.NewCommand(ui, opts...), + Func: "update", + }, nil + }, + "users": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "users create": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "users read": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "users update": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "users delete": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "users list": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "users add-accounts": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-accounts", }, nil }, "users set-accounts": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-accounts", }, nil }, "users remove-accounts": func() (cli.Command, error) { return &userscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-accounts", }, nil }, "workers": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "workers create": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "workers create worker-led": func() (cli.Command, error) { return &workerscmd.WorkerLedCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "workers create controller-led": func() (cli.Command, error) { return &workerscmd.ControllerLedCommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "create", }, nil }, "workers read": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "workers update": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "update", }, nil }, "workers delete": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "delete", }, nil }, "workers list": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "list", }, nil }, "workers add-worker-tags": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "add-worker-tags", }, nil }, "workers set-worker-tags": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "set-worker-tags", }, nil }, "workers remove-worker-tags": func() (cli.Command, error) { return &workerscmd.Command{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "remove-worker-tags", }, nil }, "workers certificate-authority": func() (cli.Command, error) { return &workerscmd.WorkerCACommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), }, nil }, "workers certificate-authority read": func() (cli.Command, error) { return &workerscmd.WorkerCACommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "read", }, nil }, "workers certificate-authority reinitialize": func() (cli.Command, error) { return &workerscmd.WorkerCACommand{ - Command: base.NewCommand(ui), + Command: base.NewCommand(ui, opts...), Func: "reinitialize", }, nil }, diff --git a/internal/cmd/commands/authenticate/authenticate.go b/internal/cmd/commands/authenticate/authenticate.go index affb0f4fe..9ca5f7c0b 100644 --- a/internal/cmd/commands/authenticate/authenticate.go +++ b/internal/cmd/commands/authenticate/authenticate.go @@ -24,7 +24,7 @@ type Command struct { } func (c *Command) Synopsis() string { - return wordwrap.WrapString("Authenticate the Boundary command-line client", base.TermWidth) + return wordwrap.WrapString("Authenticate the local client", base.TermWidth) } func (c *Command) Help() string { diff --git a/internal/cmd/commands/config/config.go b/internal/cmd/commands/config/config.go index 2435295b2..fc2e6d8da 100644 --- a/internal/cmd/commands/config/config.go +++ b/internal/cmd/commands/config/config.go @@ -15,7 +15,7 @@ type Command struct { } func (c *Command) Synopsis() string { - return "Manage resources related to Boundary's local configuration" + return "Manage the local client's configuration" } func (c *Command) Help() string { diff --git a/internal/cmd/commands/genericcmd/generic.go b/internal/cmd/commands/genericcmd/generic.go new file mode 100644 index 000000000..625eb22de --- /dev/null +++ b/internal/cmd/commands/genericcmd/generic.go @@ -0,0 +1,44 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package genericcmd + +import ( + "fmt" + + "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/mitchellh/cli" +) + +var _ cli.Command = (*Command)(nil) + +type Command struct { + *base.Command + + Func string +} + +func (c *Command) Synopsis() string { + return fmt.Sprintf("Run a generic %s command against a resource", c.Func) +} + +func (c *Command) Help() string { + aAn := "a" + if c.Func == "update" { + aAn = "an" + } + return base.WrapForHelpText([]string{ + fmt.Sprintf("Usage: boundary %s [resource ID] [args]", c.Func), + "", + fmt.Sprintf(" This command runs %s %s command against the given resource ID. Arguments are the same as the type-specific command.", aAn, c.Func), + "", + fmt.Sprintf(" Note: this command forwards to a type-specific command; help/error/cURL output from that command may show the full command syntax."), + }) +} + +func (c *Command) Run(args []string) int { + if len(args) > 0 { + return cli.RunResultHelp + } + return base.CommandSuccess +} diff --git a/internal/cmd/common/flags.go b/internal/cmd/common/flags.go index 97e6177d8..387cb595c 100644 --- a/internal/cmd/common/flags.go +++ b/internal/cmd/common/flags.go @@ -54,9 +54,10 @@ func PopulateCommonFlags(c *base.Command, f *base.FlagSet, resourceType string, }) case "id": f.StringVar(&base.StringVar{ - Name: "id", - Target: &c.FlagId, - Usage: fmt.Sprintf("ID of the %s on which to operate.", resourceType), + Name: "id", + Target: &c.FlagId, + Default: c.FlagId, + Usage: fmt.Sprintf("ID of the %s on which to operate.", resourceType), }) case "name": f.StringVar(&base.StringVar{ diff --git a/internal/cmd/main.go b/internal/cmd/main.go index 474d30799..6d0114281 100644 --- a/internal/cmd/main.go +++ b/internal/cmd/main.go @@ -8,15 +8,17 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "os" "sort" + "strconv" "strings" "text/tabwriter" "github.com/fatih/color" "github.com/hashicorp/boundary/api" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/hashicorp/boundary/internal/types/resource" colorable "github.com/mattn/go-colorable" "github.com/mitchellh/cli" ) @@ -85,10 +87,55 @@ func setupEnv(args []string) (retArgs []string, format string, outputCurlString return args, format, outputCurlString } +func handleHighLevelShortcuts(args []string, runOpts *RunOptions) []string { + switch len(args) { + case 0, 1: + return args + } + + switch strings.ToLower(args[0]) { + case "read", "update", "delete": + default: + return args + } + + // At this point we know it's something we want to handle in this function + info := globals.ResourceInfoFromPrefix(args[1]) + if info.Type == resource.Unknown { + return args + } + + newArgs := make([]string, 0, len(args)+5) + newArgs = append(newArgs, + // Start with the plural of the resource type ("credential-libraries") + info.Type.PluralString(), + // Add the action to take ("update") + args[0], + ) + // If it's update, add the subtype + if info.Subtype != globals.UnknownSubtype && + strings.ToLower(args[0]) == "update" { + newArgs = append(newArgs, + strings.ReplaceAll(info.Subtype.String(), "_", "-"), + ) + } + + // Make sure we override the ID in commands + runOpts.ImplicitId = args[1] + + // Now add the rest of the args + newArgs = append(newArgs, + args[2:]..., + ) + + return newArgs +} + type RunOptions struct { - Stdout io.Writer - Stderr io.Writer - Address string + Stdout io.Writer + Stderr io.Writer + Address string + ImplicitId string } func Run(args []string) int { @@ -134,7 +181,7 @@ func RunCustom(args []string, runOpts *RunOptions) int { uiErrWriter := runOpts.Stderr if outputCurlString { - uiErrWriter = ioutil.Discard + uiErrWriter = io.Discard } ui := &base.BoundaryUI{ @@ -169,6 +216,29 @@ func RunCustom(args []string, runOpts *RunOptions) int { return 1 } + // For autocompletion we need to manage the COMP_LINE var. That means + // reading args out of it now and then setting updated args back. + compLine := os.Getenv("COMP_LINE") + if compLine != "" { + point, err := strconv.Atoi(os.Getenv("COMP_POINT")) + if err != nil { + point = len(compLine) + } + if point != 0 && point < len(compLine) { + compLine = compLine[:point] + } + args = strings.Split(compLine, " ") + args = args[1:] // elide "boundary" since the function below expects it to not be there + } + + args = handleHighLevelShortcuts(args, runOpts) + + // Set args back + if compLine != "" { + // We need to add back "boundary" as well + os.Setenv("COMP_LINE", strings.Join(append([]string{"boundary"}, args...), " ")) + } + initCommands(ui, serverCmdUi, runOpts) hiddenCommands := []string{"version"} @@ -222,15 +292,38 @@ func groupedHelpFunc(f cli.HelpFunc) cli.HelpFunc { fmt.Fprintf(tw, "Usage: boundary [args]\n") - otherCommands := make([]string, 0, len(commands)) + genericCommands := make([]string, 0, 3) + clientCommands := make([]string, 0, 6) + typeSpecificCommands := make([]string, 0, len(commands)-cap(genericCommands)-cap(clientCommands)) for k := range commands { - otherCommands = append(otherCommands, k) + switch k { + case "authenticate", "config", "connect", "dev", "logout", "server": + clientCommands = append(clientCommands, k) + case "read", "update", "delete": + genericCommands = append(genericCommands, k) + default: + typeSpecificCommands = append(typeSpecificCommands, k) + } } - sort.Strings(otherCommands) + sort.Strings(clientCommands) fmt.Fprintf(tw, "\n") - fmt.Fprintf(tw, "Commands:\n") - for _, v := range otherCommands { + fmt.Fprintf(tw, "Local/Client Commands:\n") + for _, v := range clientCommands { + printCommand(tw, v, commands[v]) + } + + sort.Strings(genericCommands) + fmt.Fprintf(tw, "\n") + fmt.Fprintf(tw, "Generic Commands:\n") + for _, v := range genericCommands { + printCommand(tw, v, commands[v]) + } + + sort.Strings(typeSpecificCommands) + fmt.Fprintf(tw, "\n") + fmt.Fprintf(tw, "Type-Specific Commands:\n") + for _, v := range typeSpecificCommands { printCommand(tw, v, commands[v]) } diff --git a/internal/cmd/main_test.go b/internal/cmd/main_test.go new file mode 100644 index 000000000..bc6251804 --- /dev/null +++ b/internal/cmd/main_test.go @@ -0,0 +1,73 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package cmd + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestHandleHighLevelShortcuts(t *testing.T) { + t.Parallel() + tests := []struct { + name string + in []string + out []string + expRunOpts bool + }{ + { + name: "zero length", + }, + { + name: "one length", + in: []string{"foo"}, + out: []string{"foo"}, + }, + { + name: "not a match", + in: []string{"foo", "bar"}, + out: []string{"foo", "bar"}, + }, + { + name: "unhandled prefix", + in: []string{"read", "bar"}, + out: []string{"read", "bar"}, + }, + { + name: "handled read", + in: []string{"read", "hst_1234567890"}, + out: []string{"hosts", "read"}, + expRunOpts: true, + }, + { + name: "handled delete", + in: []string{"delete", "clvlt_1234567890"}, + out: []string{"credential-libraries", "delete"}, + expRunOpts: true, + }, + { + name: "handled update", + in: []string{"update", "g_1234567890"}, + out: []string{"groups", "update"}, + expRunOpts: true, + }, + { + name: "handled subtype update", + in: []string{"update", "credspk_1234567890"}, + out: []string{"credentials", "update", "ssh-private-key"}, + expRunOpts: true, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var runOpts RunOptions + out := handleHighLevelShortcuts(tc.in, &runOpts) + assert.EqualValues(t, tc.out, out) + if tc.expRunOpts { + assert.Equal(t, tc.in[1], runOpts.ImplicitId) + } + }) + } +} diff --git a/internal/credential/public_ids.go b/internal/credential/public_ids.go index 44865930b..291e34d0d 100644 --- a/internal/credential/public_ids.go +++ b/internal/credential/public_ids.go @@ -9,27 +9,22 @@ import ( "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(Domain, UsernamePasswordSubtype, globals.UsernamePasswordCredentialPrefix, globals.UsernamePasswordCredentialPreviousPrefix); err != nil { - panic(err) - } - if err := subtypes.Register(Domain, SshPrivateKeySubtype, globals.SshPrivateKeyCredentialPrefix); err != nil { - panic(err) - } - if err := subtypes.Register(Domain, JsonSubtype, globals.JsonCredentialPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.UsernamePasswordCredentialPrefix, resource.Credential, Domain, UsernamePasswordSubtype) + globals.RegisterPrefixToResourceInfo(globals.UsernamePasswordCredentialPreviousPrefix, resource.Credential, Domain, UsernamePasswordSubtype) + globals.RegisterPrefixToResourceInfo(globals.SshPrivateKeyCredentialPrefix, resource.Credential, Domain, SshPrivateKeySubtype) + globals.RegisterPrefixToResourceInfo(globals.JsonCredentialPrefix, resource.Credential, Domain, JsonSubtype) } const ( - UsernamePasswordSubtype = subtypes.Subtype("username_password") + UsernamePasswordSubtype = globals.Subtype("username_password") - SshPrivateKeySubtype = subtypes.Subtype("ssh_private_key") + SshPrivateKeySubtype = globals.Subtype("ssh_private_key") - JsonSubtype = subtypes.Subtype("json") + JsonSubtype = globals.Subtype("json") ) func NewUsernamePasswordCredentialId(ctx context.Context) (string, error) { diff --git a/internal/credential/static/public_ids.go b/internal/credential/static/public_ids.go index 2aa535a77..de5af1878 100644 --- a/internal/credential/static/public_ids.go +++ b/internal/credential/static/public_ids.go @@ -10,18 +10,17 @@ import ( "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(credential.Domain, Subtype, globals.StaticCredentialStorePrefix, globals.StaticCredentialStorePreviousPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.StaticCredentialStorePrefix, resource.CredentialStore, credential.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.StaticCredentialStorePreviousPrefix, resource.CredentialStore, credential.Domain, Subtype) } // PublicId prefixes for the resources in the static package. const ( - Subtype = subtypes.Subtype("static") + Subtype = globals.Subtype("static") ) func newCredentialStoreId(ctx context.Context) (string, error) { diff --git a/internal/credential/static/repository_credential.go b/internal/credential/static/repository_credential.go index b9e7eeaeb..82c3c951d 100644 --- a/internal/credential/static/repository_credential.go +++ b/internal/credential/static/repository_credential.go @@ -8,12 +8,12 @@ import ( "fmt" "strings" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" - "github.com/hashicorp/boundary/internal/types/subtypes" "github.com/hashicorp/go-dbw" ) @@ -289,7 +289,7 @@ func (r *Repository) LookupCredential(ctx context.Context, publicId string, _ .. var cred credential.Static - switch subtypes.SubtypeFromId(credential.Domain, publicId) { + switch globals.ResourceInfoFromPrefix(publicId).Subtype { case credential.UsernamePasswordSubtype: upCred := allocUsernamePasswordCredential() upCred.PublicId = publicId @@ -792,7 +792,7 @@ func (r *Repository) DeleteCredential(ctx context.Context, projectId, id string, var input any var md oplog.Metadata - switch subtypes.SubtypeFromId(credential.Domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case credential.UsernamePasswordSubtype: c := allocUsernamePasswordCredential() c.PublicId = id diff --git a/internal/credential/vault/public_ids.go b/internal/credential/vault/public_ids.go index b54e11fe2..cdea3f7ae 100644 --- a/internal/credential/vault/public_ids.go +++ b/internal/credential/vault/public_ids.go @@ -10,26 +10,21 @@ import ( "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(credential.Domain, Subtype, globals.VaultCredentialStorePrefix, globals.VaultDynamicCredentialPrefix); err != nil { - panic(err) - } - if err := subtypes.Register(credential.Domain, GenericLibrarySubtype, globals.VaultCredentialLibraryPrefix); err != nil { - panic(err) - } - if err := subtypes.Register(credential.Domain, SSHCertificateLibrarySubtype, globals.VaultSshCertificateCredentialLibraryPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.VaultCredentialStorePrefix, resource.CredentialStore, credential.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.VaultDynamicCredentialPrefix, resource.Credential, credential.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.VaultCredentialLibraryPrefix, resource.CredentialLibrary, credential.Domain, GenericLibrarySubtype) + globals.RegisterPrefixToResourceInfo(globals.VaultSshCertificateCredentialLibraryPrefix, resource.CredentialLibrary, credential.Domain, SSHCertificateLibrarySubtype) } // PublicId prefixes for the resources in the vault package. const ( - Subtype = subtypes.Subtype("vault") - GenericLibrarySubtype = subtypes.Subtype("vault-generic") - SSHCertificateLibrarySubtype = subtypes.Subtype("vault-ssh-certificate") + Subtype = globals.Subtype("vault") + GenericLibrarySubtype = globals.Subtype("vault-generic") + SSHCertificateLibrarySubtype = globals.Subtype("vault-ssh-certificate") ) func newCredentialStoreId(ctx context.Context) (string, error) { diff --git a/internal/daemon/controller/auth/auth.go b/internal/daemon/controller/auth/auth.go index 21823f69f..0fc8b5920 100644 --- a/internal/daemon/controller/auth/auth.go +++ b/internal/daemon/controller/auth/auth.go @@ -31,7 +31,6 @@ import ( "github.com/hashicorp/boundary/internal/types/action" "github.com/hashicorp/boundary/internal/types/resource" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/types/subtypes" "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/boundary/internal/util/template" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" @@ -555,7 +554,7 @@ func (v verifier) performAuthCheck(ctx context.Context) ( const domain = "auth" var acct auth.Account var err error - switch subtypes.SubtypeFromId(domain, *userData.Account.Id) { + switch globals.ResourceInfoFromPrefix(*userData.Account.Id).Subtype { case password.Subtype: repo, repoErr := v.passwordAuthRepoFn() if repoErr != nil { diff --git a/internal/daemon/controller/handlers/accounts/account_service.go b/internal/daemon/controller/handlers/accounts/account_service.go index 62c263249..c6c0baada 100644 --- a/internal/daemon/controller/handlers/accounts/account_service.go +++ b/internal/daemon/controller/handlers/accounts/account_service.go @@ -69,7 +69,7 @@ var ( // IdActions contains the set of actions that can be performed on // individual resources - IdActions = map[subtypes.Subtype]action.ActionSet{ + IdActions = map[globals.Subtype]action.ActionSet{ password.Subtype: { action.NoOp, action.Read, @@ -165,7 +165,7 @@ func (s Service) ListAccounts(ctx context.Context, req *pbs.ListAccountsRequest) } for _, acct := range ul { res.Id = acct.GetPublicId() - authorizedActions := authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, acct.GetPublicId())], requestauth.WithResource(&res)).Strings() + authorizedActions := authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(acct.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings() if len(authorizedActions) == 0 { continue } @@ -226,7 +226,7 @@ func (s Service) GetAccount(ctx context.Context, req *pbs.GetAccountRequest) (*p outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, acct.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(acct.GetPublicId()).Subtype]).Strings())) } if outputFields.Has(globals.ManagedGroupIdsField) { outputOpts = append(outputOpts, handlers.WithManagedGroupIds(mgIds)) @@ -268,7 +268,7 @@ func (s Service) CreateAccount(ctx context.Context, req *pbs.CreateAccountReques outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, acct.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(acct.GetPublicId()).Subtype]).Strings())) } item, err := toProto(ctx, acct, outputOpts...) @@ -307,7 +307,7 @@ func (s Service) UpdateAccount(ctx context.Context, req *pbs.UpdateAccountReques outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, acct.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(acct.GetPublicId()).Subtype]).Strings())) } item, err := toProto(ctx, acct, outputOpts...) @@ -362,7 +362,7 @@ func (s Service) ChangePassword(ctx context.Context, req *pbs.ChangePasswordRequ outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, acct.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(acct.GetPublicId()).Subtype]).Strings())) } item, err := toProto(ctx, acct, outputOpts...) @@ -401,7 +401,7 @@ func (s Service) SetPassword(ctx context.Context, req *pbs.SetPasswordRequest) ( outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, acct.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, acct.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(acct.GetPublicId()).Subtype]).Strings())) } item, err := toProto(ctx, acct, outputOpts...) @@ -417,7 +417,7 @@ func (s Service) SetPassword(ctx context.Context, req *pbs.SetPasswordRequest) ( func (s Service) getFromRepo(ctx context.Context, id string) (auth.Account, []string, error) { var acct auth.Account var mgIds []string - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case password.Subtype: repo, err := s.pwRepoFn() if err != nil { @@ -592,7 +592,7 @@ func (s Service) createInRepo(ctx context.Context, am auth.AuthMethod, item *pb. return nil, errors.New(ctx, errors.InvalidParameter, op, "missing item") } var out auth.Account - switch subtypes.SubtypeFromId(domain, am.GetPublicId()) { + switch globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype { case password.Subtype: am, err := s.createPwInRepo(ctx, am, item) if err != nil { @@ -752,7 +752,7 @@ func (s Service) updateLdapInRepo(ctx context.Context, scopeId, amId, id string, func (s Service) updateInRepo(ctx context.Context, scopeId, authMethodId string, req *pbs.UpdateAccountRequest) (auth.Account, error) { const op = "accounts.(Service).updateInRepo" var out auth.Account - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case password.Subtype: a, err := s.updatePwInRepo(ctx, scopeId, authMethodId, req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem()) if err != nil { @@ -788,7 +788,7 @@ func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, const op = "accounts.(Service).deleteFromRepo" var rows int var err error - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case password.Subtype: repo, iErr := s.pwRepoFn() if iErr != nil { @@ -821,7 +821,7 @@ func (s Service) listFromRepo(ctx context.Context, authMethodId string) ([]auth. const op = "accounts.(Service).listFromRepo" var outUl []auth.Account - switch subtypes.SubtypeFromId(domain, authMethodId) { + switch globals.ResourceInfoFromPrefix(authMethodId).Subtype { case password.Subtype: pwRepo, err := s.pwRepoFn() if err != nil { @@ -933,7 +933,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty case action.List, action.Create: parentId = id default: - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case password.Subtype: acct, err := pwRepo.LookupAccount(ctx, id) if err != nil { @@ -972,7 +972,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty } var authMeth auth.AuthMethod - switch subtypes.SubtypeFromId(domain, parentId) { + switch globals.ResourceInfoFromPrefix(parentId).Subtype { case password.Subtype: am, err := pwRepo.LookupAuthMethod(ctx, parentId) if err != nil { @@ -1174,7 +1174,7 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateAccountRequest) e if req.GetItem().GetAuthMethodId() == "" { badFields[authMethodIdField] = "This field is required." } - switch subtypes.SubtypeFromId(domain, req.GetItem().GetAuthMethodId()) { + switch globals.ResourceInfoFromPrefix(req.GetItem().GetAuthMethodId()).Subtype { case password.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != password.Subtype.String() { badFields[typeField] = "Doesn't match the parent resource's type." @@ -1255,7 +1255,7 @@ func validateUpdateRequest(ctx context.Context, req *pbs.UpdateAccountRequest) e } return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string { badFields := map[string]string{} - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case password.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != password.Subtype.String() { badFields[typeField] = "Cannot modify the resource type." diff --git a/internal/daemon/controller/handlers/accounts/account_service_test.go b/internal/daemon/controller/handlers/accounts/account_service_test.go index 990c83e73..cafc57c1e 100644 --- a/internal/daemon/controller/handlers/accounts/account_service_test.go +++ b/internal/daemon/controller/handlers/accounts/account_service_test.go @@ -26,7 +26,6 @@ import ( "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/types/action" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/types/subtypes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/accounts" scopepb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" "github.com/stretchr/testify/assert" @@ -280,7 +279,7 @@ func TestGet(t *testing.T) { t.Run(tc.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) - if subtypes.SubtypeFromId(domain, tc.req.Id) == oidc.Subtype { + if globals.ResourceInfoFromPrefix(tc.req.Id).Subtype == oidc.Subtype { // Set up managed groups before getting. First get the current // managed group to make sure we have the right version. oidcRepo, err := oidcRepoFn() diff --git a/internal/daemon/controller/handlers/authmethods/authmethod_service.go b/internal/daemon/controller/handlers/authmethods/authmethod_service.go index 29f2f9ecd..834ca8769 100644 --- a/internal/daemon/controller/handlers/authmethods/authmethod_service.go +++ b/internal/daemon/controller/handlers/authmethods/authmethod_service.go @@ -64,7 +64,7 @@ const ( var ( // IdActions contains the set of actions that can be performed on // individual resources - IdActions = make(map[subtypes.Subtype]action.ActionSet) + IdActions = make(map[globals.Subtype]action.ActionSet) // CollectionActions contains the set of actions that can be performed on // this collection @@ -167,7 +167,7 @@ func (s Service) ListAuthMethods(ctx context.Context, req *pbs.ListAuthMethodsRe for _, am := range ul { res.Id = am.GetPublicId() res.ScopeId = am.GetScopeId() - authorizedActions := authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, am.GetPublicId())], requestauth.WithResource(&res)).Strings() + authorizedActions := authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings() if len(authorizedActions) == 0 { continue } @@ -234,7 +234,7 @@ func (s Service) GetAuthMethod(ctx context.Context, req *pbs.GetAuthMethodReques outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, am.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype]).Strings())) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { collectionActions, err := requestauth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, am.GetPublicId()) @@ -279,7 +279,7 @@ func (s Service) CreateAuthMethod(ctx context.Context, req *pbs.CreateAuthMethod outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, am.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype]).Strings())) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { collectionActions, err := requestauth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, am.GetPublicId()) @@ -329,7 +329,7 @@ func (s Service) UpdateAuthMethod(ctx context.Context, req *pbs.UpdateAuthMethod outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, am.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype]).Strings())) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { collectionActions, err := requestauth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, am.GetPublicId()) @@ -383,7 +383,7 @@ func (s Service) ChangeState(ctx context.Context, req *pbs.ChangeStateRequest) ( outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, am.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype]).Strings())) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { collectionActions, err := requestauth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, am.GetPublicId()) @@ -424,7 +424,7 @@ func (s Service) Authenticate(ctx context.Context, req *pbs.AuthenticateRequest) return nil, err } - switch subtypes.SubtypeFromId(domain, req.GetAuthMethodId()) { + switch globals.ResourceInfoFromPrefix(req.GetAuthMethodId()).Subtype { case password.Subtype: if err := validateAuthenticatePasswordRequest(req); err != nil { return nil, err @@ -444,7 +444,7 @@ func (s Service) Authenticate(ctx context.Context, req *pbs.AuthenticateRequest) return nil, authResults.Error } - switch subtypes.SubtypeFromId(domain, req.GetAuthMethodId()) { + switch globals.ResourceInfoFromPrefix(req.GetAuthMethodId()).Subtype { case password.Subtype: return s.authenticatePassword(ctx, req, &authResults) @@ -459,7 +459,7 @@ func (s Service) Authenticate(ctx context.Context, req *pbs.AuthenticateRequest) func (s Service) getFromRepo(ctx context.Context, id string) (auth.AuthMethod, error) { var lookupErr error var am auth.AuthMethod - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case password.Subtype: repo, err := s.pwRepoFn() if err != nil { @@ -549,8 +549,8 @@ func (s Service) listFromRepo(ctx context.Context, scopeIds []string, authResult func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.AuthMethod) (auth.AuthMethod, error) { const op = "authmethods.(Service).createInRepo" var out auth.AuthMethod - switch subtypes.SubtypeFromType(domain, item.GetType()) { - case password.Subtype: + switch item.GetType() { + case password.Subtype.String(): am, err := s.createPwInRepo(ctx, scopeId, item) if err != nil { return nil, errors.Wrap(ctx, err, op) @@ -559,7 +559,7 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Auth return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create auth method but no error returned from repository.") } out = am - case oidc.Subtype: + case oidc.Subtype.String(): am, err := s.createOidcInRepo(ctx, scopeId, item) if err != nil { return nil, errors.Wrap(ctx, err, op) @@ -568,7 +568,7 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Auth return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create auth method but no error returned from repository.") } out = am - case ldap.Subtype: + case ldap.Subtype.String(): am, err := s.createLdapInRepo(ctx, scopeId, item) if err != nil { return nil, errors.Wrap(ctx, err, op) @@ -587,7 +587,7 @@ func (s Service) updateInRepo(ctx context.Context, scopeId string, req *pbs.Upda var am auth.AuthMethod var dryRun bool - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case password.Subtype: pam, err := s.updatePwInRepo(ctx, scopeId, req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem()) if err != nil { @@ -635,7 +635,7 @@ func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, const op = "authmethods.(Service).deleteFromRepo" var rows int var dErr error - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case password.Subtype: repo, err := s.pwRepoFn() if err != nil { @@ -656,7 +656,7 @@ func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, } rows, dErr = repo.DeleteAuthMethod(ctx, id) default: - return false, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("invalid auth method subtype: %q", subtypes.SubtypeFromId(domain, id))) + return false, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("invalid auth method subtype: %q", globals.ResourceInfoFromPrefix(id).Subtype.String())) } if dErr != nil { @@ -672,7 +672,7 @@ func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, func (s Service) changeStateInRepo(ctx context.Context, req *pbs.ChangeStateRequest) (auth.AuthMethod, error) { const op = "authmethod_service.(Service).changeStateInRepo" - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case oidc.Subtype: repo, err := s.oidcRepoFn() if err != nil { @@ -731,7 +731,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) reque } default: var authMeth auth.AuthMethod - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case password.Subtype: repo, err := s.pwRepoFn() if err != nil { @@ -987,10 +987,10 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateAuthMethodRequest if req.GetItem().GetIsPrimary() { badFields[isPrimaryField] = "This field is read only." } - switch subtypes.SubtypeFromType(domain, req.GetItem().GetType()) { - case password.Subtype: + switch req.GetItem().GetType() { + case password.Subtype.String(): // Password attributes are not required when creating a password auth method. - case oidc.Subtype: + case oidc.Subtype.String(): attrs := req.GetItem().GetOidcAuthMethodsAttributes() if attrs == nil { // OIDC attributes are required when creating an OIDC auth method. @@ -1066,7 +1066,7 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateAuthMethodRequest } } } - case ldap.Subtype: + case ldap.Subtype.String(): if len(req.GetItem().GetLdapAuthMethodsAttributes().GetUrls()) == 0 { badFields[urlsField] = "At least one URL is required" } @@ -1088,13 +1088,13 @@ func validateUpdateRequest(ctx context.Context, req *pbs.UpdateAuthMethodRequest if handlers.MaskContains(req.GetUpdateMask().GetPaths(), isPrimaryField) { badFields[isPrimaryField] = "This field is read only." } - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case password.Subtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != password.Subtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != password.Subtype.String() { badFields[typeField] = "Cannot modify the resource type." } case oidc.Subtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != oidc.Subtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != oidc.Subtype.String() { badFields[typeField] = "Cannot modify the resource type." } attrs := req.GetItem().GetOidcAuthMethodsAttributes() @@ -1198,7 +1198,7 @@ func validateUpdateRequest(ctx context.Context, req *pbs.UpdateAuthMethodRequest } } case ldap.Subtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != ldap.Subtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != ldap.Subtype.String() { badFields[typeField] = "Cannot modify the resource type." } validateLdapAttributes(ctx, req.GetItem().GetLdapAuthMethodsAttributes(), badFields) @@ -1241,7 +1241,7 @@ func validateChangeStateRequest(ctx context.Context, req *pbs.ChangeStateRequest if req == nil { return errors.New(ctx, errors.InvalidParameter, op, "Missing request") } - if st := subtypes.SubtypeFromId(domain, req.GetId()); st != oidc.Subtype { + if st := globals.ResourceInfoFromPrefix(req.GetId()).Subtype; st != oidc.Subtype { return handlers.NotFoundErrorf("This endpoint is only available for the %q Auth Method type.", oidc.Subtype.String()) } badFields := make(map[string]string) @@ -1276,7 +1276,7 @@ func validateAuthenticateRequest(ctx context.Context, req *pbs.AuthenticateReque if strings.TrimSpace(req.GetAuthMethodId()) == "" { badFields[authMethodIdField] = "This is a required field." } else { - st := subtypes.SubtypeFromId(domain, req.GetAuthMethodId()) + st := globals.ResourceInfoFromPrefix(req.GetAuthMethodId()).Subtype switch st { case password.Subtype, oidc.Subtype, ldap.Subtype: default: @@ -1380,7 +1380,7 @@ func transformAuthenticateRequestAttributes(msg proto.Message) error { if attrs == nil { return nil } - switch subtypes.SubtypeFromId(domain, authRequest.GetAuthMethodId()) { + switch globals.ResourceInfoFromPrefix(authRequest.GetAuthMethodId()).Subtype { case password.Subtype: newAttrs := &pbs.PasswordLoginAttributes{} if err := handlers.StructToProto(attrs, newAttrs); err != nil { diff --git a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go index e12447baa..dbbe0e26b 100644 --- a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go +++ b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go @@ -277,7 +277,7 @@ func (s Service) UpdateCredentialLibrary(ctx context.Context, req *pbs.UpdateCre } var currentCredentialType globals.CredentialType var mo vault.MappingOverride - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case vault.SSHCertificateLibrarySubtype: cur, err := repo.LookupSSHCertificateCredentialLibrary(ctx, req.Id) if err != nil { @@ -374,7 +374,7 @@ func (s Service) getFromRepo(ctx context.Context, id string) (credential.Library if err != nil { return nil, errors.Wrap(ctx, err, op) } - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.GenericLibrarySubtype: cs, err := repo.LookupCredentialLibrary(ctx, id) if err != nil && !errors.IsNotFoundError(err) { @@ -400,8 +400,8 @@ func (s Service) getFromRepo(ctx context.Context, id string) (credential.Library func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.CredentialLibrary) (credential.Library, error) { const op = "credentiallibraries.(Service).createInRepo" var out credential.Library - switch subtypes.SubtypeFromType(domain, item.GetType()) { - case vault.SSHCertificateLibrarySubtype: + switch item.GetType() { + case vault.SSHCertificateLibrarySubtype.String(): cl, err := toStorageVaultSSHCertificateLibrary(ctx, item.GetCredentialStoreId(), item) if err != nil { return nil, errors.Wrap(ctx, err, op) @@ -470,7 +470,7 @@ func (s Service) updateInRepo( if err != nil { return nil, errors.Wrap(ctx, err, op) } - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.SSHCertificateLibrarySubtype: dbMasks = append(dbMasks, sshCertMaskManager.Translate(masks)...) if getMapUpdate(criticalOptionsField, masks) { @@ -522,7 +522,7 @@ func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, return false, err } rows := 0 - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.SSHCertificateLibrarySubtype: rows, err = repo.DeleteSSHCertificateCredentialLibrary(ctx, scopeId, id) default: @@ -554,7 +554,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. default: opts = append(opts, auth.WithId(id)) parentId = id - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.GenericLibrarySubtype: cl, err := repo.LookupCredentialLibrary(ctx, id) if err != nil { @@ -590,7 +590,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. opts = append(opts, auth.WithPin(parentId)) - switch subtypes.SubtypeFromId(domain, parentId) { + switch globals.ResourceInfoFromPrefix(parentId).Subtype { case vault.Subtype: cs, err := repo.LookupCredentialStore(ctx, parentId) if err != nil { @@ -627,7 +627,7 @@ func toProto(ctx context.Context, in credential.Library, opt ...handlers.Option) out.CredentialStoreId = in.GetStoreId() } if outputFields.Has(globals.TypeField) { - out.Type = subtypes.SubtypeFromId(domain, in.GetPublicId()).String() + out.Type = globals.ResourceInfoFromPrefix(in.GetPublicId()).Subtype.String() } if outputFields.Has(globals.DescriptionField) && in.GetDescription() != "" { out.Description = wrapperspb.String(in.GetDescription()) @@ -650,7 +650,7 @@ func toProto(ctx context.Context, in credential.Library, opt ...handlers.Option) if outputFields.Has(globals.AuthorizedActionsField) { out.AuthorizedActions = opts.WithAuthorizedActions } - switch subtypes.SubtypeFromId(domain, in.GetPublicId()) { + switch globals.ResourceInfoFromPrefix(in.GetPublicId()).Subtype { case vault.GenericLibrarySubtype: vaultIn, ok := in.(*vault.CredentialLibrary) if !ok { @@ -879,7 +879,7 @@ func toStorageVaultSSHCertificateLibrary(ctx context.Context, storeId string, in // - There are no conflicting parameters provided func validateGetRequest(req *pbs.GetCredentialLibraryRequest) error { prefix := "" - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case vault.SSHCertificateLibrarySubtype: prefix = globals.VaultSshCertificateCredentialLibraryPrefix default: @@ -891,7 +891,7 @@ func validateGetRequest(req *pbs.GetCredentialLibraryRequest) error { func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error { return handlers.ValidateCreateRequest(req.GetItem(), func() map[string]string { badFields := map[string]string{} - switch subtypes.SubtypeFromId(domain, req.GetItem().GetCredentialStoreId()) { + switch globals.ResourceInfoFromPrefix(req.GetItem().GetCredentialStoreId()).Subtype { case vault.Subtype: var t string if version.SupportsFeature(version.Binary, version.CredentialLibraryVaultSubtype) { @@ -901,7 +901,7 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error { // subtype of vault-generic based on the credential store's subtype. // To support the deprecated subtype 'vault.Subtype', convert it // to vault-generic. - if t == "" || subtypes.SubtypeFromType(domain, t) == vault.Subtype { + if t == "" || t == vault.Subtype.String() { // fallback to assuming subtype from credential store. t = vault.GenericLibrarySubtype.String() req.GetItem().Type = t @@ -927,13 +927,13 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error { } } - if subtypes.SubtypeFromType(domain, t) != vault.GenericLibrarySubtype && - subtypes.SubtypeFromType(domain, t) != vault.SSHCertificateLibrarySubtype { + if t != vault.GenericLibrarySubtype.String() && + t != vault.SSHCertificateLibrarySubtype.String() { badFields[globals.CredentialStoreIdField] = fmt.Sprintf("Type must be a vault subtype %q or %q", vault.GenericLibrarySubtype.String(), vault.SSHCertificateLibrarySubtype.String()) } - switch subtypes.SubtypeFromType(domain, req.GetItem().GetType()) { - case vault.GenericLibrarySubtype: + switch req.GetItem().GetType() { + case vault.GenericLibrarySubtype.String(): isValidCred := false ct := req.GetItem().GetCredentialType() for _, t := range validCredentialTypesVaultGeneric { @@ -964,7 +964,7 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error { badFields[httpRequestBodyField] = fmt.Sprintf("Field can only be set if %q is set to the value 'POST'.", httpMethodField) } validateMapping(badFields, globals.CredentialType(req.GetItem().GetCredentialType()), req.GetItem().CredentialMappingOverrides.AsMap()) - case vault.SSHCertificateLibrarySubtype: + case vault.SSHCertificateLibrarySubtype.String(): if req.GetItem().GetCredentialType() != "" { badFields[globals.CredentialTypeField] = fmt.Sprintf("This field is read only and cannot be set.") } @@ -1001,7 +1001,7 @@ func validateCreateRequest(req *pbs.CreateCredentialLibraryRequest) error { func validateUpdateRequest(req *pbs.UpdateCredentialLibraryRequest, currentCredentialType globals.CredentialType) error { prefix := "" - st := subtypes.SubtypeFromId(domain, req.GetId()) + st := globals.ResourceInfoFromPrefix(req.GetId()).Subtype switch st { case vault.GenericLibrarySubtype: prefix = globals.VaultCredentialLibraryPrefix @@ -1012,7 +1012,7 @@ func validateUpdateRequest(req *pbs.UpdateCredentialLibraryRequest, currentCrede badFields := map[string]string{} switch st { case vault.GenericLibrarySubtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != vault.GenericLibrarySubtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != vault.GenericLibrarySubtype.String() { badFields[globals.TypeField] = "Cannot modify resource type." } if req.GetItem().GetCredentialType() != "" && req.GetItem().GetCredentialType() != string(currentCredentialType) { @@ -1036,7 +1036,7 @@ func validateUpdateRequest(req *pbs.UpdateCredentialLibraryRequest, currentCrede validateMapping(badFields, currentCredentialType, req.GetItem().CredentialMappingOverrides.AsMap()) } case vault.SSHCertificateLibrarySubtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != vault.SSHCertificateLibrarySubtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != vault.SSHCertificateLibrarySubtype.String() { badFields[globals.TypeField] = "Cannot modify resource type." } if req.GetItem().GetCredentialType() != "" && req.GetItem().GetCredentialType() != string(currentCredentialType) { diff --git a/internal/daemon/controller/handlers/credentials/credential_service.go b/internal/daemon/controller/handlers/credentials/credential_service.go index 16e49294f..117e0b88c 100644 --- a/internal/daemon/controller/handlers/credentials/credential_service.go +++ b/internal/daemon/controller/handlers/credentials/credential_service.go @@ -413,7 +413,7 @@ func (s Service) updateInRepo( var dbMasks []string item := proto.Clone(in).(*pb.Credential) - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case credential.UsernamePasswordSubtype: dbMasks = append(dbMasks, upMaskManager.Translate(masks)...) if len(dbMasks) == 0 { @@ -808,7 +808,7 @@ func validateCreateRequest(req *pbs.CreateCredentialRequest) error { func validateUpdateRequest(req *pbs.UpdateCredentialRequest) error { return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string { badFields := map[string]string{} - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case credential.UsernamePasswordSubtype: attrs := req.GetItem().GetUsernamePasswordAttributes() if handlers.MaskContains(req.GetUpdateMask().GetPaths(), usernameField) && attrs.GetUsername().GetValue() == "" { diff --git a/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go b/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go index 5180102de..4a0b96b39 100644 --- a/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go +++ b/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go @@ -394,7 +394,7 @@ func (s Service) listFromRepo(ctx context.Context, scopeIds []string) ([]credent func (s Service) getFromRepo(ctx context.Context, id string) (credential.Store, error) { const op = "credentialstores.(Service).getFromRepo" - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.Subtype: repo, err := s.vaultRepoFn() if err != nil { @@ -475,7 +475,7 @@ func (s Service) updateInRepo(ctx context.Context, projId, id string, mask []str return nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid fields provided in the update mask."}) } - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.Subtype: cs, err := toStorageVaultStore(ctx, projId, item) if err != nil { @@ -518,7 +518,7 @@ func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) { const op = "credentialstores.(Service).deleteFromRepo" var rows int - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.Subtype: repo, err := s.vaultRepoFn() if err != nil { @@ -581,7 +581,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. return res } default: - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.Subtype: cs, err := vaultRepo.LookupCredentialStore(ctx, id) if err != nil { @@ -630,7 +630,7 @@ func toProto(ctx context.Context, in credential.Store, opt ...handlers.Option) ( out.ScopeId = in.GetProjectId() } if outputFields.Has(globals.TypeField) { - out.Type = subtypes.SubtypeFromId(domain, in.GetPublicId()).String() + out.Type = globals.ResourceInfoFromPrefix(in.GetPublicId()).Subtype.String() } if outputFields.Has(globals.DescriptionField) && in.GetDescription() != "" { out.Description = wrapperspb.String(in.GetDescription()) @@ -657,7 +657,7 @@ func toProto(ctx context.Context, in credential.Store, opt ...handlers.Option) ( out.AuthorizedCollectionActions = opts.WithAuthorizedCollectionActions } if outputFields.Has(globals.AttributesField) { - switch subtypes.SubtypeFromId(domain, in.GetPublicId()) { + switch globals.ResourceInfoFromPrefix(in.GetPublicId()).Subtype { case vault.Subtype: vaultIn, ok := in.(*vault.CredentialStore) if !ok { @@ -790,8 +790,8 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateCredentialStoreRe if !handlers.ValidId(handlers.Id(req.GetItem().GetScopeId()), scope.Project.Prefix()) { badFields["scope_id"] = "This field must be a valid project scope id." } - switch subtypes.SubtypeFromType(domain, req.GetItem().GetType()) { - case vault.Subtype: + switch req.GetItem().GetType() { + case vault.Subtype.String(): attrs := req.GetItem().GetVaultCredentialStoreAttributes() if attrs == nil { badFields[globals.AttributesField] = "Attributes are required for creating a vault credential store" @@ -828,7 +828,7 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateCredentialStoreRe if len(cs) > 0 && pk == nil { badFields[clientCertField] = "Cannot set a client certificate without a private key." } - case static.Subtype: + case static.Subtype.String(): // No additional validation required for static credential store default: badFields[globals.TypeField] = "This is a required field and must be a known credential store type." @@ -840,9 +840,9 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateCredentialStoreRe func validateUpdateRequest(ctx context.Context, req *pbs.UpdateCredentialStoreRequest) error { return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string { badFields := map[string]string{} - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case vault.Subtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != vault.Subtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != vault.Subtype.String() { badFields["type"] = "Cannot modify resource type." } attrs := req.GetItem().GetVaultCredentialStoreAttributes() @@ -903,7 +903,7 @@ func validateListRequest(ctx context.Context, req *pbs.ListCredentialStoresReque func calculateAuthorizedCollectionActions(ctx context.Context, authResults auth.VerifyResults, id string) (map[string]*structpb.ListValue, error) { var collectionActions map[string]*structpb.ListValue var err error - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case vault.Subtype: collectionActions, err = auth.CalculateAuthorizedCollectionActions(ctx, authResults, vaultCollectionTypeMap, authResults.Scope.Id, id) diff --git a/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go b/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go index c93e00f9c..9dbb2d462 100644 --- a/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go +++ b/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go @@ -57,7 +57,7 @@ var ( action.List, } - collectionTypeMap = map[subtypes.Subtype]map[resource.Type]action.ActionSet{ + collectionTypeMap = map[globals.Subtype]map[resource.Type]action.ActionSet{ static.Subtype: { resource.HostSet: host_sets.CollectionActions, resource.Host: hosts.CollectionActions, @@ -183,7 +183,7 @@ func (s Service) ListHostCatalogs(ctx context.Context, req *pbs.ListHostCatalogs outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions)) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { - var subtype subtypes.Subtype + var subtype globals.Subtype switch item.(type) { case *static.HostCatalog: subtype = static.Subtype @@ -253,7 +253,7 @@ func (s Service) GetHostCatalog(ctx context.Context, req *pbs.GetHostCatalogRequ outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hc.GetPublicId(), IdActions).Strings())) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { - var subtype subtypes.Subtype + var subtype globals.Subtype switch hc.(type) { case *static.HostCatalog: subtype = static.Subtype @@ -310,7 +310,7 @@ func (s Service) CreateHostCatalog(ctx context.Context, req *pbs.CreateHostCatal outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hc.GetPublicId(), IdActions).Strings())) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { - var subtype subtypes.Subtype + var subtype globals.Subtype switch hc.(type) { case *static.HostCatalog: subtype = static.Subtype @@ -373,7 +373,7 @@ func (s Service) UpdateHostCatalog(ctx context.Context, req *pbs.UpdateHostCatal outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hc.GetPublicId(), IdActions).Strings())) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { - var subtype subtypes.Subtype + var subtype globals.Subtype switch hc.(type) { case *static.HostCatalog: subtype = static.Subtype @@ -415,7 +415,7 @@ func (s Service) DeleteHostCatalog(ctx context.Context, req *pbs.DeleteHostCatal func (s Service) getFromRepo(ctx context.Context, id string) (host.Catalog, *plugins.PluginInfo, error) { var plg *plugins.PluginInfo var cat host.Catalog - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -537,8 +537,8 @@ func (s Service) createPluginInRepo(ctx context.Context, projId string, req *pbs func (s Service) createInRepo(ctx context.Context, projId string, req *pbs.CreateHostCatalogRequest) (hc host.Catalog, info *plugins.PluginInfo, err error) { var plg *plugins.PluginInfo - switch subtypes.SubtypeFromType(domain, req.GetItem().GetType()) { - case static.Subtype: + switch req.GetItem().GetType() { + case static.Subtype.String(): hc, err = s.createStaticInRepo(ctx, projId, req.GetItem()) default: hc, plg, err = s.createPluginInRepo(ctx, projId, req) @@ -601,7 +601,7 @@ func (s Service) updatePluginInRepo(ctx context.Context, projId, id string, mask func (s Service) updateInRepo(ctx context.Context, projId string, req *pbs.UpdateHostCatalogRequest) (hc host.Catalog, plg *plugins.PluginInfo, err error) { const op = "host_catalogs.(Service).updateInRepo" - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case static.Subtype: hc, err = s.updateStaticInRepo(ctx, projId, req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem()) case hostplugin.Subtype: @@ -613,7 +613,7 @@ func (s Service) updateInRepo(ctx context.Context, projId string, req *pbs.Updat func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) { const op = "host_catalogs.(Service).deleteFromRepo" rows := 0 - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -659,7 +659,7 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. return res } default: - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -843,9 +843,9 @@ func validateCreateRequest(req *pbs.CreateHostCatalogRequest) error { if req.GetItem().GetSecretsHmac() != "" { badFields[globals.SecretsHmacField] = "This is a read only field." } - switch subtypes.SubtypeFromType(domain, req.GetItem().GetType()) { - case static.Subtype: - case hostplugin.Subtype: + switch req.GetItem().GetType() { + case static.Subtype.String(): + case hostplugin.Subtype.String(): if req.GetItem().GetPlugin() != nil { badFields[globals.PluginField] = "This is a read only field." } @@ -870,16 +870,16 @@ func validateUpdateRequest(req *pbs.UpdateHostCatalogRequest) error { if req.GetItem().GetSecretsHmac() != "" { badFields[globals.SecretsHmacField] = "This is a read only field." } - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case static.Subtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != static.Subtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != static.Subtype.String() { badFields[globals.TypeField] = "Cannot modify resource type." } if req.GetItem().GetPlugin() != nil { badFields[globals.PluginField] = "This field is unused for this type of host catalog." } case hostplugin.Subtype: - if req.GetItem().GetType() != "" && subtypes.SubtypeFromType(domain, req.GetItem().GetType()) != hostplugin.Subtype { + if req.GetItem().GetType() != "" && req.GetItem().GetType() != hostplugin.Subtype.String() { badFields[globals.TypeField] = "Cannot modify resource type." } if req.GetItem().GetPlugin() != nil { diff --git a/internal/daemon/controller/handlers/host_catalogs/host_catalog_service_test.go b/internal/daemon/controller/handlers/host_catalogs/host_catalog_service_test.go index 21cdf8af2..f6c8c8a8a 100644 --- a/internal/daemon/controller/handlers/host_catalogs/host_catalog_service_test.go +++ b/internal/daemon/controller/handlers/host_catalogs/host_catalog_service_test.go @@ -28,7 +28,6 @@ import ( "github.com/hashicorp/boundary/internal/plugin/loopback" "github.com/hashicorp/boundary/internal/scheduler" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/types/subtypes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/plugins" scopepb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" @@ -46,7 +45,7 @@ import ( "github.com/stretchr/testify/require" ) -var authorizedCollectionActions = map[subtypes.Subtype]map[string]*structpb.ListValue{ +var authorizedCollectionActions = map[globals.Subtype]map[string]*structpb.ListValue{ static.Subtype: { "host-sets": { Values: []*structpb.Value{ diff --git a/internal/daemon/controller/handlers/host_sets/host_set_service.go b/internal/daemon/controller/handlers/host_sets/host_set_service.go index 7e01cf404..a6d498970 100644 --- a/internal/daemon/controller/handlers/host_sets/host_set_service.go +++ b/internal/daemon/controller/handlers/host_sets/host_set_service.go @@ -35,11 +35,11 @@ import ( ) var ( - maskManager = map[subtypes.Subtype]handlers.MaskManager{} + maskManager = map[globals.Subtype]handlers.MaskManager{} // IdActions contains the set of actions that can be performed on // individual resources - idActionsTypeMap = map[subtypes.Subtype]action.ActionSet{ + idActionsTypeMap = map[globals.Subtype]action.ActionSet{ static.Subtype: { action.NoOp, action.Read, @@ -140,7 +140,7 @@ func (s Service) ListHostSetsWithOptions(ctx context.Context, req *pbs.ListHostS } for _, item := range hl { res.Id = item.GetPublicId() - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, res.Id)] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(res.Id).Subtype] authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), idActions, auth.WithResource(&res)).Strings() if len(authorizedActions) == 0 { continue @@ -204,7 +204,7 @@ func (s Service) GetHostSet(ctx context.Context, req *pbs.GetHostSetRequest) (*p outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hs.GetPublicId(), idActions).Strings())) } if plg != nil { @@ -246,7 +246,7 @@ func (s Service) CreateHostSet(ctx context.Context, req *pbs.CreateHostSetReques outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetItem().GetHostCatalogId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetItem().GetHostCatalogId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hs.GetPublicId(), idActions).Strings())) } if plg != nil { @@ -294,7 +294,7 @@ func (s Service) UpdateHostSet(ctx context.Context, req *pbs.UpdateHostSetReques outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hs.GetPublicId(), idActions).Strings())) } @@ -349,7 +349,7 @@ func (s Service) AddHostSetHosts(ctx context.Context, req *pbs.AddHostSetHostsRe outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hs.GetPublicId(), idActions).Strings())) } @@ -387,7 +387,7 @@ func (s Service) SetHostSetHosts(ctx context.Context, req *pbs.SetHostSetHostsRe outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hs.GetPublicId(), idActions).Strings())) } @@ -426,7 +426,7 @@ func (s Service) RemoveHostSetHosts(ctx context.Context, req *pbs.RemoveHostSetH outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, hs.GetPublicId(), idActions).Strings())) } @@ -442,7 +442,7 @@ func (s Service) getFromRepo(ctx context.Context, id string) (host.Set, []host.H var hs host.Set var hl []host.Host var plg *plugins.PluginInfo - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -492,7 +492,7 @@ func (s Service) createInRepo(ctx context.Context, projectId, catalogId string, } var hSet host.Set var plg *plugins.PluginInfo - switch subtypes.SubtypeFromId(domain, catalogId) { + switch globals.ResourceInfoFromPrefix(catalogId).Subtype { case static.Subtype: h, err := toStorageStaticSet(ctx, catalogId, item) if err != nil { @@ -596,7 +596,7 @@ func (s Service) updatePluginInRepo(ctx context.Context, projectId string, req * func (s Service) updateInRepo(ctx context.Context, projectId, catalogId string, req *pbs.UpdateHostSetRequest) (hs host.Set, hosts []host.Host, plg *plugins.PluginInfo, err error) { const op = "host_sets.(Service).updateInRepo" - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case static.Subtype: hs, hosts, err = s.updateStaticInRepo(ctx, projectId, catalogId, req) case hostplugin.Subtype: @@ -608,7 +608,7 @@ func (s Service) updateInRepo(ctx context.Context, projectId, catalogId string, func (s Service) deleteFromRepo(ctx context.Context, projectId, id string) (bool, error) { const op = "host_sets.(Service).deleteFromRepo" rows := 0 - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -635,7 +635,7 @@ func (s Service) listFromRepo(ctx context.Context, catalogId string, opt ...host const op = "host_sets.(Service).listFromRepo" var plg *plugins.PluginInfo var sets []host.Set - switch subtypes.SubtypeFromId(domain, catalogId) { + switch globals.ResourceInfoFromPrefix(catalogId).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -760,7 +760,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty parentId = id default: var set host.Set - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: ss, _, err := staticRepo.LookupSet(ctx, id) if err != nil { @@ -789,7 +789,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty } var cat host.Catalog - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: cs, err := staticRepo.LookupCatalog(ctx, parentId) if err != nil { @@ -970,7 +970,7 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateHostSetRequest) e badFields[globals.PreferredEndpointsField] = fmt.Errorf("Error parsing preferred endpoints: %w.", err).Error() } } - switch subtypes.SubtypeFromId(domain, req.GetItem().GetHostCatalogId()) { + switch globals.ResourceInfoFromPrefix(req.GetItem().GetHostCatalogId()).Subtype { case static.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != static.Subtype.String() { badFields[globals.TypeField] = "Doesn't match the parent resource's type." @@ -1001,7 +1001,7 @@ func validateUpdateRequest(ctx context.Context, req *pbs.UpdateHostSetRequest) e badFields[globals.PreferredEndpointsField] = fmt.Errorf("Error parsing preferred endpoints: %w.", err).Error() } } - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case static.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != static.Subtype.String() { badFields[globals.TypeField] = "Cannot modify the resource type." diff --git a/internal/daemon/controller/handlers/host_sets/host_set_service_test.go b/internal/daemon/controller/handlers/host_sets/host_set_service_test.go index 9bf703d86..3184a12ac 100644 --- a/internal/daemon/controller/handlers/host_sets/host_set_service_test.go +++ b/internal/daemon/controller/handlers/host_sets/host_set_service_test.go @@ -28,7 +28,6 @@ import ( "github.com/hashicorp/boundary/internal/plugin/loopback" "github.com/hashicorp/boundary/internal/scheduler" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/types/subtypes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostsets" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/plugins" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" @@ -45,7 +44,7 @@ import ( "google.golang.org/protobuf/types/known/wrapperspb" ) -var testAuthorizedActions = map[subtypes.Subtype][]string{ +var testAuthorizedActions = map[globals.Subtype][]string{ static.Subtype: {"no-op", "read", "update", "delete", "add-hosts", "set-hosts", "remove-hosts"}, hostplugin.Subtype: {"no-op", "read", "update", "delete"}, } diff --git a/internal/daemon/controller/handlers/hosts/host_service.go b/internal/daemon/controller/handlers/hosts/host_service.go index 4dfd964e9..77ff09758 100644 --- a/internal/daemon/controller/handlers/hosts/host_service.go +++ b/internal/daemon/controller/handlers/hosts/host_service.go @@ -36,7 +36,7 @@ var ( // IdActions contains the set of actions that can be performed on // individual resources - idActionsTypeMap = map[subtypes.Subtype]action.ActionSet{ + idActionsTypeMap = map[globals.Subtype]action.ActionSet{ static.Subtype: { action.NoOp, action.Read, @@ -121,7 +121,7 @@ func (s Service) ListHosts(ctx context.Context, req *pbs.ListHostsRequest) (*pbs } for _, item := range hl { res.Id = item.GetPublicId() - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, res.Id)] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(res.Id).Subtype] authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), idActions, auth.WithResource(&res)).Strings() if len(authorizedActions) == 0 { continue @@ -188,7 +188,7 @@ func (s Service) GetHost(ctx context.Context, req *pbs.GetHostRequest) (*pbs.Get outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, h.GetPublicId(), idActions).Strings())) } outputOpts = append(outputOpts, handlers.WithHostSetIds(h.GetSetIds())) @@ -227,7 +227,7 @@ func (s Service) CreateHost(ctx context.Context, req *pbs.CreateHostRequest) (*p outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetItem().GetHostCatalogId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetItem().GetHostCatalogId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, h.GetPublicId(), idActions).Strings())) } @@ -269,7 +269,7 @@ func (s Service) UpdateHost(ctx context.Context, req *pbs.UpdateHostRequest) (*p outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - idActions := idActionsTypeMap[subtypes.SubtypeFromId(domain, req.GetId())] + idActions := idActionsTypeMap[globals.ResourceInfoFromPrefix(req.GetId()).Subtype] outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, h.GetPublicId(), idActions).Strings())) } outputOpts = append(outputOpts, handlers.WithHostSetIds(h.GetSetIds())) @@ -301,7 +301,7 @@ func (s Service) DeleteHost(ctx context.Context, req *pbs.DeleteHostRequest) (*p func (s Service) getFromRepo(ctx context.Context, id string) (host.Host, *plugins.PluginInfo, error) { var h host.Host var plg *plugins.PluginInfo - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -416,7 +416,7 @@ func (s Service) deleteFromRepo(ctx context.Context, projectId, id string) (bool func (s Service) listFromRepo(ctx context.Context, catalogId string) ([]host.Host, *plugins.PluginInfo, error) { var hosts []host.Host var plg *plugins.PluginInfo - switch subtypes.SubtypeFromId(domain, catalogId) { + switch globals.ResourceInfoFromPrefix(catalogId).Subtype { case static.Subtype: repo, err := s.staticRepoFn() if err != nil { @@ -465,7 +465,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty case action.List, action.Create: parentId = id default: - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: h, err := staticRepo.LookupHost(ctx, id) if err != nil { @@ -493,7 +493,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty } var cat host.Catalog - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case static.Subtype: stcat, err := staticRepo.LookupCatalog(ctx, parentId) if err != nil { @@ -619,8 +619,8 @@ func toProto(ctx context.Context, in host.Host, opt ...handlers.Option) (*pb.Hos func validateGetRequest(req *pbs.GetHostRequest) error { return handlers.ValidateGetRequest(func() map[string]string { badFields := map[string]string{} - ct := subtypes.SubtypeFromId(domain, req.GetId()) - if ct == subtypes.UnknownSubtype { + ct := globals.ResourceInfoFromPrefix(req.GetId()).Subtype + if ct == globals.UnknownSubtype { badFields["id"] = "Improperly formatted identifier used." } return badFields @@ -633,7 +633,7 @@ func validateCreateRequest(req *pbs.CreateHostRequest) error { if !handlers.ValidId(handlers.Id(req.GetItem().GetHostCatalogId()), globals.StaticHostCatalogPrefix) { badFields["host_catalog_id"] = "The field is incorrectly formatted." } - switch subtypes.SubtypeFromId(domain, req.GetItem().GetHostCatalogId()) { + switch globals.ResourceInfoFromPrefix(req.GetItem().GetHostCatalogId()).Subtype { case static.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != static.Subtype.String() { badFields[globals.TypeField] = "Doesn't match the parent resource's type." @@ -675,7 +675,7 @@ func validateCreateRequest(req *pbs.CreateHostRequest) error { func validateUpdateRequest(req *pbs.UpdateHostRequest) error { return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string { badFields := map[string]string{} - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case static.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != static.Subtype.String() { badFields[globals.TypeField] = "Cannot modify the resource type." @@ -715,7 +715,7 @@ func validateUpdateRequest(req *pbs.UpdateHostRequest) error { func validateDeleteRequest(req *pbs.DeleteHostRequest) error { return handlers.ValidateDeleteRequest(func() map[string]string { badFields := map[string]string{} - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case hostplugin.Subtype: badFields[globals.IdField] = "Cannot manually delete this type of host." } diff --git a/internal/daemon/controller/handlers/hosts/host_service_test.go b/internal/daemon/controller/handlers/hosts/host_service_test.go index 3ac4a886c..13dd0189c 100644 --- a/internal/daemon/controller/handlers/hosts/host_service_test.go +++ b/internal/daemon/controller/handlers/hosts/host_service_test.go @@ -27,7 +27,6 @@ import ( "github.com/hashicorp/boundary/internal/plugin/loopback" "github.com/hashicorp/boundary/internal/scheduler" "github.com/hashicorp/boundary/internal/types/scope" - "github.com/hashicorp/boundary/internal/types/subtypes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hosts" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/plugins" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" @@ -42,7 +41,7 @@ import ( "google.golang.org/protobuf/types/known/wrapperspb" ) -var testAuthorizedActions = map[subtypes.Subtype][]string{ +var testAuthorizedActions = map[globals.Subtype][]string{ static.Subtype: {"no-op", "read", "update", "delete"}, hostplugin.Subtype: {"no-op", "read"}, } diff --git a/internal/daemon/controller/handlers/managed_groups/managed_group_service.go b/internal/daemon/controller/handlers/managed_groups/managed_group_service.go index 24aacee5f..bbaf59586 100644 --- a/internal/daemon/controller/handlers/managed_groups/managed_group_service.go +++ b/internal/daemon/controller/handlers/managed_groups/managed_group_service.go @@ -44,7 +44,7 @@ var ( // IdActions contains the set of actions that can be performed on // individual resources - IdActions = map[subtypes.Subtype]action.ActionSet{ + IdActions = map[globals.Subtype]action.ActionSet{ oidc.Subtype: { action.NoOp, action.Read, @@ -137,7 +137,7 @@ func (s Service) ListManagedGroups(ctx context.Context, req *pbs.ListManagedGrou } for _, mg := range ul { res.Id = mg.GetPublicId() - authorizedActions := authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, mg.GetPublicId())], requestauth.WithResource(&res)).Strings() + authorizedActions := authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(mg.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings() if len(authorizedActions) == 0 { continue } @@ -198,7 +198,7 @@ func (s Service) GetManagedGroup(ctx context.Context, req *pbs.GetManagedGroupRe outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, mg.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(mg.GetPublicId()).Subtype]).Strings())) } if outputFields.Has(globals.MemberIdsField) { outputOpts = append(outputOpts, handlers.WithMemberIds(memberIds)) @@ -240,7 +240,7 @@ func (s Service) CreateManagedGroup(ctx context.Context, req *pbs.CreateManagedG outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, mg.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(mg.GetPublicId()).Subtype]).Strings())) } item, err := toProto(ctx, mg, outputOpts...) @@ -279,7 +279,7 @@ func (s Service) UpdateManagedGroup(ctx context.Context, req *pbs.UpdateManagedG outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) } if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[subtypes.SubtypeFromId(domain, mg.GetPublicId())]).Strings())) + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(mg.GetPublicId()).Subtype]).Strings())) } item, err := toProto(ctx, mg, outputOpts...) @@ -309,7 +309,7 @@ func (s Service) DeleteManagedGroup(ctx context.Context, req *pbs.DeleteManagedG func (s Service) getFromRepo(ctx context.Context, id string) (auth.ManagedGroup, []string, error) { var out auth.ManagedGroup var memberIds []string - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case oidc.Subtype: repo, err := s.oidcRepoFn() if err != nil { @@ -432,7 +432,7 @@ func (s Service) createInRepo(ctx context.Context, am auth.AuthMethod, item *pb. return nil, errors.New(ctx, errors.InvalidParameter, op, "missing item") } var out auth.ManagedGroup - switch subtypes.SubtypeFromId(domain, am.GetPublicId()) { + switch globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype { case oidc.Subtype: am, err := s.createOidcInRepo(ctx, am, item) if err != nil { @@ -534,7 +534,7 @@ func (s Service) updateLdapInRepo(ctx context.Context, scopeId, amId, id string, func (s Service) updateInRepo(ctx context.Context, scopeId, authMethodId string, req *pbs.UpdateManagedGroupRequest) (auth.ManagedGroup, error) { const op = "managed_groups.(Service).updateInRepo" var out auth.ManagedGroup - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case oidc.Subtype: mg, err := s.updateOidcInRepo(ctx, scopeId, authMethodId, req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem()) if err != nil { @@ -561,7 +561,7 @@ func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, const op = "managed_groups.(Service).deleteFromRepo" var rows int var err error - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case oidc.Subtype: repo, iErr := s.oidcRepoFn() if iErr != nil { @@ -588,7 +588,7 @@ func (s Service) listFromRepo(ctx context.Context, authMethodId string) ([]auth. const op = "managed_groups.(Service).listFromRepo" var outUl []auth.ManagedGroup - switch subtypes.SubtypeFromId(domain, authMethodId) { + switch globals.ResourceInfoFromPrefix(authMethodId).Subtype { case oidc.Subtype: oidcRepo, err := s.oidcRepoFn() if err != nil { @@ -637,7 +637,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty case action.List, action.Create: parentId = id default: - switch subtypes.SubtypeFromId(domain, id) { + switch globals.ResourceInfoFromPrefix(id).Subtype { case oidc.Subtype: grp, err := oidcRepo.LookupManagedGroup(ctx, id) if err != nil { @@ -668,7 +668,7 @@ func (s Service) parentAndAuthResult(ctx context.Context, id string, a action.Ty } var authMeth auth.AuthMethod - switch subtypes.SubtypeFromId(domain, parentId) { + switch globals.ResourceInfoFromPrefix(parentId).Subtype { case oidc.Subtype: am, err := oidcRepo.LookupAuthMethod(ctx, parentId) if err != nil { @@ -799,7 +799,7 @@ func validateCreateRequest(ctx context.Context, req *pbs.CreateManagedGroupReque if req.GetItem().GetAuthMethodId() == "" { badFields[globals.AuthMethodIdField] = "This field is required." } - switch subtypes.SubtypeFromId(domain, req.GetItem().GetAuthMethodId()) { + switch globals.ResourceInfoFromPrefix(req.GetItem().GetAuthMethodId()).Subtype { case oidc.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != oidc.Subtype.String() { badFields[globals.TypeField] = "Doesn't match the parent resource's type." @@ -842,7 +842,7 @@ func validateUpdateRequest(ctx context.Context, req *pbs.UpdateManagedGroupReque } return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string { badFields := map[string]string{} - switch subtypes.SubtypeFromId(domain, req.GetId()) { + switch globals.ResourceInfoFromPrefix(req.GetId()).Subtype { case oidc.Subtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != oidc.Subtype.String() { badFields[globals.TypeField] = "Cannot modify the resource type." diff --git a/internal/daemon/controller/handlers/targets/credentials.go b/internal/daemon/controller/handlers/targets/credentials.go index 06c31a4dc..24af14609 100644 --- a/internal/daemon/controller/handlers/targets/credentials.go +++ b/internal/daemon/controller/handlers/targets/credentials.go @@ -16,7 +16,6 @@ import ( "github.com/hashicorp/boundary/internal/errors" serverpb "github.com/hashicorp/boundary/internal/gen/controller/servers/services" "github.com/hashicorp/boundary/internal/session" - "github.com/hashicorp/boundary/internal/types/subtypes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" @@ -137,7 +136,7 @@ func dynamicToSessionCredential(ctx context.Context, cred credential.Dynamic) (* Name: l.GetName(), Description: l.GetDescription(), CredentialStoreId: l.GetStoreId(), - Type: subtypes.SubtypeFromId(credentialDomain, l.GetPublicId()).String(), + Type: globals.ResourceInfoFromPrefix(l.GetPublicId()).Subtype.String(), CredentialType: credType, }, Secret: &pb.SessionSecret{ diff --git a/internal/daemon/controller/handlers/targets/registry.go b/internal/daemon/controller/handlers/targets/registry.go index c25a8ea1d..3aac06e03 100644 --- a/internal/daemon/controller/handlers/targets/registry.go +++ b/internal/daemon/controller/handlers/targets/registry.go @@ -8,10 +8,10 @@ import ( "fmt" "sync" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" "github.com/hashicorp/boundary/internal/session" "github.com/hashicorp/boundary/internal/target" - "github.com/hashicorp/boundary/internal/types/subtypes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets" "google.golang.org/protobuf/proto" ) @@ -52,7 +52,7 @@ type registry struct { *sync.Map } -func (r registry) get(s subtypes.Subtype) (*registryEntry, error) { +func (r registry) get(s globals.Subtype) (*registryEntry, error) { v, ok := r.Load(s) if !ok { return nil, fmt.Errorf("subtype %q not registered", s) @@ -65,7 +65,7 @@ func (r registry) get(s subtypes.Subtype) (*registryEntry, error) { return re, nil } -func (r registry) maskManager(s subtypes.Subtype) (handlers.MaskManager, error) { +func (r registry) maskManager(s globals.Subtype) (handlers.MaskManager, error) { re, err := r.get(s) if err != nil { return nil, err @@ -77,7 +77,7 @@ func (r registry) maskManager(s subtypes.Subtype) (handlers.MaskManager, error) // newAttribute creates an Attribute for the given subtype. It delegates the // allocation of the Attribute to the registered attrFunc for the given // subtype. An error is returned if the provided subtype is not registered -func (r registry) newAttribute(s subtypes.Subtype, m any) (Attributes, error) { +func (r registry) newAttribute(s globals.Subtype, m any) (Attributes, error) { re, err := r.get(s) if err != nil { return nil, err @@ -92,7 +92,7 @@ func (r registry) newAttribute(s subtypes.Subtype, m any) (Attributes, error) { // setting of the specific attribute type to the registered setAttributeFunc for // the given subtype. An error is returned if the provided subtype is not // registered. -func (r registry) setAttributes(s subtypes.Subtype, in target.Target, out *pb.Target) error { +func (r registry) setAttributes(s globals.Subtype, in target.Target, out *pb.Target) error { re, err := r.get(s) if err != nil { return err @@ -106,7 +106,7 @@ var subtypeRegistry = registry{ } // Register registers a subtype for used by the service handler. -func Register(s subtypes.Subtype, maskManager handlers.MaskManager, af attributeFunc, sf setAttributeFunc, vsf validateSessionStateFunc) { +func Register(s globals.Subtype, maskManager handlers.MaskManager, af attributeFunc, sf setAttributeFunc, vsf validateSessionStateFunc) { if _, existed := subtypeRegistry.LoadOrStore(s, ®istryEntry{ maskManager: maskManager, attrFunc: af, diff --git a/internal/daemon/controller/handlers/targets/target_service.go b/internal/daemon/controller/handlers/targets/target_service.go index fb1679f8d..0469cef8f 100644 --- a/internal/daemon/controller/handlers/targets/target_service.go +++ b/internal/daemon/controller/handlers/targets/target_service.go @@ -95,7 +95,7 @@ var ( action.List, } - validateCredentialSourcesFn = func(context.Context, subtypes.Subtype, []target.CredentialSource) error { return nil } + validateCredentialSourcesFn = func(context.Context, globals.Subtype, []target.CredentialSource) error { return nil } ValidateIngressWorkerFilterFn = IngressWorkerFilterUnsupported AuthorizeSessionWorkerFilterFn = AuthorizeSessionWithWorkerFilter PostSessionAuthorizationCallback = DefaultPostSessionAuthorizationCallback @@ -799,7 +799,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession var endpoints []*host.Endpoint for _, hSource := range hostSources { hsId := hSource.Id() - switch subtypes.SubtypeFromId(hostDomain, hsId) { + switch globals.ResourceInfoFromPrefix(hsId).Subtype { case static.Subtype: eps, err := staticHostRepo.Endpoints(ctx, hsId) if err != nil { @@ -2038,7 +2038,7 @@ func validateAuthorizeSessionRequest(req *pbs.AuthorizeSessionRequest) error { } } if req.GetHostId() != "" { - switch subtypes.SubtypeFromId(hostDomain, req.GetHostId()) { + switch globals.ResourceInfoFromPrefix(req.GetHostId()).Subtype { case static.Subtype, plugin.Subtype: default: badFields[globals.HostIdField] = "Incorrectly formatted identifier." diff --git a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go index d7d64a15a..2b41fff62 100644 --- a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go +++ b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go @@ -3410,7 +3410,7 @@ func TestAuthorizeSession_Errors(t *testing.T) { h.Address = fmt.Sprintf("%s:54321", h.GetAddress()) repo, err := staticHostRepoFn() require.NoError(t, err) - h, _, err = repo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"}) + _, _, err = repo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"}) require.NoError(t, err) return apiTar.GetItem().GetVersion() } diff --git a/internal/host/plugin/ids.go b/internal/host/plugin/ids.go index 97acd296f..38de6cdce 100644 --- a/internal/host/plugin/ids.go +++ b/internal/host/plugin/ids.go @@ -10,18 +10,21 @@ import ( "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/host" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(host.Domain, Subtype, globals.PluginHostCatalogPrefix, globals.PluginHostCatalogPreviousPrefix, globals.PluginHostSetPrefix, globals.PluginHostSetPreviousPrefix, globals.PluginHostPrefix, globals.PluginHostPreviousPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.PluginHostCatalogPrefix, resource.HostCatalog, host.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.PluginHostCatalogPreviousPrefix, resource.HostCatalog, host.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.PluginHostSetPrefix, resource.HostSet, host.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.PluginHostSetPreviousPrefix, resource.HostSet, host.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.PluginHostPrefix, resource.Host, host.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.PluginHostPreviousPrefix, resource.Host, host.Domain, Subtype) } // PublicId prefixes for the resources in the plugin package. const ( - Subtype = subtypes.Subtype("plugin") + Subtype = globals.Subtype("plugin") ) func newHostCatalogId(ctx context.Context) (string, error) { diff --git a/internal/host/static/public_ids.go b/internal/host/static/public_ids.go index 9fcd4f138..91e8af6be 100644 --- a/internal/host/static/public_ids.go +++ b/internal/host/static/public_ids.go @@ -10,18 +10,18 @@ import ( "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/host" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) func init() { - if err := subtypes.Register(host.Domain, Subtype, globals.StaticHostCatalogPrefix, globals.StaticHostSetPrefix, globals.StaticHostPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.StaticHostCatalogPrefix, resource.HostCatalog, host.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.StaticHostSetPrefix, resource.HostSet, host.Domain, Subtype) + globals.RegisterPrefixToResourceInfo(globals.StaticHostPrefix, resource.Host, host.Domain, Subtype) } // PublicId prefixes for the resources in the static package. const ( - Subtype = subtypes.Subtype("static") + Subtype = globals.Subtype("static") ) func newHostCatalogId(ctx context.Context) (string, error) { diff --git a/internal/perms/acl.go b/internal/perms/acl.go index be0d7d99e..9974e105e 100644 --- a/internal/perms/acl.go +++ b/internal/perms/acl.go @@ -207,7 +207,7 @@ func (a ACL) Allowed(r Resource, aType action.Type, userId string, opt ...Option case grant.id == r.Id && grant.id != "" && grant.id != "*" && - (grant.typ == resource.Unknown || grant.typ == globals.ResourceTypeFromPrefix(grant.id)) && + (grant.typ == resource.Unknown || grant.typ == globals.ResourceInfoFromPrefix(grant.id).Type) && !action.List.IsActionOrParent(aType) && !action.Create.IsActionOrParent(aType): @@ -306,7 +306,7 @@ func (a ACL) ListPermissions(requestedScopes map[string]*scopes.ScopeInfo, grants := a.scopeMap[scopeId] for _, grant := range grants { // This grant doesn't match what we're looking for, ignore. - if grant.typ != requestedType && grant.typ != resource.All && globals.ResourceTypeFromPrefix(grant.id) != requestedType { + if grant.typ != requestedType && grant.typ != resource.All && globals.ResourceInfoFromPrefix(grant.id).Type != requestedType { continue } diff --git a/internal/perms/grants.go b/internal/perms/grants.go index e3fa53539..56ad5f372 100644 --- a/internal/perms/grants.go +++ b/internal/perms/grants.go @@ -439,10 +439,10 @@ func Parse(ctx context.Context, scopeId, grantString string, opt ...Option) (Gra var seenType resource.Type for i, id := range grantIds { if i == 0 { - seenType = globals.ResourceTypeFromPrefix(id) + seenType = globals.ResourceInfoFromPrefix(id).Type continue } - if seenType != globals.ResourceTypeFromPrefix(id) { + if seenType != globals.ResourceInfoFromPrefix(id).Type { return Grant{}, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("input grant string %q contains ids of differently-typed resources", grantString)) } } @@ -524,7 +524,7 @@ func Parse(ctx context.Context, scopeId, grantString string, opt ...Option) (Gra // the second example the type corresponding to the ID must have the // specified type as a child type; in the third the ID must be a // type that has child types. - idType := globals.ResourceTypeFromPrefix(grantIds[i]) + idType := globals.ResourceInfoFromPrefix(grantIds[i]).Type if idType == resource.Unknown { return Grant{}, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("parsed grant string %q contains an id %q of an unknown resource type", grant.CanonicalString(), grantIds[i])) } diff --git a/internal/storage/plugin/ids.go b/internal/storage/plugin/ids.go index 16ad140e8..1d48e5828 100644 --- a/internal/storage/plugin/ids.go +++ b/internal/storage/plugin/ids.go @@ -9,19 +9,17 @@ import ( "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) const StorageDomain = "storage" func init() { - if err := subtypes.Register(StorageDomain, Subtype, globals.PluginStorageBucketPrefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(globals.PluginStorageBucketPrefix, resource.StorageBucket, StorageDomain, Subtype) } const ( - Subtype = subtypes.Subtype("plugin") + Subtype = globals.Subtype("plugin") ) func newStorageBucketId(ctx context.Context) (string, error) { diff --git a/internal/target/options.go b/internal/target/options.go index 69aec6b0c..2185b0e1f 100644 --- a/internal/target/options.go +++ b/internal/target/options.go @@ -7,9 +7,9 @@ import ( "net" "time" + "github.com/hashicorp/boundary/globals" intglobals "github.com/hashicorp/boundary/internal/globals" "github.com/hashicorp/boundary/internal/perms" - "github.com/hashicorp/boundary/internal/types/subtypes" ) // GetOpts - iterate the inbound Options and return a struct @@ -35,7 +35,7 @@ type options struct { WithProjectIds []string WithProjectName string WithUserId string - WithType subtypes.Subtype + WithType globals.Subtype WithHostSources []string WithCredentialLibraries []*CredentialLibrary WithStaticCredentials []*StaticCredential @@ -148,7 +148,7 @@ func WithUserId(userId string) Option { } // WithType provides an option to search by a target type -func WithType(t subtypes.Subtype) Option { +func WithType(t globals.Subtype) Option { return func(o *options) { o.WithType = t } diff --git a/internal/target/options_test.go b/internal/target/options_test.go index 42b1c8075..25eaa88a7 100644 --- a/internal/target/options_test.go +++ b/internal/target/options_test.go @@ -6,10 +6,10 @@ package target import ( "testing" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/perms" "github.com/hashicorp/boundary/internal/target/store" - "github.com/hashicorp/boundary/internal/types/subtypes" "github.com/stretchr/testify/assert" ) @@ -103,7 +103,7 @@ func Test_GetOpts(t *testing.T) { assert.Equal(opts, testOpts) }) t.Run("WithType", func(t *testing.T) { - subtype := subtypes.Subtype("testtype") + subtype := globals.Subtype("testtype") assert := assert.New(t) opts := GetOpts(WithType(subtype)) testOpts := getDefaultOptions() diff --git a/internal/target/registry.go b/internal/target/registry.go index aa69547c6..f1badbe3f 100644 --- a/internal/target/registry.go +++ b/internal/target/registry.go @@ -8,11 +8,12 @@ import ( "fmt" "sync" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/errors" - "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/types/resource" ) -const domain = "target" +const Domain = "target" // NewFunc is a function that creates a Target with the provided project and options. type NewFunc func(ctx context.Context, projectId string, opt ...Option) (Target, error) @@ -57,12 +58,12 @@ type registryEntry struct { } type registry struct { - m map[subtypes.Subtype]*registryEntry + m map[globals.Subtype]*registryEntry sync.RWMutex } -func (r *registry) set(s subtypes.Subtype, entry *registryEntry) { +func (r *registry) set(s globals.Subtype, entry *registryEntry) { r.Lock() defer r.Unlock() @@ -71,14 +72,12 @@ func (r *registry) set(s subtypes.Subtype, entry *registryEntry) { panic(fmt.Sprintf("target subtype %s already registered", s)) } - if err := subtypes.Register(domain, s, entry.prefix); err != nil { - panic(err) - } + globals.RegisterPrefixToResourceInfo(entry.prefix, resource.Target, Domain, s) r.m[s] = entry } -func (r *registry) get(s subtypes.Subtype) (*registryEntry, bool) { +func (r *registry) get(s globals.Subtype) (*registryEntry, bool) { r.RLock() defer r.RUnlock() @@ -89,7 +88,7 @@ func (r *registry) get(s subtypes.Subtype) (*registryEntry, bool) { return nil, ok } -func (r *registry) newFunc(s subtypes.Subtype) (NewFunc, bool) { +func (r *registry) newFunc(s globals.Subtype) (NewFunc, bool) { entry, ok := r.get(s) if !ok { return nil, ok @@ -97,7 +96,7 @@ func (r *registry) newFunc(s subtypes.Subtype) (NewFunc, bool) { return entry.targetHooks.NewTarget, ok } -func (r *registry) allocFunc(s subtypes.Subtype) (AllocFunc, bool) { +func (r *registry) allocFunc(s globals.Subtype) (AllocFunc, bool) { entry, ok := r.get(s) if !ok { return nil, ok @@ -105,7 +104,7 @@ func (r *registry) allocFunc(s subtypes.Subtype) (AllocFunc, bool) { return entry.targetHooks.AllocTarget, ok } -func (r *registry) vetFunc(s subtypes.Subtype) (VetFunc, bool) { +func (r *registry) vetFunc(s globals.Subtype) (VetFunc, bool) { entry, ok := r.get(s) if !ok { return nil, ok @@ -113,7 +112,7 @@ func (r *registry) vetFunc(s subtypes.Subtype) (VetFunc, bool) { return entry.targetHooks.Vet, ok } -func (r *registry) vetForUpdateFunc(s subtypes.Subtype) (VetForUpdateFunc, bool) { +func (r *registry) vetForUpdateFunc(s globals.Subtype) (VetForUpdateFunc, bool) { entry, ok := r.get(s) if !ok { return nil, ok @@ -121,7 +120,7 @@ func (r *registry) vetForUpdateFunc(s subtypes.Subtype) (VetForUpdateFunc, bool) return entry.targetHooks.VetForUpdate, ok } -func (r *registry) vetCredentialSourcesFunc(s subtypes.Subtype) (VetCredentialSourcesFunc, bool) { +func (r *registry) vetCredentialSourcesFunc(s globals.Subtype) (VetCredentialSourcesFunc, bool) { entry, ok := r.get(s) if !ok { return nil, ok @@ -130,7 +129,7 @@ func (r *registry) vetCredentialSourcesFunc(s subtypes.Subtype) (VetCredentialSo return entry.targetHooks.VetCredentialSources, ok } -func (r *registry) idPrefix(s subtypes.Subtype) (string, bool) { +func (r *registry) idPrefix(s globals.Subtype) (string, bool) { entry, ok := r.get(s) if !ok { return "", ok @@ -139,28 +138,28 @@ func (r *registry) idPrefix(s subtypes.Subtype) (string, bool) { } var subtypeRegistry = registry{ - m: make(map[subtypes.Subtype]*registryEntry), + m: make(map[globals.Subtype]*registryEntry), } // SubtypeFromType returns the Subtype from the provided string or if // no Subtype was registered with that string Unknown is returned. -func SubtypeFromType(t string) subtypes.Subtype { - return subtypes.SubtypeFromType(domain, t) +func SubtypeFromType(t string) globals.Subtype { + return globals.Subtype(t) } // SubtypeFromId returns the Subtype from the provided id if the id's prefix // was registered with a Subtype. Otherwise Unknown is returned. -func SubtypeFromId(id string) subtypes.Subtype { - return subtypes.SubtypeFromId(domain, id) +func SubtypeFromId(id string) globals.Subtype { + return globals.ResourceInfoFromPrefix(id).Subtype } // Prefixes returns the list of all known target Prefixes. func Prefixes() []string { - return subtypes.Prefixes(domain) + return globals.PrefixesFromDomain(Domain) } // New creates a Target of the given subtype and projectId. -func New(ctx context.Context, subtype subtypes.Subtype, projectId string, opt ...Option) (Target, error) { +func New(ctx context.Context, subtype globals.Subtype, projectId string, opt ...Option) (Target, error) { const op = "target.New" nf, ok := subtypeRegistry.newFunc(subtype) if !ok { @@ -172,7 +171,7 @@ func New(ctx context.Context, subtype subtypes.Subtype, projectId string, opt .. // Register registers repository hooks and the prefixes for a provided Subtype. Register // panics if the subtype has already been registered or if any of the // prefixes are associated with another subtype. -func Register(s subtypes.Subtype, th targetHooks, prefix string) { +func Register(s globals.Subtype, th targetHooks, prefix string) { subtypeRegistry.set(s, ®istryEntry{ targetHooks: th, prefix: prefix, diff --git a/internal/target/repository_credential_source.go b/internal/target/repository_credential_source.go index 9f84034e7..0c267c27e 100644 --- a/internal/target/repository_credential_source.go +++ b/internal/target/repository_credential_source.go @@ -9,12 +9,12 @@ import ( "fmt" "strings" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/credential" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" - "github.com/hashicorp/boundary/internal/types/subtypes" "github.com/hashicorp/go-secure-stdlib/strutil" ) @@ -536,7 +536,7 @@ func fetchCredentialSources(ctx context.Context, r db.Reader, targetId string) ( return ret, nil } -func (r *Repository) createSources(ctx context.Context, tId string, tSubtype subtypes.Subtype, credSources CredentialSources) ([]*CredentialLibrary, []*StaticCredential, error) { +func (r *Repository) createSources(ctx context.Context, tId string, tSubtype globals.Subtype, credSources CredentialSources) ([]*CredentialLibrary, []*StaticCredential, error) { const op = "target.(Repository).createSources" // Get a list of unique ids being attached to the target, to be used for looking up the source type (library or static) diff --git a/internal/target/target.go b/internal/target/target.go index 34dcffe67..255fb53e3 100644 --- a/internal/target/target.go +++ b/internal/target/target.go @@ -8,12 +8,12 @@ import ( goerrs "errors" "fmt" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/boundary" "github.com/hashicorp/boundary/internal/db/timestamp" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/oplog" "github.com/hashicorp/boundary/internal/target/store" - "github.com/hashicorp/boundary/internal/types/subtypes" ) // Target is a commmon interface for all target subtypes @@ -25,7 +25,7 @@ type Target interface { GetName() string GetDescription() string GetVersion() uint32 - GetType() subtypes.Subtype + GetType() globals.Subtype GetCreateTime() *timestamp.Timestamp GetUpdateTime() *timestamp.Timestamp GetSessionMaxSeconds() uint32 @@ -140,8 +140,8 @@ func (t targetView) GetUserId() string { return "" } -func (t *targetView) Subtype() subtypes.Subtype { - return subtypes.Subtype(t.Type) +func (t *targetView) Subtype() globals.Subtype { + return globals.Subtype(t.Type) } // targetSubtype converts the target view to the concrete subtype diff --git a/internal/target/targettest/target.go b/internal/target/targettest/target.go index 8c4e98d7e..0a1b70e78 100644 --- a/internal/target/targettest/target.go +++ b/internal/target/targettest/target.go @@ -18,13 +18,12 @@ import ( "github.com/hashicorp/boundary/internal/oplog" "github.com/hashicorp/boundary/internal/target" "github.com/hashicorp/boundary/internal/target/targettest/store" - "github.com/hashicorp/boundary/internal/types/subtypes" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" ) const ( - Subtype = subtypes.Subtype("tcp") + Subtype = globals.Subtype("tcp") ) // Target is a target.Target used for tests. @@ -103,7 +102,7 @@ func (t *Target) GetVersion() uint32 { return t.Version } -func (t *Target) GetType() subtypes.Subtype { +func (t *Target) GetType() globals.Subtype { return Subtype } diff --git a/internal/target/tcp/target.go b/internal/target/tcp/target.go index d710ff3a4..3257bffaf 100644 --- a/internal/target/tcp/target.go +++ b/internal/target/tcp/target.go @@ -11,19 +11,19 @@ import ( "fmt" "strings" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/db/timestamp" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/oplog" "github.com/hashicorp/boundary/internal/target" "github.com/hashicorp/boundary/internal/target/tcp/store" - "github.com/hashicorp/boundary/internal/types/subtypes" "google.golang.org/protobuf/proto" ) const ( defaultTableName = "target_tcp" - Subtype = subtypes.Subtype("tcp") + Subtype = globals.Subtype("tcp") ) // Target is a resources that represets a networked service @@ -132,7 +132,7 @@ func (t *Target) Oplog(op oplog.OpType) oplog.Metadata { return metadata } -func (t *Target) GetType() subtypes.Subtype { +func (t *Target) GetType() globals.Subtype { return Subtype } diff --git a/internal/types/subtypes/attribute_transform.go b/internal/types/subtypes/attribute_transform.go index 2cb8adeeb..ff124fc31 100644 --- a/internal/types/subtypes/attribute_transform.go +++ b/internal/types/subtypes/attribute_transform.go @@ -6,13 +6,14 @@ package subtypes import ( "fmt" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/types/known/structpb" ) -func convertAttributesToSubtype(msg proto.Message, st Subtype) error { +func convertAttributesToSubtype(msg proto.Message, st globals.Subtype) error { r := msg.ProtoReflect() d := r.Descriptor() @@ -55,7 +56,7 @@ func convertAttributesToSubtype(msg proto.Message, st Subtype) error { return nil } -func convertAttributesToDefault(msg proto.Message, st Subtype) error { +func convertAttributesToDefault(msg proto.Message, st globals.Subtype) error { r := msg.ProtoReflect() d := r.Descriptor() diff --git a/internal/types/subtypes/attributes.go b/internal/types/subtypes/attributes.go index 19709e500..bf52ce66f 100644 --- a/internal/types/subtypes/attributes.go +++ b/internal/types/subtypes/attributes.go @@ -7,6 +7,7 @@ import ( "fmt" "sync" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" @@ -33,7 +34,7 @@ func init() { }) } -type fieldMap map[Subtype]protoreflect.FieldDescriptor +type fieldMap map[globals.Subtype]protoreflect.FieldDescriptor type attributeRegistry struct { sync.RWMutex @@ -72,7 +73,7 @@ func (ak *attributeRegistry) register(d protoreflect.MessageDescriptor) error { opts := f.Options().(*descriptorpb.FieldOptions) st := proto.GetExtension(opts, protooptions.E_Subtype).(string) if st != "" { - km[Subtype(st)] = f + km[globals.Subtype(st)] = f } } @@ -99,7 +100,7 @@ func (ak *attributeRegistry) register(d protoreflect.MessageDescriptor) error { // attributeField retrieves the FieldDescriptor for a given subtype's // attribute fields. If the corresponding protobuf message has not been // registered it will return an error. -func (ak *attributeRegistry) attributeField(d protoreflect.MessageDescriptor, t Subtype) (protoreflect.FieldDescriptor, error) { +func (ak *attributeRegistry) attributeField(d protoreflect.MessageDescriptor, t globals.Subtype) (protoreflect.FieldDescriptor, error) { ak.RLock() defer ak.RUnlock() @@ -124,6 +125,6 @@ func (ak *attributeRegistry) attributeField(d protoreflect.MessageDescriptor, t // attributeField is used by the AttributeTransformInterceptor to retrieve // the proto FieldDescriptor for a given subtype. -func attributeField(d protoreflect.MessageDescriptor, t Subtype) (protoreflect.FieldDescriptor, error) { +func attributeField(d protoreflect.MessageDescriptor, t globals.Subtype) (protoreflect.FieldDescriptor, error) { return globalAttributeRegistry.attributeField(d, t) } diff --git a/internal/types/subtypes/attributes_test.go b/internal/types/subtypes/attributes_test.go index 6746b8d9b..f1cf6384d 100644 --- a/internal/types/subtypes/attributes_test.go +++ b/internal/types/subtypes/attributes_test.go @@ -6,6 +6,7 @@ package subtypes import ( "testing" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/gen/testing/attribute" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -17,7 +18,7 @@ func TestProtoAttributeKey(t *testing.T) { cases := []struct { name string msg proto.Message - subtype Subtype + subtype globals.Subtype expected protoreflect.FullName }{ { @@ -35,7 +36,7 @@ func TestProtoAttributeKey(t *testing.T) { { "TestResource/unknown", &attribute.TestResource{}, - UnknownSubtype, + globals.UnknownSubtype, "testing.attribute.v1.TestResource.attributes", }, } @@ -54,7 +55,7 @@ func TestProtoAttributeKeyErrors(t *testing.T) { cases := []struct { name string msg proto.Message - subtype Subtype + subtype globals.Subtype expectedErr string }{ { @@ -72,7 +73,7 @@ func TestProtoAttributeKeyErrors(t *testing.T) { { "TestNoAttributes/unknown", &attribute.TestNoAttributes{}, - UnknownSubtype, + globals.UnknownSubtype, "proto message testing.attribute.v1.TestNoAttributes not registered", }, } diff --git a/internal/types/subtypes/interceptor.go b/internal/types/subtypes/interceptor.go index f2b4d125c..b7519d1d7 100644 --- a/internal/types/subtypes/interceptor.go +++ b/internal/types/subtypes/interceptor.go @@ -7,31 +7,14 @@ import ( "context" "errors" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" - "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/types/descriptorpb" ) -func messageDomain(m proto.Message) string { - r := m.ProtoReflect() - fd := r.Descriptor().ParentFile() - if fd == nil { - return "" - } - - opts, ok := fd.Options().(*descriptorpb.FileOptions) - if !ok { - return "" - } - - domain := proto.GetExtension(opts, protooptions.E_Domain).(string) - return domain -} - // transformRequestAttributes will modify the request proto.Message, setting // any subtype attribute fields into the corresponding strongly-typed struct // for the subtype. It looks for some specific structure in the proto.Message @@ -98,8 +81,6 @@ func messageDomain(m proto.Message) string { // Also note that for any of the id based lookups to function, the file that contains // the proto.Message definition must set the "domain" custom option. func transformRequestAttributes(req proto.Message) error { - domain := messageDomain(req) - r := req.ProtoReflect() fields := r.Descriptor().Fields() @@ -114,7 +95,7 @@ func transformRequestAttributes(req proto.Message) error { return m.Get(fd).String() } - var st Subtype + var st globals.Subtype switch { case itemField != nil: itemR := itemField.Message() @@ -134,18 +115,18 @@ func transformRequestAttributes(req proto.Message) error { switch { case idField != nil && id != "": - st = SubtypeFromId(domain, id) + st = globals.ResourceInfoFromPrefix(id).Subtype case sourceIdField != nil && sourceId != "": - st = SubtypeFromId(domain, sourceId) + st = globals.ResourceInfoFromPrefix(sourceId).Subtype case typeField != nil && t != "": - st = Subtype(t) + st = globals.Subtype(t) default: // need either type or id return nil } return convertAttributesToSubtype(item, st) case idField != nil && attributesField != nil: id := r.Get(idField).String() - st = SubtypeFromId(domain, id) + st = globals.ResourceInfoFromPrefix(id).Subtype return convertAttributesToSubtype(req, st) } return nil @@ -172,7 +153,7 @@ func transformResponseItemAttributes(item proto.Message) error { return nil } - st := Subtype(item.ProtoReflect().Get(typeField).String()) + st := globals.Subtype(item.ProtoReflect().Get(typeField).String()) return convertAttributesToDefault(item, st) } diff --git a/internal/types/subtypes/interceptor_test.go b/internal/types/subtypes/interceptor_test.go index d17d708b8..a5c64215d 100644 --- a/internal/types/subtypes/interceptor_test.go +++ b/internal/types/subtypes/interceptor_test.go @@ -7,8 +7,10 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" "github.com/hashicorp/boundary/internal/gen/testing/attribute" + "github.com/hashicorp/boundary/internal/types/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" @@ -17,8 +19,8 @@ import ( ) func init() { - Register("test", Subtype("sub_resource"), "trsr") - Register("test", Subtype("resource_plugin"), "trrp") + globals.RegisterPrefixToResourceInfo("trsr", resource.Unknown, "test", globals.Subtype("sub_resource")) + globals.RegisterPrefixToResourceInfo("trrp", resource.Unknown, "test", globals.Subtype("resource_plugin")) } func TestTransformRequestAttributes(t *testing.T) { diff --git a/internal/types/subtypes/registry.go b/internal/types/subtypes/registry.go index a90ffa227..43d1a67bf 100644 --- a/internal/types/subtypes/registry.go +++ b/internal/types/subtypes/registry.go @@ -10,26 +10,15 @@ import ( "strings" "sync" + "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/errors" ) -// Subtype variables identify a boundary resource subtype. -type Subtype string - -const ( - UnknownSubtype Subtype = "unknown" -) - -// String returns the string representation of a Subtype -func (t Subtype) String() string { - return string(t) -} - // Registry stores a collection of boundary resource subtypes along with their // prefixes and allows for translating prefixes back to registered subtypes. type Registry struct { - subtypesPrefixes map[string]Subtype - knownSubtypes map[Subtype]any + subtypesPrefixes map[string]globals.Subtype + knownSubtypes map[globals.Subtype]any sync.RWMutex } @@ -37,39 +26,39 @@ type Registry struct { // NewRegistry creates a new boundary resource subtype registry. func NewRegistry() *Registry { return &Registry{ - subtypesPrefixes: make(map[string]Subtype), - knownSubtypes: make(map[Subtype]any), + subtypesPrefixes: make(map[string]globals.Subtype), + knownSubtypes: make(map[globals.Subtype]any), } } // SubtypeFromType returns the Subtype from the provided string or if // no Subtype was registered with that string Unknown is returned. -func (r *Registry) SubtypeFromType(t string) Subtype { +func (r *Registry) SubtypeFromType(t string) globals.Subtype { r.RLock() defer r.RUnlock() - st := Subtype(t) + st := globals.Subtype(t) if _, ok := r.knownSubtypes[st]; !ok { - return UnknownSubtype + return globals.UnknownSubtype } return st } // SubtypeFromId returns the Subtype from the provided id if the id's prefix // was registered with a Subtype. Otherwise Unknown is returned. -func (r *Registry) SubtypeFromId(id string) Subtype { +func (r *Registry) SubtypeFromId(id string) globals.Subtype { r.RLock() defer r.RUnlock() i := strings.Index(id, "_") if i == -1 { - return UnknownSubtype + return globals.UnknownSubtype } prefix := id[:i] subtype, ok := r.subtypesPrefixes[prefix] if !ok { - return UnknownSubtype + return globals.UnknownSubtype } return subtype } @@ -89,7 +78,7 @@ func (r *Registry) Prefixes() []string { // Register registers all the prefixes for a provided Subtype. Register returns // an error if the subtype has already been registered or if any of the // prefixes are associated with another subtype. -func (r *Registry) Register(ctx context.Context, subtype Subtype, prefixes ...string) error { +func (r *Registry) Register(ctx context.Context, subtype globals.Subtype, prefixes ...string) error { r.Lock() defer r.Unlock() diff --git a/internal/types/subtypes/registry_global.go b/internal/types/subtypes/registry_global.go deleted file mode 100644 index e454aa83a..000000000 --- a/internal/types/subtypes/registry_global.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package subtypes - -import ( - "context" - "fmt" - "strings" - "sync" - - "github.com/hashicorp/boundary/internal/errors" -) - -var globalRegistry = newRegistry() - -// newGlobalRegistry creates a new boundary resource subtype registry. -func newRegistry() *registry { - return ®istry{ - subtypesPrefixes: make(map[string]map[string]Subtype), - knownSubtypes: make(map[string]map[Subtype]any), - } -} - -// registry stores a collection of boundary resource subtypes along with their -// prefixes and allows for translating prefixes back to registered subtypes. -type registry struct { - subtypesPrefixes map[string]map[string]Subtype - knownSubtypes map[string]map[Subtype]any - - sync.RWMutex -} - -// SubtypeFromType returns the Subtype from the provided string or if -// no Subtype was registered with that string Unknown is returned. -func (r *registry) subtypeFromType(domain, t string) Subtype { - r.RLock() - defer r.RUnlock() - - knownSubtypes, ok := r.knownSubtypes[domain] - if !ok { - return UnknownSubtype - } - - st := Subtype(t) - if _, ok := knownSubtypes[st]; !ok { - return UnknownSubtype - } - return st -} - -// SubtypeFromId returns the Subtype from the provided id if the id's prefix -// was registered with a Subtype. Otherwise Unknown is returned. -func (r *registry) subtypeFromId(domain, id string) Subtype { - r.RLock() - defer r.RUnlock() - - i := strings.Index(id, "_") - if i == -1 { - return UnknownSubtype - } - prefix := id[:i] - - subtypePrefixes, ok := r.subtypesPrefixes[domain] - if !ok { - return UnknownSubtype - } - - subtype, ok := subtypePrefixes[prefix] - if !ok { - return UnknownSubtype - } - return subtype -} - -func (r *registry) prefixes(domain string) []string { - r.RLock() - defer r.RUnlock() - - subtypePrefixes, ok := r.subtypesPrefixes[domain] - if !ok { - return nil - } - - ret := make([]string, 0, len(subtypePrefixes)) - for p := range subtypePrefixes { - ret = append(ret, p) - } - return ret -} - -// Register registers all the prefixes for a provided Subtype. Register returns -// an error if the subtype has already been registered or if any of the -// prefixes are associated with another subtype. -func (r *registry) register(ctx context.Context, domain string, subtype Subtype, prefixes ...string) error { - r.Lock() - defer r.Unlock() - - const op = "subtypes.(registry).register" - - knownSubtypes, present := r.knownSubtypes[domain] - if !present { - knownSubtypes = make(map[Subtype]any) - r.knownSubtypes[domain] = knownSubtypes - r.subtypesPrefixes[domain] = make(map[string]Subtype) - } - - if _, present := knownSubtypes[subtype]; present { - return errors.New( - ctx, - errors.SubtypeAlreadyRegistered, - op, - fmt.Sprintf("subtype %q already registered in domain %s", subtype, domain), - ) - } - knownSubtypes[subtype] = nil - - for _, prefix := range prefixes { - prefix = strings.TrimSpace(prefix) - if st, ok := r.subtypesPrefixes[domain][prefix]; ok { - return errors.New( - ctx, - errors.SubtypeAlreadyRegistered, - op, - fmt.Sprintf("prefix %q is already registered to subtype %q in domain %s", prefix, st, domain), - ) - } - r.subtypesPrefixes[domain][prefix] = subtype - } - return nil -} - -// SubtypeFromType returns the Subtype from the provided string or if -// no Subtype was registered with that string Unknown is returned. -func SubtypeFromType(domain, t string) Subtype { - return globalRegistry.subtypeFromType(domain, t) -} - -// SubtypeFromId returns the Subtype from the provided id if the id's prefix -// was registered with a Subtype. Otherwise Unknown is returned. -func SubtypeFromId(domain, id string) Subtype { - return globalRegistry.subtypeFromId(domain, id) -} - -// Prefixes returns the list of all known Prefixes for a domain. -func Prefixes(domain string) []string { - return globalRegistry.prefixes(domain) -} - -// Register registers all the prefixes for a provided Subtype. Register returns -// an error if the subtype has already been registered or if any of the -// prefixes are associated with another subtype. -func Register(domain string, subtype Subtype, prefixes ...string) error { - ctx := context.TODO() - return globalRegistry.register(ctx, domain, subtype, prefixes...) -} diff --git a/internal/types/subtypes/registry_test.go b/internal/types/subtypes/registry_test.go deleted file mode 100644 index 5f843da28..000000000 --- a/internal/types/subtypes/registry_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package subtypes_test - -import ( - "context" - "testing" - - "github.com/hashicorp/boundary/internal/types/subtypes" - "github.com/stretchr/testify/assert" -) - -func TestSubtypeFromId(t *testing.T) { - testSubtype := subtypes.Subtype("test") - r := subtypes.NewRegistry() - r.Register(context.Background(), testSubtype, "tttst") - tests := []struct { - name string - given string - want subtypes.Subtype - }{ - {"empty-string", "", subtypes.UnknownSubtype}, - {"no-prefix-delimiter", "tttst1234", subtypes.UnknownSubtype}, - {"prefix-first", "_tttst_1234", subtypes.UnknownSubtype}, - {"unknown-prefix", "kaz_1234", subtypes.UnknownSubtype}, - {"prefix-no-id", "tttst_", testSubtype}, - {"vault-prefix", "tttst_1234", testSubtype}, - {"prefix-no-delimiter-no-id", "tttst", subtypes.UnknownSubtype}, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - got := r.SubtypeFromId(tt.given) - assert.Equalf(t, tt.want, got, "given: %s", tt.given) - if got != tt.want { - t.Errorf("(%s): expected %s, actual %s", tt.given, tt.want, got) - } - }) - } -} - -func TestSubtypeFromType(t *testing.T) { - testSubtype := subtypes.Subtype("test") - r := subtypes.NewRegistry() - r.Register(context.Background(), testSubtype, "tttst") - tests := []struct { - name string - given string - want subtypes.Subtype - }{ - {"empty-string", "", subtypes.UnknownSubtype}, - {"correct-string", "test", testSubtype}, - {"captialized", "TEST", subtypes.UnknownSubtype}, - {"typo", "testt", subtypes.UnknownSubtype}, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - got := r.SubtypeFromType(tt.given) - assert.Equalf(t, tt.want, got, "given: %s", tt.given) - if got != tt.want { - t.Errorf("(%s): expected %s, actual %s", tt.given, tt.want, got) - } - }) - } -} - -func TestRegister(t *testing.T) { - r := subtypes.NewRegistry() - ctx := context.Background() - assert.NoError(t, r.Register(ctx, "test", "testprefix")) - // registering multiple subtypes should be fine. - assert.NoError(t, r.Register(ctx, "second", "secondprefix")) - // registering another prefix with a different subtype errors. - assert.Error(t, r.Register(ctx, "third", "testprefix")) - // Registering the same subtype twice errors. - assert.Error(t, r.Register(ctx, "test", "repeatedprefix")) -}