Add more host-catalog and host-set CLI support (#1567)

Add more host-catalog and host-set CLI support

Co-authored-by: Todd <T.Alan.Knight@gmail.com>
This commit is contained in:
Jeff MitchellandTodd authored and GitHub committed 2021-09-28 09:40:12 -04:00
1 parent a834a14785
commit 7d71618df0
37 files changed
+803 -406

No files matched your search

+19
View File
@@ -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
}
}
+1
View File
@@ -61,4 +61,5 @@ const (
PreferredEndpointsField = "preferred_endpoints"
PluginIdField = "plugin_id"
PluginField = "plugin"
PluginNameField = "plugin_name"
)
+15 -6
View File
@@ -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",
+5 -5
View File
@@ -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
+6
View File
@@ -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
}
+14 -2
View File
@@ -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.
+12
View File
@@ -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 " <not included in response>"
}
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
+48
View File
@@ -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
}
+15 -1
View File
@@ -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
}
}
}
+4
View File
@@ -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
+41 -30
View File
@@ -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 {
+24 -8
View File
@@ -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)
}
@@ -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
}
+16 -8
View File
@@ -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)
}
@@ -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
}
+109 -45
View File
@@ -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 {
+50 -42
View File
@@ -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)
})
}
}
}
+22 -12
View File
@@ -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": {
+43 -4
View File
@@ -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
}
+1 -1
View File
@@ -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"
@@ -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 (
+4 -4
View File
@@ -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.
+3 -2
View File
@@ -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
@@ -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
}
@@ -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
+10 -2
View File
@@ -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.
+9 -3
View File
@@ -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)
+1 -1
View File
@@ -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(),
-2
View File
@@ -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
+1 -1
View File
@@ -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
+11 -6
View File
@@ -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.
@@ -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;
@@ -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 {
+6 -2
View File
@@ -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)
@@ -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())
@@ -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"],
},
},
},
@@ -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 (