Add deprecation status to plugin api and cli (#17077)

* api: Add deprecation status to plugin endpoints

* cli: Add -detailed flag to `plugin list`

* docs: Update plugin list/info docs
This commit is contained in:
Mike Palmiotto
2022-09-09 16:03:07 -04:00
committed by GitHub
parent 661ba95887
commit 63e6cc1d66
10 changed files with 153 additions and 50 deletions

View File

@@ -36,6 +36,7 @@ type PluginDetails struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
Builtin bool `json:"builtin"` Builtin bool `json:"builtin"`
DeprecationStatus string `json:"deprecation_status,omitempty" mapstructure:"deprecation_status"`
} }
// ListPlugins wraps ListPluginsWithContext using context.Background. // ListPlugins wraps ListPluginsWithContext using context.Background.
@@ -163,6 +164,7 @@ type GetPluginResponse struct {
Command string `json:"command"` Command string `json:"command"`
Name string `json:"name"` Name string `json:"name"`
SHA256 string `json:"sha256"` SHA256 string `json:"sha256"`
DeprecationStatus string `json:"deprecation_status,omitempty"`
} }
// GetPlugin wraps GetPluginWithContext using context.Background. // GetPlugin wraps GetPluginWithContext using context.Background.

12
changelog/17077.txt Normal file
View File

@@ -0,0 +1,12 @@
```release-note:change
plugins: `GET /sys/plugins/catalog/:type/:name` endpoint contains deprecation status for builtin plugins.
```
```release-note:change
plugins: `GET /sys/plugins/catalog/` endpoint contains deprecation status in `detailed` list.
```
```release-note:change
plugins: `plugin list` now accepts a `-detailed` flag, which display deprecation status and version info.
```
```release-note:change
plugins: `plugin info` displays deprecation status for builtin plugins.
```

View File

@@ -112,6 +112,7 @@ func (c *PluginInfoCommand) Run(args []string) int {
"command": resp.Command, "command": resp.Command,
"name": resp.Name, "name": resp.Name,
"sha256": resp.SHA256, "sha256": resp.SHA256,
"deprecation_status": resp.DeprecationStatus,
} }
if c.flagField != "" { if c.flagField != "" {

View File

@@ -18,6 +18,8 @@ var (
type PluginListCommand struct { type PluginListCommand struct {
*BaseCommand *BaseCommand
flagDetailed bool
} }
func (c *PluginListCommand) Synopsis() string { func (c *PluginListCommand) Synopsis() string {
@@ -40,13 +42,30 @@ Usage: vault plugin list [options] [TYPE]
$ vault plugin list database $ vault plugin list database
List all available plugins with detailed output:
$ vault plugin list -detailed
` + c.Flags().Help() ` + c.Flags().Help()
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }
func (c *PluginListCommand) Flags() *FlagSets { func (c *PluginListCommand) Flags() *FlagSets {
return c.flagSet(FlagSetHTTP | FlagSetOutputFormat) set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
f.BoolVar(&BoolVar{
Name: "detailed",
Target: &c.flagDetailed,
Default: false,
Usage: "Print detailed plugin information such as plugin type, " +
"version, and deprecation status for each plugin. This option " +
"is only applicable to table-formatted output.",
})
return set
} }
func (c *PluginListCommand) AutocompleteArgs() complete.Predictor { func (c *PluginListCommand) AutocompleteArgs() complete.Predictor {
@@ -105,19 +124,11 @@ func (c *PluginListCommand) Run(args []string) int {
switch Format(c.UI) { switch Format(c.UI) {
case "table": case "table":
var flattenedNames []string if c.flagDetailed {
namesAdded := make(map[string]bool) c.UI.Output(tableOutput(c.detailedResponse(resp), nil))
for _, names := range resp.PluginsByType { return 0
for _, name := range names {
if ok := namesAdded[name]; !ok {
flattenedNames = append(flattenedNames, name)
namesAdded[name] = true
} }
} c.UI.Output(tableOutput(c.simpleResponse(resp), nil))
sort.Strings(flattenedNames)
}
list := append([]string{"Plugins"}, flattenedNames...)
c.UI.Output(tableOutput(list, nil))
return 0 return 0
default: default:
res := make(map[string]interface{}) res := make(map[string]interface{})
@@ -127,3 +138,28 @@ func (c *PluginListCommand) Run(args []string) int {
return OutputData(c.UI, res) return OutputData(c.UI, res)
} }
} }
func (c *PluginListCommand) simpleResponse(plugins *api.ListPluginsResponse) []string {
var flattenedNames []string
namesAdded := make(map[string]bool)
for _, names := range plugins.PluginsByType {
for _, name := range names {
if ok := namesAdded[name]; !ok {
flattenedNames = append(flattenedNames, name)
namesAdded[name] = true
}
}
sort.Strings(flattenedNames)
}
list := append([]string{"Plugins"}, flattenedNames...)
return list
}
func (c *PluginListCommand) detailedResponse(plugins *api.ListPluginsResponse) []string {
out := []string{"Name | Type | Version | Deprecation Status"}
for _, plugin := range plugins.Details {
out = append(out, fmt.Sprintf("%s | %s | %s | %s", plugin.Name, plugin.Type, plugin.Version, plugin.DeprecationStatus))
}
return out
}

View File

@@ -93,6 +93,7 @@ type VersionedPlugin struct {
Version string `json:"version"` Version string `json:"version"`
SHA256 string `json:"sha256,omitempty"` SHA256 string `json:"sha256,omitempty"`
Builtin bool `json:"builtin"` Builtin bool `json:"builtin"`
DeprecationStatus string `json:"deprecation_status,omitempty"`
// Pre-parsed semver struct of the Version field // Pre-parsed semver struct of the Version field
SemanticVersion *version.Version `json:"-"` SemanticVersion *version.Version `json:"-"`

View File

@@ -572,6 +572,11 @@ func (b *SystemBackend) handlePluginCatalogRead(ctx context.Context, _ *logical.
"version": plugin.Version, "version": plugin.Version,
} }
if plugin.Builtin {
status, _ := b.Core.builtinRegistry.DeprecationStatus(plugin.Name, plugin.Type)
data["deprecation_status"] = status.String()
}
return &logical.Response{ return &logical.Response{
Data: data, Data: data,
}, nil }, nil

View File

@@ -2989,6 +2989,9 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
// Get deprecation status directly from the registry so we can compare it to the API response
deprecationStatus, _ := c.builtinRegistry.DeprecationStatus("mysql-database-plugin", consts.PluginTypeDatabase)
actualRespData := resp.Data actualRespData := resp.Data
expectedRespData := map[string]interface{}{ expectedRespData := map[string]interface{}{
"name": "mysql-database-plugin", "name": "mysql-database-plugin",
@@ -2997,6 +3000,7 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
"sha256": "", "sha256": "",
"builtin": true, "builtin": true,
"version": c.pluginCatalog.getBuiltinVersion(consts.PluginTypeDatabase, "mysql-database-plugin"), "version": c.pluginCatalog.getBuiltinVersion(consts.PluginTypeDatabase, "mysql-database-plugin"),
"deprecation_status": deprecationStatus.String(),
} }
if !reflect.DeepEqual(actualRespData, expectedRespData) { if !reflect.DeepEqual(actualRespData, expectedRespData) {
t.Fatalf("expected did not match actual, got %#v\n expected %#v\n", actualRespData, expectedRespData) t.Fatalf("expected did not match actual, got %#v\n expected %#v\n", actualRespData, expectedRespData)

View File

@@ -853,6 +853,7 @@ func (c *PluginCatalog) listInternal(ctx context.Context, pluginType consts.Plug
version := c.getBuiltinVersion(pluginType, plugin) version := c.getBuiltinVersion(pluginType, plugin)
semanticVersion, err := semver.NewVersion(version) semanticVersion, err := semver.NewVersion(version)
deprecationStatus, _ := c.builtinRegistry.DeprecationStatus(plugin, pluginType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -862,6 +863,7 @@ func (c *PluginCatalog) listInternal(ctx context.Context, pluginType consts.Plug
Version: version, Version: version,
Builtin: true, Builtin: true,
SemanticVersion: semanticVersion, SemanticVersion: semanticVersion,
DeprecationStatus: deprecationStatus.String(),
}) })
} }

View File

@@ -9,6 +9,12 @@ description: The "plugin info" command displays information about a plugin in th
The `plugin info` displays information about a plugin in the catalog. The `plugin info` displays information about a plugin in the catalog.
The plugin's type of "auth", "database", or "secret" must be included. The plugin's type of "auth", "database", or "secret" must be included.
## deprecation_status field
As of 1.12, all builtin plugins will have an associated Deprecation
Status. This status will be reflected in the `deprecation_status` key/value
pair, seen below.
## Examples ## Examples
Display information about a plugin Display information about a plugin
@@ -21,10 +27,23 @@ Key Value
args [] args []
builtin false builtin false
command my-custom-plugin command my-custom-plugin
deprecation_status n/a
name my-custom-plugin name my-custom-plugin
sha256 d3f0a8be02f6c074cf38c9c99d4d04c9c6466249 sha256 d3f0a8be02f6c074cf38c9c99d4d04c9c6466249
``` ```
```shell-session
$ vault plugin info database postgresql-database-plugin
Key Value
--- -----
args []
builtin true
command n/a
deprecation_status supported
name postgresql-database-plugin
sha256 n/a
```
## Usage ## Usage
The following flags are available in addition to the [standard set of The following flags are available in addition to the [standard set of

View File

@@ -9,6 +9,12 @@ description: The "plugin list" command lists all available plugins in the plugin
The `plugin list` command lists all available plugins in the plugin catalog. The `plugin list` command lists all available plugins in the plugin catalog.
It can be used alone or with a type such as "auth", "database", or "secret". It can be used alone or with a type such as "auth", "database", or "secret".
## Deprecation Status Column
As of 1.12, all builtin plugins will have an associated Deprecation
Status. This status will be reflected in the `Deprecation Status` column, seen
below. All non-builtin plugins will show a `Deprecation Status` of "n/a".
## Examples ## Examples
List all available plugins in the catalog. List all available plugins in the catalog.
@@ -28,6 +34,16 @@ cassandra-database-plugin
# ... # ...
``` ```
List detailed plugin information:
```shell-session
$ vault plugin list -detailed
Name Type Version Deprecation Status
---- ---- ------- ------------------
alicloud auth v0.12.0+builtin supported
app-id auth v1.12.0+builtin.vault pending removal
# ...
```
## Usage ## Usage
The following flags are available in addition to the [standard set of The following flags are available in addition to the [standard set of
@@ -38,3 +54,8 @@ flags](/docs/commands) included on all commands.
- `-format` `(string: "table")` - Print the output in the given format. Valid - `-format` `(string: "table")` - Print the output in the given format. Valid
formats are "table", "json", or "yaml". This can also be specified via the formats are "table", "json", or "yaml". This can also be specified via the
`VAULT_FORMAT` environment variable. `VAULT_FORMAT` environment variable.
### Command Options
- `-detailed` `(bool: false)` - Print detailed information such as version and
deprecation status about each plugin.