diff --git a/api/sys_plugins.go b/api/sys_plugins.go index fda919449997..b00b314ee5eb 100644 --- a/api/sys_plugins.go +++ b/api/sys_plugins.go @@ -20,6 +20,9 @@ type ListPluginsInput struct { type ListPluginsResponse struct { // PluginsByType is the list of plugins by type. PluginsByType map[consts.PluginType][]string `json:"types"` + + // NamesDeprecated is the list of names of the plugins. + NamesDeprecated []string `json:"names"` } // ListPlugins lists all plugins in the catalog and returns their names as a @@ -53,6 +56,20 @@ func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) { return nil, errors.New("data from server response is empty") } + if resp.StatusCode == 405 { + // We received an Unsupported Operation response from Vault, indicating + // Vault of an older version that doesn't support the READ method yet. + var result struct { + Data struct { + Keys []string `json:"keys"` + } `json:"data"` + } + if err := resp.DecodeJSON(&result); err != nil { + return nil, err + } + return &ListPluginsResponse{NamesDeprecated: result.Data.Keys}, nil + } + result := &ListPluginsResponse{ PluginsByType: make(map[consts.PluginType][]string), } diff --git a/vault/logical_system.go b/vault/logical_system.go index a0cf9d15cd12..f042abe43daa 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -256,7 +256,8 @@ func (b *SystemBackend) handleTidyLeases(ctx context.Context, req *logical.Reque } func (b *SystemBackend) handlePluginCatalogTypedList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { - pluginType, err := consts.ParsePluginType(d.Get("type").(string)) + pluginTypeStr := d.Get("type").(string) + pluginType, err := consts.ParsePluginType(pluginTypeStr) if err != nil { return nil, err } @@ -268,6 +269,25 @@ func (b *SystemBackend) handlePluginCatalogTypedList(ctx context.Context, req *l return logical.ListResponse(plugins), nil } +func (b *SystemBackend) handlePluginsListDeprecated(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + var plugins []string + pluginsAdded := make(map[string]bool) + for _, pluginType := range consts.PluginTypes { + names, err := b.Core.pluginCatalog.List(ctx, pluginType) + if err != nil { + return nil, err + } + for _, name := range names { + if _, found := pluginsAdded[name]; !found { + plugins = append(plugins, name) + pluginsAdded[name] = true + } + } + } + sort.Strings(plugins) + return logical.ListResponse(plugins), nil +} + func (b *SystemBackend) handlePluginCatalogUntypedList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { pluginsByType := make(map[string]interface{}) for _, pluginType := range consts.PluginTypes { diff --git a/vault/logical_system_paths.go b/vault/logical_system_paths.go index ab97aa04ebbe..4d7b58547d1b 100644 --- a/vault/logical_system_paths.go +++ b/vault/logical_system_paths.go @@ -560,6 +560,26 @@ func (b *SystemBackend) sealPaths() []*framework.Path { func (b *SystemBackend) pluginsCatalogPaths() []*framework.Path { return []*framework.Path{ + { + Pattern: "plugins/catalog/?$", + + Fields: map[string]*framework.FieldSchema{ + "type": &framework.FieldSchema{ + Type: framework.TypeString, + Description: strings.TrimSpace(sysHelp["plugin-catalog_type"][0]), + }, + }, + + Operations: map[logical.Operation]framework.OperationHandler{ + logical.ListOperation: &framework.PathOperation{ + Callback: b.handlePluginsListDeprecated, + Summary: "List the plugins in the catalog.", + }, + }, + + HelpSynopsis: strings.TrimSpace(sysHelp["plugin-catalog"][0]), + HelpDescription: strings.TrimSpace(sysHelp["plugin-catalog"][1]), + }, { Pattern: "plugins/catalog/(?Pauth|database|secret)/?$",