diff --git a/api/hostcatalogs/option.gen.go b/api/hostcatalogs/option.gen.go index f0d29cee6..71daabb19 100644 --- a/api/hostcatalogs/option.gen.go +++ b/api/hostcatalogs/option.gen.go @@ -1,6 +1,7 @@ package hostcatalogs import ( + "fmt" "strconv" "strings" @@ -123,8 +124,26 @@ func DefaultName() Option { } } +func WithPluginId(inPluginId string) Option { + return func(o *options) { + o.postMap["plugin_id"] = inPluginId + } +} + +func WithPluginName(inPluginName string) Option { + return func(o *options) { + o.queryMap["plugin_name"] = fmt.Sprintf("%v", inPluginName) + } +} + func WithSecrets(inSecrets map[string]interface{}) Option { return func(o *options) { o.postMap["secrets"] = inSecrets } } + +func DefaultSecrets() Option { + return func(o *options) { + o.postMap["secrets"] = nil + } +} diff --git a/globals/fields.go b/globals/fields.go index 0ddaacf44..fe6738718 100644 --- a/globals/fields.go +++ b/globals/fields.go @@ -61,4 +61,5 @@ const ( PreferredEndpointsField = "preferred_endpoints" PluginIdField = "plugin_id" PluginField = "plugin" + PluginNameField = "plugin_name" ) diff --git a/internal/api/genapi/input.go b/internal/api/genapi/input.go index 938699ea1..46341352a 100644 --- a/internal/api/genapi/input.go +++ b/internal/api/genapi/input.go @@ -95,13 +95,13 @@ type structInfo struct { // listing recursiveListing bool - // extraOptions allows specifying extra options that will be created for a + // extraFields allows specifying extra options that will be created for a // given type, e.g. arguments only valid for one call or purpose and not // conveyed within the item itself - extraOptions []fieldInfo + extraFields []fieldInfo // fieldOverrides allows overriding some field behavior without making them - // "new" fields like with extraOptions + // "new" fields like with extraFields fieldOverrides []fieldInfo // createResponseTypes controls for which structs response types are created @@ -156,7 +156,7 @@ var inputStructs = []*structInfo{ listTemplate, }, pluralResourceName: "scopes", - extraOptions: []fieldInfo{ + extraFields: []fieldInfo{ { Name: "SkipAdminRoleCreation", ProtoName: "skip_admin_role_creation", @@ -508,9 +508,18 @@ var inputStructs = []*structInfo{ deleteTemplate, listTemplate, }, + extraFields: []fieldInfo{ + { + Name: "PluginName", + ProtoName: "plugin_name", + FieldType: "string", + SkipDefault: true, + Query: true, + }, + }, fieldOverrides: []fieldInfo{ { - Name: "Secrets", + Name: "PluginId", SkipDefault: true, }, }, @@ -632,7 +641,7 @@ var inputStructs = []*structInfo{ "CredentialLibraries": {}, "CredentialSources": {}, }, - extraOptions: []fieldInfo{ + extraFields: []fieldInfo{ { Name: "HostId", ProtoName: "host_id", diff --git a/internal/api/genapi/templates.go b/internal/api/genapi/templates.go index 8bfc3c409..5b5386c99 100644 --- a/internal/api/genapi/templates.go +++ b/internal/api/genapi/templates.go @@ -44,7 +44,7 @@ type templateInput struct { ResourcePath string ParentTypeName string SliceSubtypes map[string]sliceSubtypeInfo - ExtraOptions []fieldInfo + ExtraFields []fieldInfo VersionEnabled bool TypeOnCreate bool CreateResponseTypes bool @@ -63,7 +63,7 @@ func fillTemplates() { Fields: in.generatedStructure.fields, PluralResourceName: in.pluralResourceName, ParentTypeName: in.parentTypeName, - ExtraOptions: in.extraOptions, + ExtraFields: in.extraFields, VersionEnabled: in.versionEnabled, TypeOnCreate: in.typeOnCreate, CreateResponseTypes: in.createResponseTypes, @@ -129,13 +129,13 @@ func fillTemplates() { } optionsMap[input.Package] = optionMap } - // Add in extra defined options - if len(in.extraOptions) > 0 { + // Add in extra defined fields + if len(in.extraFields) > 0 { optionMap := optionsMap[input.Package] if optionMap == nil { optionMap = map[string]fieldInfo{} } - for _, val := range in.extraOptions { + for _, val := range in.extraFields { optionMap[val.Name] = val } optionsMap[input.Package] = optionMap diff --git a/internal/cmd/base/base.go b/internal/cmd/base/base.go index 826c7e2f2..4c8205bf7 100644 --- a/internal/cmd/base/base.go +++ b/internal/cmd/base/base.go @@ -73,6 +73,8 @@ type Command struct { FlagScopeId string FlagScopeName string + FlagPluginId string + FlagPluginName string FlagId string FlagName string FlagDescription string @@ -87,6 +89,10 @@ type Command struct { FlagAttributes string FlagAttrs []CombinedSliceFlagValue + // Secret values + FlagSecrets string + FlagScrts []CombinedSliceFlagValue + client *api.Client } diff --git a/internal/cmd/base/dev.go b/internal/cmd/base/dev.go index 90db26906..5ab9a3ec1 100644 --- a/internal/cmd/base/dev.go +++ b/internal/cmd/base/dev.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/observability/event" + hostplugin "github.com/hashicorp/boundary/internal/plugin/host" "github.com/hashicorp/boundary/internal/types/scope" "github.com/hashicorp/boundary/testing/dbtest" capoidc "github.com/hashicorp/cap/oidc" @@ -100,8 +101,6 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error { return err } - b.Database.LogMode(true) - if err := b.CreateGlobalKmsKeys(ctx); err != nil { if c != nil { err = multierror.Append(err, c()) @@ -144,6 +143,19 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error { return err } + if opts.withHostPlugin != nil { + pluginId, plg := opts.withHostPlugin() + b.DevLoopbackHostPluginId = pluginId + opts := []hostplugin.Option{ + hostplugin.WithName("loopback"), + hostplugin.WithDescription("Provides an initial loopback host plugin in Boundary"), + hostplugin.WithPublicId(b.DevLoopbackHostPluginId), + } + if _, err = b.CreateHostPlugin(ctx, plg, opts...); err != nil { + return err + } + } + if opts.withSkipHostResourcesCreation { // now that we have passed all the error cases, reset c to be a noop so the // defer doesn't do anything. diff --git a/internal/cmd/base/format.go b/internal/cmd/base/format.go index 55ff54b9d..ea269680b 100644 --- a/internal/cmd/base/format.go +++ b/internal/cmd/base/format.go @@ -10,6 +10,7 @@ import ( "unicode/utf8" "github.com/hashicorp/boundary/api" + "github.com/hashicorp/boundary/api/plugins" "github.com/hashicorp/boundary/api/scopes" "github.com/mitchellh/cli" "github.com/mitchellh/go-wordwrap" @@ -34,6 +35,17 @@ func ScopeInfoForOutput(scp *scopes.ScopeInfo, maxLength int) string { return WrapMap(4, maxLength, vals) } +func PluginInfoForOutput(plg *plugins.PluginInfo, maxLength int) string { + if plg == nil { + return " " + } + vals := map[string]interface{}{ + "ID": plg.Id, + "Name": plg.Name, + } + return WrapMap(4, maxLength, vals) +} + func MaxAttributesLength(nonAttributesMap, attributesMap map[string]interface{}, keySubstMap map[string]string) int { // We always print a scope ID and in some cases this particular key ends up // being the longest key, so start with it as a baseline. It's always diff --git a/internal/cmd/base/initial_resources.go b/internal/cmd/base/initial_resources.go index ecf2e34f6..bc7080b8c 100644 --- a/internal/cmd/base/initial_resources.go +++ b/internal/cmd/base/initial_resources.go @@ -10,9 +10,11 @@ import ( "github.com/hashicorp/boundary/internal/host/static" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" + hostplugin "github.com/hashicorp/boundary/internal/plugin/host" "github.com/hashicorp/boundary/internal/servers/controller/auth" "github.com/hashicorp/boundary/internal/target" "github.com/hashicorp/boundary/internal/types/scope" + plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin" "github.com/hashicorp/go-secure-stdlib/base62" ) @@ -584,3 +586,49 @@ func (b *Server) CreateInitialTarget(ctx context.Context) (target.Target, error) return tt, nil } + +func (b *Server) CreateHostPlugin(ctx context.Context, plg plgpb.HostPluginServiceServer, opt ...hostplugin.Option) (*hostplugin.Plugin, error) { + rw := db.New(b.Database) + + kmsRepo, err := kms.NewRepository(rw, rw) + if err != nil { + return nil, fmt.Errorf("error creating kms repository: %w", err) + } + kmsCache, err := kms.NewKms(kmsRepo) + if err != nil { + return nil, fmt.Errorf("error creating kms cache: %w", err) + } + if err := kmsCache.AddExternalWrappers( + kms.WithRootWrapper(b.RootKms), + ); err != nil { + return nil, fmt.Errorf("error adding config keys to kms: %w", err) + } + + cancelCtx, cancel := context.WithCancel(ctx) + defer cancel() + go func() { + select { + case <-b.ShutdownCh: + cancel() + case <-cancelCtx.Done(): + } + }() + + hpRepo, err := hostplugin.NewRepository(rw, rw, kmsCache) + if err != nil { + return nil, fmt.Errorf("error creating host plugin repository: %w", err) + } + + plugin := hostplugin.NewPlugin(opt...) + plugin, err = hpRepo.CreatePlugin(cancelCtx, plugin, opt...) + if err != nil { + return nil, fmt.Errorf("error creating host plugin: %w", err) + } + + if b.HostPlugins == nil { + b.HostPlugins = make(map[string]plgpb.HostPluginServiceServer) + } + b.HostPlugins[plugin.GetPublicId()] = plg + + return plugin, nil +} diff --git a/internal/cmd/base/option.go b/internal/cmd/base/option.go index f528d6e28..96a164739 100644 --- a/internal/cmd/base/option.go +++ b/internal/cmd/base/option.go @@ -1,6 +1,9 @@ package base -import "github.com/hashicorp/boundary/internal/observability/event" +import ( + "github.com/hashicorp/boundary/internal/observability/event" + "github.com/hashicorp/boundary/sdk/pbs/plugin" +) // getOpts - iterate the inbound Options and return a struct. func getOpts(opt ...Option) Options { @@ -33,6 +36,7 @@ type Options struct { withEventFlags *EventFlags withAttributeFieldPrefix string withStatusCode int + withHostPlugin func() (string, plugin.HostPluginServiceServer) } func getDefaultOptions() Options { @@ -158,3 +162,13 @@ func WithDatabaseTemplate(template string) Option { o.withDatabaseTemplate = template } } + +// WithHostPlugin allows specifying a plugin ID and implementation to create at +// startup +func WithHostPlugin(pluginId string, plg plugin.HostPluginServiceServer) Option { + return func(o *Options) { + o.withHostPlugin = func() (string, plugin.HostPluginServiceServer) { + return pluginId, plg + } + } +} diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index 9f8309bdf..642f5bb0f 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -27,6 +27,7 @@ import ( "github.com/hashicorp/boundary/internal/observability/event" "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/boundary/internal/types/scope" + plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin" "github.com/hashicorp/boundary/version" "github.com/hashicorp/go-hclog" wrapping "github.com/hashicorp/go-kms-wrapping" @@ -112,6 +113,9 @@ type Server struct { DevTargetDefaultPort int DevTargetSessionMaxSeconds int DevTargetSessionConnectionLimit int + DevLoopbackHostPluginId string + + HostPlugins map[string]plgpb.HostPluginServiceServer DevOidcSetup oidcSetup diff --git a/internal/cmd/commands/dev/dev.go b/internal/cmd/commands/dev/dev.go index 6cb3934f6..662786b7f 100644 --- a/internal/cmd/commands/dev/dev.go +++ b/internal/cmd/commands/dev/dev.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/boundary/internal/auth/password" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/cmd/config" + "github.com/hashicorp/boundary/internal/host/plugin" "github.com/hashicorp/boundary/internal/host/static" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/intglobals" @@ -47,36 +48,37 @@ type Command struct { controller *controller.Controller worker *worker.Worker - flagLogLevel string - flagLogFormat string - flagCombineLogs bool - flagLoginName string - flagPassword string - flagUnprivilegedLoginName string - flagUnprivilegedPassword string - flagIdSuffix string - flagHostAddress string - flagTargetDefaultPort int - flagTargetSessionMaxSeconds int - flagTargetSessionConnectionLimit int - flagControllerAPIListenAddr string - flagControllerClusterListenAddr string - flagControllerPublicClusterAddr string - flagControllerOnly bool - flagWorkerAuthKey string - flagWorkerProxyListenAddr string - flagWorkerPublicAddr string - flagPassthroughDirectory string - flagRecoveryKey string - flagDatabaseUrl string - flagContainerImage string - flagDisableDatabaseDestruction bool - flagEventFormat string - flagAudit string - flagObservations string - flagSysEvents string - flagEveryEventAllowFilters []string - flagEveryEventDenyFilters []string + flagLogLevel string + flagLogFormat string + flagCombineLogs bool + flagLoginName string + flagPassword string + flagUnprivilegedLoginName string + flagUnprivilegedPassword string + flagIdSuffix string + flagHostAddress string + flagTargetDefaultPort int + flagTargetSessionMaxSeconds int + flagTargetSessionConnectionLimit int + flagControllerAPIListenAddr string + flagControllerClusterListenAddr string + flagControllerPublicClusterAddr string + flagControllerOnly bool + flagWorkerAuthKey string + flagWorkerProxyListenAddr string + flagWorkerPublicAddr string + flagPassthroughDirectory string + flagRecoveryKey string + flagDatabaseUrl string + flagContainerImage string + flagDisableDatabaseDestruction bool + flagEventFormat string + flagAudit string + flagObservations string + flagSysEvents string + flagEveryEventAllowFilters []string + flagEveryEventDenyFilters []string + flagCreateLoopbackHostCatalogPlugin bool } func (c *Command) Synopsis() string { @@ -308,6 +310,12 @@ func (c *Command) Flags() *base.FlagSets { Usage: `The optional every event deny filter. May be specified multiple times.`, }) + f.BoolVar(&base.BoolVar{ + Name: "create-loopback-hostcatalog-plugin", + Target: &c.flagCreateLoopbackHostCatalogPlugin, + Hidden: true, + }) + return set } @@ -542,6 +550,9 @@ func (c *Command) Run(args []string) int { }() var opts []base.Option + if c.flagCreateLoopbackHostCatalogPlugin { + opts = append(opts, base.WithHostPlugin("pl_1234567890", plugin.NewLoopbackPlugin())) + } switch c.flagDatabaseUrl { case "": if c.flagDisableDatabaseDestruction { diff --git a/internal/cmd/commands/hostcatalogscmd/funcs.go b/internal/cmd/commands/hostcatalogscmd/funcs.go index e6022239b..273ab3d1f 100644 --- a/internal/cmd/commands/hostcatalogscmd/funcs.go +++ b/internal/cmd/commands/hostcatalogscmd/funcs.go @@ -83,6 +83,11 @@ func (c *Command) printListTable(items []*hostcatalogs.HostCatalog) string { fmt.Sprintf(" Scope ID: %s", m.ScopeId), ) } + if m.PluginId != "" { + output = append(output, + fmt.Sprintf(" Plugin ID: %s", m.PluginId), + ) + } if m.Version > 0 { output = append(output, fmt.Sprintf(" Version: %d", m.Version), @@ -135,6 +140,9 @@ func printItemTable(result api.GenericResult) string { if item.Description != "" { nonAttributeMap["Description"] = item.Description } + if item.PluginId != "" { + nonAttributeMap["Plugin ID"] = item.PluginId + } if item.Type != "" { nonAttributeMap["Type"] = item.Type } @@ -155,6 +163,22 @@ func printItemTable(result api.GenericResult) string { ) } + if item.Plugin != nil { + ret = append(ret, + "", + " Plugin:", + base.PluginInfoForOutput(item.Plugin, maxLength), + ) + } + + if len(item.Attributes) > 0 { + ret = append(ret, + "", + " Attributes:", + base.WrapMap(4, maxLength, item.Attributes), + ) + } + if len(item.AuthorizedActions) > 0 { ret = append(ret, "", @@ -180,14 +204,6 @@ func printItemTable(result api.GenericResult) string { } } - if len(item.Attributes) > 0 { - ret = append(ret, - "", - " Attributes:", - base.WrapMap(4, maxLength, item.Attributes), - ) - } - return base.WrapForHelpText(ret) } diff --git a/internal/cmd/commands/hostcatalogscmd/plugin_hostcatalogs.gen.go b/internal/cmd/commands/hostcatalogscmd/plugin_hostcatalogs.gen.go index 223ee3026..41b1fb8dd 100644 --- a/internal/cmd/commands/hostcatalogscmd/plugin_hostcatalogs.gen.go +++ b/internal/cmd/commands/hostcatalogscmd/plugin_hostcatalogs.gen.go @@ -77,9 +77,9 @@ func (c *PluginCommand) Help() string { var flagsPluginMap = map[string][]string{ - "create": {"scope-id", "name", "description", "attributes", "attr", "string-attr", "bool-attr", "num-attr"}, + "create": {"scope-id", "name", "description", "plugin-id", "plugin-name", "attributes", "attr", "string-attr", "bool-attr", "num-attr", "secrets", "secret", "string-secret", "bool-secret", "num-secret"}, - "update": {"id", "name", "description", "version", "attributes", "attr", "string-attr", "bool-attr", "num-attr"}, + "update": {"id", "name", "description", "version", "attributes", "attr", "string-attr", "bool-attr", "num-attr", "secrets", "secret", "string-secret", "bool-secret", "num-secret"}, } func (c *PluginCommand) Flags() *base.FlagSets { @@ -94,6 +94,9 @@ func (c *PluginCommand) Flags() *base.FlagSets { f = set.NewFlagSet("Attribute Options") common.PopulateAttributeFlags(c.Command, f, flagsPluginMap, c.Func) + f = set.NewFlagSet("Secrets Options") + common.PopulateSecretFlags(c.Command, f, flagsPluginMap, c.Func) + extraPluginFlagsFunc(c, set, f) return set @@ -169,6 +172,17 @@ func (c *PluginCommand) Run(args []string) int { opts = append(opts, hostcatalogs.WithFilter(c.FlagFilter)) } + switch c.FlagPluginId { + case "": + default: + opts = append(opts, hostcatalogs.WithPluginId(c.FlagPluginId)) + } + switch c.FlagPluginName { + case "": + default: + opts = append(opts, hostcatalogs.WithPluginName(c.FlagPluginName)) + } + var version uint32 switch c.Func { @@ -184,16 +198,33 @@ func (c *PluginCommand) Run(args []string) int { if err := common.HandleAttributeFlags( c.Command, "attr", + c.FlagAttributes, + c.FlagAttrs, func() { - hostcatalogs.DefaultAttributes() + opts = append(opts, hostcatalogs.DefaultAttributes()) }, func(in map[string]interface{}) { - hostcatalogs.WithAttributes(in) + opts = append(opts, hostcatalogs.WithAttributes(in)) }); err != nil { c.PrintCliError(fmt.Errorf("Error evaluating attribute flags to: %s", err.Error())) return base.CommandCliError } + if err := common.HandleAttributeFlags( + c.Command, + "secret", + c.FlagSecrets, + c.FlagScrts, + func() { + opts = append(opts, hostcatalogs.DefaultSecrets()) + }, + func(in map[string]interface{}) { + opts = append(opts, hostcatalogs.WithSecrets(in)) + }); err != nil { + c.PrintCliError(fmt.Errorf("Error evaluating secret flags to: %s", err.Error())) + return base.CommandCliError + } + if ok := extraPluginFlagsHandlingFunc(c, f, &opts); !ok { return base.CommandUserError } diff --git a/internal/cmd/commands/hostsetscmd/funcs.go b/internal/cmd/commands/hostsetscmd/funcs.go index 933396332..532501bf7 100644 --- a/internal/cmd/commands/hostsetscmd/funcs.go +++ b/internal/cmd/commands/hostsetscmd/funcs.go @@ -273,6 +273,22 @@ func printItemTable(result api.GenericResult) string { ) } + if item.Plugin != nil { + ret = append(ret, + "", + " Plugin:", + base.PluginInfoForOutput(item.Plugin, maxLength), + ) + } + + if len(item.Attributes) > 0 { + ret = append(ret, + "", + " Attributes:", + base.WrapMap(4, maxLength, item.Attributes), + ) + } + if len(item.AuthorizedActions) > 0 { ret = append(ret, "", @@ -289,14 +305,6 @@ func printItemTable(result api.GenericResult) string { ) } - if len(item.Attributes) > 0 { - ret = append(ret, - "", - " Attributes:", - base.WrapMap(4, maxLength, item.Attributes), - ) - } - return base.WrapForHelpText(ret) } diff --git a/internal/cmd/commands/hostsetscmd/plugin_hostsets.gen.go b/internal/cmd/commands/hostsetscmd/plugin_hostsets.gen.go index f47e6cc76..8190cae04 100644 --- a/internal/cmd/commands/hostsetscmd/plugin_hostsets.gen.go +++ b/internal/cmd/commands/hostsetscmd/plugin_hostsets.gen.go @@ -79,9 +79,9 @@ func (c *PluginCommand) Help() string { var flagsPluginMap = map[string][]string{ - "create": {"host-catalog-id", "name", "description"}, + "create": {"host-catalog-id", "name", "description", "attributes", "attr", "string-attr", "bool-attr", "num-attr"}, - "update": {"id", "name", "description", "version"}, + "update": {"id", "name", "description", "version", "attributes", "attr", "string-attr", "bool-attr", "num-attr"}, } func (c *PluginCommand) Flags() *base.FlagSets { @@ -93,6 +93,9 @@ func (c *PluginCommand) Flags() *base.FlagSets { f := set.NewFlagSet("Command Options") common.PopulateCommonFlags(c.Command, f, "plugin-type host set", flagsPluginMap, c.Func) + f = set.NewFlagSet("Attribute Options") + common.PopulateAttributeFlags(c.Command, f, flagsPluginMap, c.Func) + extraPluginFlagsFunc(c, set, f) return set @@ -175,6 +178,21 @@ func (c *PluginCommand) Run(args []string) int { } } + if err := common.HandleAttributeFlags( + c.Command, + "attr", + c.FlagAttributes, + c.FlagAttrs, + func() { + opts = append(opts, hostsets.DefaultAttributes()) + }, + func(in map[string]interface{}) { + opts = append(opts, hostsets.WithAttributes(in)) + }); err != nil { + c.PrintCliError(fmt.Errorf("Error evaluating attribute flags to: %s", err.Error())) + return base.CommandCliError + } + if ok := extraPluginFlagsHandlingFunc(c, f, &opts); !ok { return base.CommandUserError } diff --git a/internal/cmd/common/flags.go b/internal/cmd/common/flags.go index df15751d9..f7b197896 100644 --- a/internal/cmd/common/flags.go +++ b/internal/cmd/common/flags.go @@ -34,6 +34,20 @@ func PopulateCommonFlags(c *base.Command, f *base.FlagSet, resourceType string, Completion: complete.PredictAnything, Usage: `Scope in which to make the request, identified by name.`, }) + case "plugin-id": + f.StringVar(&base.StringVar{ + Name: "plugin-id", + Target: &c.FlagPluginId, + Completion: complete.PredictAnything, + Usage: `ID of a plugin being referenced in the request.`, + }) + case "plugin-name": + f.StringVar(&base.StringVar{ + Name: "plugin-name", + Target: &c.FlagPluginName, + Completion: complete.PredictAnything, + Usage: `Name of a plugin being referenced in the request.`, + }) case "id": f.StringVar(&base.StringVar{ Name: "id", @@ -109,7 +123,7 @@ func PopulateAttributeFlags(c *base.Command, f *base.FlagSet, flagNames map[stri f.StringVar(&base.StringVar{ Name: "attributes", Target: &c.FlagAttributes, - Usage: `A JSON map value to use as the entirety of the request's attribute map. Usually this will be soured from a file via "file://" syntax.`, + Usage: `A JSON map value to use as the entirety of the request's attributes map. Usually this will be sourced from a file via "file://" syntax.`, }) case "attr": f.CombinationSliceVar(&base.CombinationSliceVar{ @@ -118,7 +132,7 @@ func PopulateAttributeFlags(c *base.Command, f *base.FlagSet, flagNames map[stri KvSplit: true, KeyDelimiter: &keyDelimiter, ProtoCompatKey: true, - Usage: `A key=value attribute to add to the request's attribute map. The type is automatically inferred. Use -string-attr, -bool-attr, or -num-attr if the type needs to be overridden. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + Usage: `A key=value attribute to add to the request's attributes map. The type is automatically inferred. Use -string-attr, -bool-attr, or -num-attr if the type needs to be overridden. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, }) case "string-attr": f.CombinationSliceVar(&base.CombinationSliceVar{ @@ -127,7 +141,7 @@ func PopulateAttributeFlags(c *base.Command, f *base.FlagSet, flagNames map[stri KvSplit: true, KeyDelimiter: &keyDelimiter, ProtoCompatKey: true, - Usage: `A key=value string attribute to add to the request's attribute map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + Usage: `A key=value string attribute to add to the request's attributes map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, }) case "bool-attr": f.CombinationSliceVar(&base.CombinationSliceVar{ @@ -136,7 +150,7 @@ func PopulateAttributeFlags(c *base.Command, f *base.FlagSet, flagNames map[stri KvSplit: true, KeyDelimiter: &keyDelimiter, ProtoCompatKey: true, - Usage: `A key=value bool attribute to add to the request's attribute map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + Usage: `A key=value bool attribute to add to the request's attributes map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, }) case "num-attr": f.CombinationSliceVar(&base.CombinationSliceVar{ @@ -145,7 +159,57 @@ func PopulateAttributeFlags(c *base.Command, f *base.FlagSet, flagNames map[stri KvSplit: true, KeyDelimiter: &keyDelimiter, ProtoCompatKey: true, - Usage: `A key=value numeric attribute to add to the request's attribute map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + Usage: `A key=value numeric attribute to add to the request's attributes map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + }) + } + } +} + +func PopulateSecretFlags(c *base.Command, f *base.FlagSet, flagNames map[string][]string, command string) { + keyDelimiter := "." + for _, name := range flagNames[command] { + switch name { + case "secrets": + f.StringVar(&base.StringVar{ + Name: "secrets", + Target: &c.FlagSecrets, + Usage: `A JSON map value to use as the entirety of the request's secrets map. Usually this will be sourced from a file via "file://" syntax.`, + }) + case "secret": + f.CombinationSliceVar(&base.CombinationSliceVar{ + Name: "secret", + Target: &c.FlagScrts, + KvSplit: true, + KeyDelimiter: &keyDelimiter, + ProtoCompatKey: true, + Usage: `A key=value secret to add to the request's secrets map. The type is automatically inferred. Use -string-secret, -bool-secret, or -num-secret if the type needs to be overridden. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + }) + case "string-secret": + f.CombinationSliceVar(&base.CombinationSliceVar{ + Name: "string-secret", + Target: &c.FlagScrts, + KvSplit: true, + KeyDelimiter: &keyDelimiter, + ProtoCompatKey: true, + Usage: `A key=value string secret to add to the request's secrets map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + }) + case "bool-secret": + f.CombinationSliceVar(&base.CombinationSliceVar{ + Name: "bool-secret", + Target: &c.FlagScrts, + KvSplit: true, + KeyDelimiter: &keyDelimiter, + ProtoCompatKey: true, + Usage: `A key=value bool secret to add to the request's secrets map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, + }) + case "num-secret": + f.CombinationSliceVar(&base.CombinationSliceVar{ + Name: "num-secret", + Target: &c.FlagScrts, + KvSplit: true, + KeyDelimiter: &keyDelimiter, + ProtoCompatKey: true, + Usage: `A key=value numeric secret to add to the request's secrets map. Can be specified multiple times. Supports sourcing values from files via "file://" and env vars via "env://"`, }) } } @@ -157,23 +221,23 @@ var jsonNumberRegex = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?$`) // HandleAttributeFlags takes in a command and a func to call for default (that // is, set to nil) and non-default values. Suffix can be used to allow this // logic to be used for various needs, e.g. -attr vs -secret. -func HandleAttributeFlags(c *base.Command, suffix string, defaultFunc func(), setFunc func(map[string]interface{})) error { - // If we were given -attributes, use that as-is - switch c.FlagAttributes { +func HandleAttributeFlags(c *base.Command, suffix, fullField string, sepFields []base.CombinedSliceFlagValue, defaultFunc func(), setFunc func(map[string]interface{})) error { + // If we were given a fullly defined field, use that as-is + switch fullField { case "": // Nothing, continue on case "null": defaultFunc() return nil default: - parsedString, err := parseutil.ParsePath(c.FlagAttributes) + parsedString, err := parseutil.ParsePath(fullField) if err != nil && !errors.Is(err, parseutil.ErrNotAUrl) { - return fmt.Errorf("error parsing attributes flag as a URL: %w", err) + return fmt.Errorf("error parsing %s flag as a URL: %w", suffix, err) } // We should be able to parse the string as a JSON object var setMap map[string]interface{} if err := json.Unmarshal([]byte(parsedString), &setMap); err != nil { - return fmt.Errorf("error parsing attributes flag as JSON: %w", err) + return fmt.Errorf("error parsing %s flag as JSON: %w", suffix, err) } setFunc(setMap) return nil @@ -181,8 +245,8 @@ func HandleAttributeFlags(c *base.Command, suffix string, defaultFunc func(), se setMap := map[string]interface{}{} - for _, attr := range c.FlagAttrs { - if len(attr.Keys) == 0 { + for _, field := range sepFields { + if len(field.Keys) == 0 { // No idea why this would happen, but skip it continue } @@ -191,101 +255,101 @@ func HandleAttributeFlags(c *base.Command, suffix string, defaultFunc func(), se var err error // First, perform any needed parsing if we are given the type - switch attr.Name { + switch field.Name { case "num-" + suffix: // JSON treats all numbers equally, however, we will try to be a // little better so that we don't include decimals if we don't need // to (and don't have to worry about precision if not necessary) - if strings.Contains(attr.Value, ".") { - val, err = strconv.ParseFloat(attr.Value, 64) + if strings.Contains(field.Value, ".") { + val, err = strconv.ParseFloat(field.Value, 64) if err != nil { - return fmt.Errorf("error parsing attribute %q as a float: %w", attr.Value, err) + return fmt.Errorf("error parsing value %q as a float: %w", field.Value, err) } } else { - val, err = strconv.ParseInt(attr.Value, 10, 64) + val, err = strconv.ParseInt(field.Value, 10, 64) if err != nil { - return fmt.Errorf("error parsing attribute %q as an integer: %w", attr.Value, err) + return fmt.Errorf("error parsing value %q as an integer: %w", field.Value, err) } } case "string-" + suffix: - val = strings.Trim(attr.Value, `"`) + val = strings.Trim(field.Value, `"`) case "bool-" + suffix: - switch attr.Value { + switch field.Value { case "true": val = true case "false": val = false default: - return fmt.Errorf("error parsing attribute %q as a bool", attr.Value) + return fmt.Errorf("error parsing value %q as a bool", field.Value) } case suffix: // In this case, use heuristics to just do the right thing the vast // majority of the time switch { - case attr.Value == "null": // Explicit null, we want to set to a null value to clear it + case field.Value == "null": // Explicit null, we want to set to a null value to clear it val = nil - case attr.Value == "true": // bool true + case field.Value == "true": // bool true val = true - case attr.Value == "false": // bool false + case field.Value == "false": // bool false val = false - case strings.HasPrefix(attr.Value, `"`): // explicitly quoted string - val = strings.Trim(attr.Value, `"`) + case strings.HasPrefix(field.Value, `"`): // explicitly quoted string + val = strings.Trim(field.Value, `"`) - case jsonNumberRegex.Match([]byte(strings.Trim(attr.Value, `"`))): // number + case jsonNumberRegex.Match([]byte(strings.Trim(field.Value, `"`))): // number // Same logic as above - if strings.Contains(attr.Value, ".") { - val, err = strconv.ParseFloat(attr.Value, 64) + if strings.Contains(field.Value, ".") { + val, err = strconv.ParseFloat(field.Value, 64) if err != nil { - return fmt.Errorf("error parsing attribute %q as a float: %w", attr.Value, err) + return fmt.Errorf("error parsing value %q as a float: %w", field.Value, err) } } else { - val, err = strconv.ParseInt(attr.Value, 10, 64) + val, err = strconv.ParseInt(field.Value, 10, 64) if err != nil { - return fmt.Errorf("error parsing attribute %q as an integer: %w", attr.Value, err) + return fmt.Errorf("error parsing value %q as an integer: %w", field.Value, err) } } - case strings.HasPrefix(attr.Value, "["): // serialized JSON array + case strings.HasPrefix(field.Value, "["): // serialized JSON array var s []interface{} - u := json.NewDecoder(bytes.NewBufferString(attr.Value)) + u := json.NewDecoder(bytes.NewBufferString(field.Value)) u.UseNumber() if err := u.Decode(&s); err != nil { - return fmt.Errorf("error parsing attribute %q as a json array: %w", attr.Value, err) + return fmt.Errorf("error parsing value %q as a json array: %w", field.Value, err) } val = s - case strings.HasPrefix(attr.Value, "{"): // serialized JSON map + case strings.HasPrefix(field.Value, "{"): // serialized JSON map var m map[string]interface{} - u := json.NewDecoder(bytes.NewBufferString(attr.Value)) + u := json.NewDecoder(bytes.NewBufferString(field.Value)) u.UseNumber() if err := u.Decode(&m); err != nil { - return fmt.Errorf("error parsing attribute %q as a json map: %w", attr.Value, err) + return fmt.Errorf("error parsing value %q as a json map: %w", field.Value, err) } val = m default: // Default is to treat as a string value - val = attr.Value + val = field.Value } default: - return fmt.Errorf("unknown attribute flag %q", attr.Name) + return fmt.Errorf("unknown flag %q", field.Name) } - // Now we have to insert it in the right position in the attribute map + // Now we have to insert it in the right position in the final map currMap := setMap - for i, segment := range attr.Keys { + for i, segment := range field.Keys { if segment == "" { - return fmt.Errorf("key segment %q for value %q is empty", segment, attr.Value) + return fmt.Errorf("key segment %q for value %q is empty", segment, field.Value) } switch { - case i == len(attr.Keys)-1: + case i == len(field.Keys)-1: // If we get an explicit "null" override whatever is currently // there if val == nil { diff --git a/internal/cmd/common/flags_test.go b/internal/cmd/common/flags_test.go index b4e3bd4d6..6d41bab66 100644 --- a/internal/cmd/common/flags_test.go +++ b/internal/cmd/common/flags_test.go @@ -2,6 +2,7 @@ package common import ( "encoding/json" + "fmt" "testing" "github.com/hashicorp/boundary/internal/cmd/base" @@ -170,12 +171,12 @@ func TestHandleAttributeFlags(t *testing.T) { name: "strings-only", args: []base.CombinedSliceFlagValue{ { - Name: "string-attr", + Name: "string-%s", Keys: []string{"foo"}, Value: "bar", }, { - Name: "string-attr", + Name: "string-%s", Keys: []string{"bar"}, Value: `"baz"`, }, @@ -189,12 +190,12 @@ func TestHandleAttributeFlags(t *testing.T) { name: "nums-only", args: []base.CombinedSliceFlagValue{ { - Name: "num-attr", + Name: "num-%s", Keys: []string{"foo"}, Value: "-1.2", }, { - Name: "num-attr", + Name: "num-%s", Keys: []string{"bar"}, Value: "5", }, @@ -208,7 +209,7 @@ func TestHandleAttributeFlags(t *testing.T) { name: "bad-float-num", args: []base.CombinedSliceFlagValue{ { - Name: "num-attr", + Name: "num-%s", Keys: []string{"foo"}, Value: "-15d.2", }, @@ -219,7 +220,7 @@ func TestHandleAttributeFlags(t *testing.T) { name: "bad-int-num", args: []base.CombinedSliceFlagValue{ { - Name: "num-attr", + Name: "num-%s", Keys: []string{"foo"}, Value: "-15d3", }, @@ -230,12 +231,12 @@ func TestHandleAttributeFlags(t *testing.T) { name: "bools-only", args: []base.CombinedSliceFlagValue{ { - Name: "bool-attr", + Name: "bool-%s", Keys: []string{"foo"}, Value: "true", }, { - Name: "bool-attr", + Name: "bool-%s", Keys: []string{"bar"}, Value: "false", }, @@ -249,7 +250,7 @@ func TestHandleAttributeFlags(t *testing.T) { name: "bad-bool", args: []base.CombinedSliceFlagValue{ { - Name: "bool-attr", + Name: "bool-%s", Keys: []string{"foo"}, Value: "t", }, @@ -260,47 +261,47 @@ func TestHandleAttributeFlags(t *testing.T) { name: "attr-only", args: []base.CombinedSliceFlagValue{ { - Name: "attr", + Name: "%s", Keys: []string{"b1"}, Value: "true", }, { - Name: "attr", + Name: "%s", Keys: []string{"b2"}, Value: "false", }, { - Name: "attr", + Name: "%s", Keys: []string{"s1"}, Value: "scoopde", }, { - Name: "attr", + Name: "%s", Keys: []string{"s2"}, Value: `"woop"`, }, { - Name: "attr", + Name: "%s", Keys: []string{"n1"}, Value: "-1.2", }, { - Name: "attr", + Name: "%s", Keys: []string{"n2"}, Value: "5", }, { - Name: "attr", + Name: "%s", Keys: []string{"a"}, Value: `["foo", 1.5, true, ["bar"], {"hip": "hop"}]`, }, { - Name: "attr", + Name: "%s", Keys: []string{"nil"}, Value: "null", }, { - Name: "attr", + Name: "%s", Keys: []string{"m"}, Value: `{"b": true, "n": 6, "s": "scoopde", "a": ["bar"], "m": {"hip": "hop"}}`, }, @@ -333,37 +334,37 @@ func TestHandleAttributeFlags(t *testing.T) { name: "map-array-structure", args: []base.CombinedSliceFlagValue{ { - Name: "attr", + Name: "%s", Keys: []string{"bools"}, Value: "true", }, { - Name: "attr", + Name: "%s", Keys: []string{"bools"}, Value: "false", }, { - Name: "attr", + Name: "%s", Keys: []string{"strings", "s1"}, Value: "scoopde", }, { - Name: "attr", + Name: "%s", Keys: []string{"strings", "s2"}, Value: `"woop"`, }, { - Name: "attr", + Name: "%s", Keys: []string{"numbers", "reps"}, Value: "-1.2", }, { - Name: "attr", + Name: "%s", Keys: []string{"numbers", "reps"}, Value: "5", }, { - Name: "attr", + Name: "%s", Keys: []string{"strings", "s2"}, // This will overwrite above! Value: "null", }, @@ -381,25 +382,32 @@ func TestHandleAttributeFlags(t *testing.T) { }, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) + for _, typ := range []string{"attr", "secret"} { + t.Run(fmt.Sprintf("%s-%s", tt.name, typ), func(t *testing.T) { + assert, require := assert.New(t), require.New(t) - // Note: we do the setup on each run to make sure we aren't carrying - // state over; just like in the real CLI where each run would have - // pristine state. - c := new(base.Command) - c.FlagAttrs = tt.args - var outMap map[string]interface{} + // Note: we do the setup on each run to make sure we aren't carrying + // state over; just like in the real CLI where each run would have + // pristine state. + c := new(base.Command) + var outMap map[string]interface{} - err := HandleAttributeFlags(c, "attr", func() {}, func(in map[string]interface{}) { outMap = in }) - if tt.expectedErr != "" { - require.Error(err) - assert.Contains(err.Error(), tt.expectedErr) - return - } + args := make([]base.CombinedSliceFlagValue, 0, len(tt.args)) + for _, arg := range tt.args { + arg.Name = fmt.Sprintf(arg.Name, typ) + args = append(args, arg) + } - require.NoError(err) - assert.Equal(tt.expectedMap, outMap) - }) + err := HandleAttributeFlags(c, typ, "", args, func() {}, func(in map[string]interface{}) { outMap = in }) + if tt.expectedErr != "" { + require.Error(err) + assert.Contains(err.Error(), tt.expectedErr) + return + } + + require.NoError(err) + assert.Equal(tt.expectedMap, outMap) + }) + } } } diff --git a/internal/cmd/gencli/input.go b/internal/cmd/gencli/input.go index e88fdefd1..0c57d3827 100644 --- a/internal/cmd/gencli/input.go +++ b/internal/cmd/gencli/input.go @@ -72,6 +72,13 @@ type cmdInfo struct { // HasGenericAttributes controls whether to generate flags for -attributes, // -attr, -string-attr, etc. HasGenericAttributes bool + + // HasGenericSecrets controls whether to generate flags for -secrets, + // -secret, -string-secret, etc. + HasGenericSecrets bool + + // IsPluginType controls whether standard plugin flags are generated + IsPluginType bool } var inputStructs = map[string][]*cmdInfo{ @@ -269,9 +276,11 @@ var inputStructs = map[string][]*cmdInfo{ HasName: true, HasDescription: true, Container: "Scope", + IsPluginType: true, VersionedActions: []string{"update"}, NeedsSubtypeInCreate: true, HasGenericAttributes: true, + HasGenericSecrets: true, }, }, "hostsets": { @@ -302,18 +311,19 @@ var inputStructs = map[string][]*cmdInfo{ VersionedActions: []string{"update"}, }, { - ResourceType: resource.HostSet.String(), - Pkg: "hostsets", - StdActions: []string{"create", "update"}, - SubActionPrefix: "plugin", - HasExtraCommandVars: true, - SkipNormalHelp: true, - HasExtraHelpFunc: true, - HasId: true, - HasName: true, - Container: "HostCatalog", - HasDescription: true, - VersionedActions: []string{"update"}, + ResourceType: resource.HostSet.String(), + Pkg: "hostsets", + StdActions: []string{"create", "update"}, + SubActionPrefix: "plugin", + HasExtraCommandVars: true, + SkipNormalHelp: true, + HasExtraHelpFunc: true, + HasId: true, + HasName: true, + Container: "HostCatalog", + HasDescription: true, + HasGenericAttributes: true, + VersionedActions: []string{"update"}, }, }, "hosts": { diff --git a/internal/cmd/gencli/templates.go b/internal/cmd/gencli/templates.go index 22d591a02..5c8f08854 100644 --- a/internal/cmd/gencli/templates.go +++ b/internal/cmd/gencli/templates.go @@ -170,15 +170,16 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Help() string { var flags{{ camelCase .SubActionPrefix }}Map = map[string][]string{ {{ with $attrFlags := ", \"attributes\", \"attr\", \"string-attr\", \"bool-attr\", \"num-attr\"" }} + {{ with $secretFlags := ", \"secrets\", \"secret\", \"string-secret\", \"bool-secret\", \"num-secret\"" }} {{ range $i, $action := $input.StdActions }} {{ if eq $action "create" }} - "create": { "{{ kebabCase $input.Container }}-id", "name", "description" {{ if $input.HasGenericAttributes }} {{ $attrFlags }} {{ end }} }, + "create": { "{{ kebabCase $input.Container }}-id", "name", "description" {{ if $input.IsPluginType }} , "plugin-id", "plugin-name" {{ end }} {{ if $input.HasGenericAttributes }} {{ $attrFlags }} {{ end }} {{ if $input.HasGenericSecrets }} {{ $secretFlags }} {{ end }} }, {{ end }} {{ if eq $action "read" }} "read": {"id"}, {{ end }} {{ if eq $action "update" }} - "update": {"id", "name", "description" {{ if hasAction $input.VersionedActions "update" }}, "version" {{ end }} {{ if $input.HasGenericAttributes }} {{ $attrFlags }} {{ end }} }, + "update": {"id", "name", "description" {{ if hasAction $input.VersionedActions "update" }}, "version" {{ end }} {{ if $input.HasGenericAttributes }} {{ $attrFlags }} {{ end }} {{ if $input.HasGenericSecrets }} {{ $secretFlags }} {{ end }} }, {{ end }} {{ if eq $action "delete" }} "delete": {"id"}, @@ -188,6 +189,7 @@ var flags{{ camelCase .SubActionPrefix }}Map = map[string][]string{ {{ end }} {{ end }} {{ end }} + {{ end }} } func (c *{{ camelCase .SubActionPrefix }}Command) Flags() *base.FlagSets { @@ -204,6 +206,11 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Flags() *base.FlagSets { common.PopulateAttributeFlags(c.Command, f, flags{{ camelCase .SubActionPrefix }}Map, c.Func) {{ end }} + {{ if .HasGenericSecrets }} + f = set.NewFlagSet("Secrets Options") + common.PopulateSecretFlags(c.Command, f, flags{{ camelCase .SubActionPrefix }}Map, c.Func) + {{ end }} + extra{{ camelCase .SubActionPrefix }}FlagsFunc(c, set, f) return set @@ -314,6 +321,19 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Run(args []string) int { opts = append(opts, {{ .Pkg }}.WithScopeName(c.FlagScopeName)) } {{ end }} + + {{ if .IsPluginType }} + switch c.FlagPluginId { + case "": + default: + opts = append(opts, {{ .Pkg }}.WithPluginId(c.FlagPluginId)) + } + switch c.FlagPluginName { + case "": + default: + opts = append(opts, {{ .Pkg }}.WithPluginName(c.FlagPluginName)) + } + {{ end }} var version uint32 {{ if .VersionedActions }} @@ -334,17 +354,36 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Run(args []string) int { if err := common.HandleAttributeFlags( c.Command, "attr", + c.FlagAttributes, + c.FlagAttrs, func() { - {{ .Pkg }}.DefaultAttributes() + opts = append(opts, {{ .Pkg }}.DefaultAttributes()) }, func(in map[string]interface{}) { - {{ .Pkg }}.WithAttributes(in) + opts = append(opts, {{ .Pkg }}.WithAttributes(in)) }); err != nil { c.PrintCliError(fmt.Errorf("Error evaluating attribute flags to: %s", err.Error())) return base.CommandCliError } {{ end }} + {{ if .HasGenericSecrets }} + if err := common.HandleAttributeFlags( + c.Command, + "secret", + c.FlagSecrets, + c.FlagScrts, + func() { + opts = append(opts, {{ .Pkg }}.DefaultSecrets()) + }, + func(in map[string]interface{}) { + opts = append(opts, {{ .Pkg }}.WithSecrets(in)) + }); err != nil { + c.PrintCliError(fmt.Errorf("Error evaluating secret flags to: %s", err.Error())) + return base.CommandCliError + } + {{ end }} + if ok := extra{{ camelCase .SubActionPrefix }}FlagsHandlingFunc(c, f, &opts, ); !ok { return base.CommandUserError } diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index f3f8afa34..1f3125ceb 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -1247,7 +1247,7 @@ }, { "name": "plugin_name", - "description": "As an alternative to providing the plugin id in the provided HostCatalog,\nthis field can be used to lookup the plugin using it's name.", + "description": "As an alternative to providing the plugin id in the provided HostCatalog,\nthis field can be used to lookup the plugin using its name.", "in": "query", "required": false, "type": "string" diff --git a/internal/gen/controller/api/services/host_catalog_service.pb.go b/internal/gen/controller/api/services/host_catalog_service.pb.go index 7bb089e0d..26edfda4f 100644 --- a/internal/gen/controller/api/services/host_catalog_service.pb.go +++ b/internal/gen/controller/api/services/host_catalog_service.pb.go @@ -235,8 +235,8 @@ type CreateHostCatalogRequest struct { Item *hostcatalogs.HostCatalog `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` // As an alternative to providing the plugin id in the provided HostCatalog, - // this field can be used to lookup the plugin using it's name. - PluginName string `protobuf:"bytes,2,opt,name=plugin_name,json=pluginName,proto3" json:"plugin_name,omitempty"` + // this field can be used to lookup the plugin using its name. + PluginName string `protobuf:"bytes,2,opt,name=plugin_name,proto3" json:"plugin_name,omitempty"` } func (x *CreateHostCatalogRequest) Reset() { @@ -576,113 +576,113 @@ var file_controller_api_services_v1_host_catalog_service_proto_rawDesc = []byte{ 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x05, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, + 0x74, 0x65, 0x6d, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, - 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, + 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x78, 0x0a, - 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, - 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, - 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x49, 0x0a, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, - 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, - 0x67, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xb2, 0x01, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x49, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, - 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, - 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, - 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, - 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x66, 0x0a, 0x19, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, - 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x22, 0x2a, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, - 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x22, 0x1b, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, - 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xde, 0x07, - 0x0a, 0x12, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0xbd, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, - 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, - 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, + 0x09, 0x52, 0x0b, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x78, + 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, + 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, + 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x49, 0x0a, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, + 0x6f, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, + 0x6f, 0x67, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xb2, 0x01, 0x0a, 0x18, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x49, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, + 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, + 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, + 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x66, 0x0a, + 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, + 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x2a, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, + 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x22, 0x1b, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, + 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xde, + 0x07, 0x0a, 0x12, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xbd, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, + 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, + 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, + 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x68, 0x6f, 0x73, + 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x1d, 0x12, 0x1b, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, + 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, + 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x12, 0xba, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, + 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x43, - 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, - 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x1d, 0x12, 0x1b, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, - 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, 0x61, - 0x6c, 0x6f, 0x67, 0x2e, 0x12, 0xba, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, 0x73, - 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x43, - 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, + 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, + 0x76, 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, + 0x92, 0x41, 0x1f, 0x12, 0x1d, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, + 0x73, 0x2e, 0x12, 0xc2, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, + 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, + 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, - 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x92, - 0x41, 0x1f, 0x12, 0x1d, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, - 0x6f, 0x66, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, - 0x2e, 0x12, 0xc2, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x40, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x11, 0x2f, + 0x76, 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, + 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x18, 0x12, + 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, + 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0xc7, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x34, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, + 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x45, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x24, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, + 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x18, 0x12, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, + 0x67, 0x12, 0xbb, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x40, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x11, 0x2f, 0x76, - 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x3a, - 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x18, 0x12, 0x16, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, - 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0xc7, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x34, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, - 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x45, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x24, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, - 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, - 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x18, 0x12, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x73, 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, - 0x12, 0xbb, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, - 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, - 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x76, 0x31, - 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x92, 0x41, 0x18, 0x12, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, - 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x4d, - 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x76, + 0x31, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2f, + 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x18, 0x12, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, + 0x20, 0x61, 0x20, 0x48, 0x6f, 0x73, 0x74, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x42, + 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/host/plugin/host_catalog.go b/internal/host/plugin/host_catalog.go index 437b5ecb4..df151fef0 100644 --- a/internal/host/plugin/host_catalog.go +++ b/internal/host/plugin/host_catalog.go @@ -19,7 +19,7 @@ type HostCatalog struct { *store.HostCatalog tableName string `gorm:"-"` - secrets *structpb.Struct `gorm:"-"` + Secrets *structpb.Struct `gorm:"-"` } // NewHostCatalog creates a new in memory HostCatalog assigned to a scopeId @@ -42,7 +42,7 @@ func NewHostCatalog(ctx context.Context, scopeId, pluginId string, opt ...Option Description: opts.withDescription, Attributes: attrs, }, - secrets: opts.withSecrets, + Secrets: opts.withSecrets, } return hc, nil } @@ -57,11 +57,11 @@ func allocHostCatalog() *HostCatalog { // secret. The secret shallow copied. func (c *HostCatalog) clone() *HostCatalog { cp := proto.Clone(c.HostCatalog) - newSecret := proto.Clone(c.secrets) + newSecret := proto.Clone(c.Secrets) hc := &HostCatalog{ HostCatalog: cp.(*store.HostCatalog), - secrets: newSecret.(*structpb.Struct), + Secrets: newSecret.(*structpb.Struct), } // proto.Clone will convert slices with length and capacity of 0 to nil. // Fix this since gorm treats empty slices differently than nil. diff --git a/internal/host/plugin/repository.go b/internal/host/plugin/repository.go index 5755b3db3..f52d98572 100644 --- a/internal/host/plugin/repository.go +++ b/internal/host/plugin/repository.go @@ -19,8 +19,9 @@ type Repository struct { kms *kms.Kms // plugins is a map from plugin resource id to host plugin client. - // TODO: When we are using go-plugin change from using a plgpb.HostPluginServiceServer - // to the client. + // + // TODO: When we are using go-plugin change from using a + // plgpb.HostPluginServiceServer to the client. plugins map[string]plgpb.HostPluginServiceServer // defaultLimit provides a default for limiting the number of results // returned from the repo diff --git a/internal/host/plugin/repository_host_catalog.go b/internal/host/plugin/repository_host_catalog.go index 416815206..f788fe7ee 100644 --- a/internal/host/plugin/repository_host_catalog.go +++ b/internal/host/plugin/repository_host_catalog.go @@ -274,8 +274,8 @@ func toPluginCatalog(ctx context.Context, in *HostCatalog) (*pb.HostCatalog, err } hc.Attributes = attrs } - if in.secrets != nil { - hc.Secrets = in.secrets + if in.Secrets != nil { + hc.Secrets = in.Secrets } return hc, nil } diff --git a/internal/host/plugin/repository_host_catalog_test.go b/internal/host/plugin/repository_host_catalog_test.go index b4cc8c764..87b6664f4 100644 --- a/internal/host/plugin/repository_host_catalog_test.go +++ b/internal/host/plugin/repository_host_catalog_test.go @@ -212,7 +212,7 @@ func TestRepository_CreateCatalog(t *testing.T) { PluginId: plg.GetPublicId(), Attributes: []byte{}, }, - secrets: func() *structpb.Struct { + Secrets: func() *structpb.Struct { st, err := structpb.NewStruct(map[string]interface{}{ "k1": "v1", "k2": 2, @@ -276,7 +276,7 @@ func TestRepository_CreateCatalog(t *testing.T) { cSecret := allocHostCatalogSecret() err = rw.LookupWhere(ctx, &cSecret, "catalog_id=?", got.GetPublicId()) if tt.wantSecret == nil { - assert.Nil(got.secrets) + assert.Nil(got.Secrets) require.Error(t, err) require.True(t, errors.IsNotFoundError(err)) return diff --git a/internal/plugin/host/options.go b/internal/plugin/host/options.go index 3832ef15d..4bfbe5d13 100644 --- a/internal/plugin/host/options.go +++ b/internal/plugin/host/options.go @@ -1,7 +1,7 @@ package host -// getOpts - iterate the inbound Options and return a struct -func getOpts(opt ...Option) options { +// GetOpts - iterate the inbound Options and return a struct +func GetOpts(opt ...Option) options { opts := getDefaultOptions() for _, o := range opt { o(&opts) @@ -16,6 +16,7 @@ type Option func(*options) type options struct { withName string withDescription string + withPublicId string withLimit int } @@ -40,6 +41,13 @@ func WithName(name string) Option { } } +// WithPublicId provides an optional specific public ID +func WithPublicId(with string) Option { + return func(o *options) { + o.withPublicId = with + } +} + // WithLimit provides an option to provide a limit. Intentionally allowing // negative integers. If WithLimit < 0, then unlimited results are // returned. If WithLimit == 0, then default limits are used for results. diff --git a/internal/plugin/host/options_test.go b/internal/plugin/host/options_test.go index fed3d1c9f..7abe5829d 100644 --- a/internal/plugin/host/options_test.go +++ b/internal/plugin/host/options_test.go @@ -9,19 +9,25 @@ import ( func Test_GetOpts(t *testing.T) { t.Parallel() t.Run("WithName", func(t *testing.T) { - opts := getOpts(WithName("test")) + opts := GetOpts(WithName("test")) testOpts := getDefaultOptions() testOpts.withName = "test" assert.Equal(t, opts, testOpts) }) t.Run("WithDescription", func(t *testing.T) { - opts := getOpts(WithDescription("test desc")) + opts := GetOpts(WithDescription("test desc")) testOpts := getDefaultOptions() testOpts.withDescription = "test desc" assert.Equal(t, opts, testOpts) }) + t.Run("WithPublicId", func(t *testing.T) { + opts := GetOpts(WithPublicId("pl_1234567890")) + testOpts := getDefaultOptions() + testOpts.withPublicId = "pl_1234567890" + assert.Equal(t, opts, testOpts) + }) t.Run("WithLimit", func(t *testing.T) { - opts := getOpts(WithLimit(5)) + opts := GetOpts(WithLimit(5)) testOpts := getDefaultOptions() testOpts.withLimit = 5 assert.Equal(t, opts, testOpts) diff --git a/internal/plugin/host/plugin.go b/internal/plugin/host/plugin.go index a7ef7c9f5..fc5ec1c4f 100644 --- a/internal/plugin/host/plugin.go +++ b/internal/plugin/host/plugin.go @@ -17,7 +17,7 @@ type Plugin struct { // NewPlugin creates a new in memory Plugin assigned to the global scope. // Name, Description are the only allowed option. All other options are ignored. func NewPlugin(opt ...Option) *Plugin { - opts := getOpts(opt...) + opts := GetOpts(opt...) p := &Plugin{ Plugin: &store.Plugin{ ScopeId: scope.Global.String(), diff --git a/internal/plugin/host/plugin_test.go b/internal/plugin/host/plugin_test.go index 0bd6a3c30..1d7af800d 100644 --- a/internal/plugin/host/plugin_test.go +++ b/internal/plugin/host/plugin_test.go @@ -15,8 +15,6 @@ import ( func TestPlugin_Create(t *testing.T) { conn, _ := db.TestSetup(t, "postgres") - type args struct{} - tests := []struct { name string opts []Option diff --git a/internal/plugin/host/repository.go b/internal/plugin/host/repository.go index a8604342a..f07c0bd72 100644 --- a/internal/plugin/host/repository.go +++ b/internal/plugin/host/repository.go @@ -32,7 +32,7 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, opt ...Option) (*Repo return nil, errors.NewDeprecated(errors.InvalidParameter, op, "kms") } - opts := getOpts(opt...) + opts := GetOpts(opt...) if opts.withLimit == 0 { // zero signals the boundary defaults should be used. opts.withLimit = db.DefaultLimit diff --git a/internal/plugin/host/repository_plugin.go b/internal/plugin/host/repository_plugin.go index e3669fefa..414840465 100644 --- a/internal/plugin/host/repository_plugin.go +++ b/internal/plugin/host/repository_plugin.go @@ -20,7 +20,7 @@ import ( // unique within p.ScopeID. // // Both p.CreateTime and c.UpdateTime are ignored. -func (r *Repository) CreatePlugin(ctx context.Context, p *Plugin, _ ...Option) (*Plugin, error) { +func (r *Repository) CreatePlugin(ctx context.Context, p *Plugin, opt ...Option) (*Plugin, error) { const op = "host.(Repository).CreatePlugin" if p == nil { return nil, errors.New(ctx, errors.InvalidParameter, op, "nil Plugin") @@ -39,11 +39,16 @@ func (r *Repository) CreatePlugin(ctx context.Context, p *Plugin, _ ...Option) ( } p = p.clone() - id, err := newPluginId() - if err != nil { - return nil, errors.Wrap(ctx, err, op) + opts := GetOpts(opt...) + + p.PublicId = opts.withPublicId + if p.PublicId == "" { + var err error + p.PublicId, err = newPluginId() + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } } - p.PublicId = id oplogWrapper, err := r.kms.GetWrapper(ctx, p.ScopeId, kms.KeyPurposeOplog) if err != nil { @@ -122,7 +127,7 @@ func (r *Repository) ListPlugins(ctx context.Context, scopeIds []string, opt ... if len(scopeIds) == 0 { return nil, errors.New(ctx, errors.InvalidParameter, op, "no scope id") } - opts := getOpts(opt...) + opts := GetOpts(opt...) limit := r.defaultLimit if opts.withLimit != 0 { // non-zero signals an override of the default limit for the repo. diff --git a/internal/proto/local/controller/api/resources/hostcatalogs/v1/host_catalog.proto b/internal/proto/local/controller/api/resources/hostcatalogs/v1/host_catalog.proto index 325768684..c2c8f917b 100644 --- a/internal/proto/local/controller/api/resources/hostcatalogs/v1/host_catalog.proto +++ b/internal/proto/local/controller/api/resources/hostcatalogs/v1/host_catalog.proto @@ -23,7 +23,7 @@ message HostCatalog { resources.scopes.v1.ScopeInfo scope = 30; // The ID of the plugin of which this catalog is created. - string plugin_id = 34 [json_name="plugin_id"]; + string plugin_id = 34 [json_name="plugin_id", (custom_options.v1.generate_sdk_option) = true]; // Output only. Plugin information for this resource. resources.plugins.v1.PluginInfo plugin = 35; diff --git a/internal/proto/local/controller/api/services/v1/host_catalog_service.proto b/internal/proto/local/controller/api/services/v1/host_catalog_service.proto index ad6fc7dab..db8057d9e 100644 --- a/internal/proto/local/controller/api/services/v1/host_catalog_service.proto +++ b/internal/proto/local/controller/api/services/v1/host_catalog_service.proto @@ -104,8 +104,8 @@ message ListHostCatalogsResponse { message CreateHostCatalogRequest { api.resources.hostcatalogs.v1.HostCatalog item = 1; // As an alternative to providing the plugin id in the provided HostCatalog, - // this field can be used to lookup the plugin using it's name. - string plugin_name = 2; + // this field can be used to lookup the plugin using its name. + string plugin_name = 2 [json_name="plugin_name"]; } message CreateHostCatalogResponse { diff --git a/internal/servers/controller/controller.go b/internal/servers/controller/controller.go index eca57cf3e..41d01118d 100644 --- a/internal/servers/controller/controller.go +++ b/internal/servers/controller/controller.go @@ -24,7 +24,7 @@ import ( "github.com/hashicorp/boundary/internal/servers/controller/common" "github.com/hashicorp/boundary/internal/session" "github.com/hashicorp/boundary/internal/target" - plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin" + "github.com/hashicorp/boundary/sdk/pbs/plugin" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-secure-stdlib/mlock" "github.com/patrickmn/go-cache" @@ -104,6 +104,10 @@ func New(ctx context.Context, conf *Config) (*Controller, error) { } } + if conf.HostPlugins == nil { + conf.HostPlugins = make(map[string]plugin.HostPluginServiceServer) + } + // Set up repo stuff dbase := db.New(c.conf.Database) kmsRepo, err := kms.NewRepository(dbase, dbase) @@ -137,7 +141,7 @@ func New(ctx context.Context, conf *Config) (*Controller, error) { return static.NewRepository(dbase, dbase, c.kms) } c.PluginHostRepoFn = func() (*hostplugin.Repository, error) { - return hostplugin.NewRepository(dbase, dbase, c.kms, map[string]plgpb.HostPluginServiceServer{}) + return hostplugin.NewRepository(dbase, dbase, c.kms, c.conf.HostPlugins) } c.HostPluginRepoFn = func() (*host.Repository, error) { return host.NewRepository(dbase, dbase, c.kms) diff --git a/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go b/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go index d5879439c..a8db57fbc 100644 --- a/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go +++ b/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go @@ -50,9 +50,14 @@ var ( action.List, } - collectionTypeMap = map[resource.Type]action.ActionSet{ - resource.HostSet: host_sets.CollectionActions, - resource.Host: hosts.CollectionActions, + collectionTypeMap = map[string]map[resource.Type]action.ActionSet{ + "static": { + resource.HostSet: host_sets.CollectionActions, + resource.Host: hosts.CollectionActions, + }, + "plugin": { + resource.HostSet: host_sets.CollectionActions, + }, } ) @@ -121,11 +126,11 @@ func (s Service) ListHostCatalogs(ctx context.Context, req *pbs.ListHostCatalogs return &pbs.ListHostCatalogsResponse{}, nil } - ul, pluginInfoMap, err := s.listFromRepo(ctx, scopeIds) + items, pluginInfoMap, err := s.listFromRepo(ctx, scopeIds) if err != nil { return nil, err } - if len(ul) == 0 { + if len(items) == 0 { return &pbs.ListHostCatalogsResponse{}, nil } @@ -133,11 +138,11 @@ func (s Service) ListHostCatalogs(ctx context.Context, req *pbs.ListHostCatalogs if err != nil { return nil, err } - finalItems := make([]*pb.HostCatalog, 0, len(ul)) + finalItems := make([]*pb.HostCatalog, 0, len(items)) res := perms.Resource{ Type: resource.HostCatalog, } - for _, item := range ul { + for _, item := range items { res.Id = item.GetPublicId() res.ScopeId = item.GetScopeId() authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings() @@ -155,11 +160,20 @@ func (s Service) ListHostCatalogs(ctx context.Context, req *pbs.ListHostCatalogs outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions)) } if outputFields.Has(globals.AuthorizedCollectionActionsField) { - collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, item.GetPublicId()) - if err != nil { - return nil, err + var collType string + switch item.(type) { + case *static.HostCatalog: + collType = "static" + case *plugin.HostCatalog: + collType = "plugin" + } + if collType != "" { + collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap[collType], authResults.Scope.Id, item.GetPublicId()) + if err != nil { + return nil, err + } + outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions)) } - outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions)) } switch hc := item.(type) { case *plugin.HostCatalog: @@ -210,11 +224,20 @@ 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) { - collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, hc.GetPublicId()) - if err != nil { - return nil, err + var collType string + switch hc.(type) { + case *static.HostCatalog: + collType = "static" + case *plugin.HostCatalog: + collType = "plugin" + } + if collType != "" { + collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap[collType], authResults.Scope.Id, hc.GetPublicId()) + if err != nil { + return nil, err + } + outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions)) } - outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions)) } if plg != nil { outputOpts = append(outputOpts, handlers.WithPlugin(plg)) @@ -258,11 +281,20 @@ 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) { - collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, hc.GetPublicId()) - if err != nil { - return nil, err + var collType string + switch hc.(type) { + case *static.HostCatalog: + collType = "static" + case *plugin.HostCatalog: + collType = "plugin" + } + if collType != "" { + collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap[collType], authResults.Scope.Id, hc.GetPublicId()) + if err != nil { + return nil, err + } + outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions)) } - outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions)) } if plg != nil { outputOpts = append(outputOpts, handlers.WithPlugin(plg)) @@ -309,7 +341,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) { - collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, hc.GetPublicId()) + collectionActions, err := auth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap["static"], authResults.Scope.Id, hc.GetPublicId()) if err != nil { return nil, err } @@ -408,7 +440,7 @@ func (s Service) listFromRepo(ctx context.Context, scopeIds []string) ([]host.Ca } func (s Service) createStaticInRepo(ctx context.Context, projId string, item *pb.HostCatalog) (*static.HostCatalog, error) { - const op = "host_catalogs.(Service).createInRepo" + const op = "host_catalogs.(Service).createStaticInRepo" h, err := toStorageStaticCatalog(ctx, projId, item) if err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to build catalog for creation")) @@ -428,7 +460,7 @@ func (s Service) createStaticInRepo(ctx context.Context, projId string, item *pb } func (s Service) createPluginInRepo(ctx context.Context, projId string, req *pbs.CreateHostCatalogRequest) (*plugin.HostCatalog, *plugins.PluginInfo, error) { - const op = "host_catalogs.(Service).createInRepo" + const op = "host_catalogs.(Service).createPluginInRepo" item := req.GetItem() pluginId := item.GetPluginId() if pluginId == "" { @@ -716,13 +748,15 @@ func validateCreateRequest(req *pbs.CreateHostCatalogRequest) error { case static.Subtype: case plugin.Subtype: if req.GetItem().GetPlugin() != nil { - badFields[globals.PluginField] = fmt.Sprintf("This is a read only field.") + badFields[globals.PluginField] = "This is a read only field." } if req.GetItem().GetPluginId() == "" && req.GetPluginName() == "" { - badFields[globals.PluginIdField] = fmt.Sprintf("This is a required field.") + badFields[globals.PluginIdField] = "This or plugin name is a required field." + badFields[globals.PluginNameField] = "This or plugin id is a required field." } if req.GetItem().GetPluginId() != "" && req.GetPluginName() != "" { - badFields[globals.PluginIdField] = fmt.Sprintf("Can't set the plugin name field along with this field.") + badFields[globals.PluginIdField] = "Can't set the plugin name field along with this field." + badFields[globals.PluginNameField] = "Can't set the plugin id field along with this field." } default: badFields[globals.TypeField] = fmt.Sprintf("This is a required field and must be either %q or %q.", static.Subtype.String(), plugin.Subtype.String()) diff --git a/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go b/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go index 797ea630d..a0f496094 100644 --- a/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go +++ b/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go @@ -36,17 +36,27 @@ import ( "github.com/stretchr/testify/require" ) -var authorizedCollectionActions = map[string]*structpb.ListValue{ - "host-sets": { - Values: []*structpb.Value{ - structpb.NewStringValue("create"), - structpb.NewStringValue("list"), +var authorizedCollectionActions = map[string]map[string]*structpb.ListValue{ + "static": { + "host-sets": { + Values: []*structpb.Value{ + structpb.NewStringValue("create"), + structpb.NewStringValue("list"), + }, + }, + "hosts": { + Values: []*structpb.Value{ + structpb.NewStringValue("create"), + structpb.NewStringValue("list"), + }, }, }, - "hosts": { - Values: []*structpb.Value{ - structpb.NewStringValue("create"), - structpb.NewStringValue("list"), + "plugin": { + "host-sets": { + Values: []*structpb.Value{ + structpb.NewStringValue("create"), + structpb.NewStringValue("list"), + }, }, }, } @@ -86,7 +96,7 @@ func TestGet_Static(t *testing.T) { UpdatedTime: hc.UpdateTime.GetTimestamp(), Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], } cases := []struct { @@ -187,7 +197,7 @@ func TestGet_Plugin(t *testing.T) { UpdatedTime: hc.UpdateTime.GetTimestamp(), Type: plugin.Subtype.String(), AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["plugin"], } cases := []struct { @@ -277,7 +287,7 @@ func TestList(t *testing.T) { Version: 1, Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }) } @@ -301,7 +311,7 @@ func TestList(t *testing.T) { Version: 1, Type: plugin.Subtype.String(), AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["plugin"], } wantSomeCatalogs = append(wantSomeCatalogs, cat) testPluginCatalogs = append(testPluginCatalogs, cat) @@ -318,7 +328,7 @@ func TestList(t *testing.T) { Version: 1, Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }) } @@ -341,7 +351,7 @@ func TestList(t *testing.T) { Version: 1, Type: plugin.Subtype.String(), AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["plugin"], }) } @@ -597,7 +607,7 @@ func TestCreate_Static(t *testing.T) { Description: &wrappers.StringValue{Value: "desc"}, Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }, }, }, @@ -764,7 +774,7 @@ func TestCreate_Plugin(t *testing.T) { Description: &wrappers.StringValue{Value: "desc"}, Type: plugin.Subtype.String(), AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["plugin"], }, }, }, @@ -951,7 +961,7 @@ func TestUpdate(t *testing.T) { CreatedTime: hc.GetCreateTime().GetTimestamp(), Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }, }, }, @@ -977,7 +987,7 @@ func TestUpdate(t *testing.T) { CreatedTime: hc.GetCreateTime().GetTimestamp(), Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }, }, }, @@ -1032,7 +1042,7 @@ func TestUpdate(t *testing.T) { CreatedTime: hc.GetCreateTime().GetTimestamp(), Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }, }, }, @@ -1055,7 +1065,7 @@ func TestUpdate(t *testing.T) { CreatedTime: hc.GetCreateTime().GetTimestamp(), Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }, }, }, @@ -1080,7 +1090,7 @@ func TestUpdate(t *testing.T) { CreatedTime: hc.GetCreateTime().GetTimestamp(), Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }, }, }, @@ -1105,7 +1115,7 @@ func TestUpdate(t *testing.T) { CreatedTime: hc.GetCreateTime().GetTimestamp(), Type: "static", AuthorizedActions: testAuthorizedActions, - AuthorizedCollectionActions: authorizedCollectionActions, + AuthorizedCollectionActions: authorizedCollectionActions["static"], }, }, }, diff --git a/sdk/pbs/controller/api/resources/hostcatalogs/host_catalog.pb.go b/sdk/pbs/controller/api/resources/hostcatalogs/host_catalog.pb.go index 988b3ccb9..2b318fed2 100644 --- a/sdk/pbs/controller/api/resources/hostcatalogs/host_catalog.pb.go +++ b/sdk/pbs/controller/api/resources/hostcatalogs/host_catalog.pb.go @@ -226,7 +226,7 @@ var file_controller_api_resources_hostcatalogs_v1_host_catalog_proto_rawDesc = [ 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf4, 0x07, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfa, 0x07, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, @@ -234,68 +234,69 @@ var file_controller_api_resources_hostcatalogs_v1_host_catalog_proto_rawDesc = [ 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, - 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x22, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x5f, 0x69, 0x64, 0x12, 0x47, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x23, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x46, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x14, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, - 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x62, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x22, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, - 0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, - 0x18, 0x6e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, - 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x2f, - 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x9d, 0x01, 0x0a, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0xb6, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x56, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x2e, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, - 0x6a, 0x0a, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x43, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x09, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x22, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x09, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x47, 0x0a, 0x06, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x12, 0x46, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x14, + 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x62, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x22, 0xa0, + 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, + 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x5a, 0x5a, 0x58, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x73, 0x64, 0x6b, - 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x68, 0x6f, - 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x3b, 0x68, 0x6f, 0x73, 0x74, 0x63, - 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x3e, + 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x46, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3d, 0x0a, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, + 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x73, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01, 0x52, 0x07, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x9d, 0x01, 0x0a, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb6, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x56, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, + 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x61, + 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x6a, 0x0a, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x42, 0x5a, 0x5a, 0x58, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, + 0x72, 0x79, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, + 0x3b, 0x68, 0x6f, 0x73, 0x74, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var (