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 102f5f6832
commit 9849af8663
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 153 additions and 50 deletions

View File

@ -32,10 +32,11 @@ type ListPluginsResponse struct {
}
type PluginDetails struct {
Type string `json:"string"`
Name string `json:"name"`
Version string `json:"version,omitempty"`
Builtin bool `json:"builtin"`
Type string `json:"string"`
Name string `json:"name"`
Version string `json:"version,omitempty"`
Builtin bool `json:"builtin"`
DeprecationStatus string `json:"deprecation_status,omitempty" mapstructure:"deprecation_status"`
}
// ListPlugins wraps ListPluginsWithContext using context.Background.
@ -158,11 +159,12 @@ type GetPluginInput struct {
// GetPluginResponse is the response from the GetPlugin call.
type GetPluginResponse struct {
Args []string `json:"args"`
Builtin bool `json:"builtin"`
Command string `json:"command"`
Name string `json:"name"`
SHA256 string `json:"sha256"`
Args []string `json:"args"`
Builtin bool `json:"builtin"`
Command string `json:"command"`
Name string `json:"name"`
SHA256 string `json:"sha256"`
DeprecationStatus string `json:"deprecation_status,omitempty"`
}
// 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

@ -107,11 +107,12 @@ func (c *PluginInfoCommand) Run(args []string) int {
}
data := map[string]interface{}{
"args": resp.Args,
"builtin": resp.Builtin,
"command": resp.Command,
"name": resp.Name,
"sha256": resp.SHA256,
"args": resp.Args,
"builtin": resp.Builtin,
"command": resp.Command,
"name": resp.Name,
"sha256": resp.SHA256,
"deprecation_status": resp.DeprecationStatus,
}
if c.flagField != "" {

View File

@ -18,6 +18,8 @@ var (
type PluginListCommand struct {
*BaseCommand
flagDetailed bool
}
func (c *PluginListCommand) Synopsis() string {
@ -40,13 +42,30 @@ Usage: vault plugin list [options] [TYPE]
$ vault plugin list database
List all available plugins with detailed output:
$ vault plugin list -detailed
` + c.Flags().Help()
return strings.TrimSpace(helpText)
}
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 {
@ -105,19 +124,11 @@ func (c *PluginListCommand) Run(args []string) int {
switch Format(c.UI) {
case "table":
var flattenedNames []string
namesAdded := make(map[string]bool)
for _, names := range resp.PluginsByType {
for _, name := range names {
if ok := namesAdded[name]; !ok {
flattenedNames = append(flattenedNames, name)
namesAdded[name] = true
}
}
sort.Strings(flattenedNames)
if c.flagDetailed {
c.UI.Output(tableOutput(c.detailedResponse(resp), nil))
return 0
}
list := append([]string{"Plugins"}, flattenedNames...)
c.UI.Output(tableOutput(list, nil))
c.UI.Output(tableOutput(c.simpleResponse(resp), nil))
return 0
default:
res := make(map[string]interface{})
@ -127,3 +138,28 @@ func (c *PluginListCommand) Run(args []string) int {
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

@ -88,11 +88,12 @@ func (r *PluginRunner) RunMetadataMode(ctx context.Context, wrapper RunnerUtil,
// VersionedPlugin holds any versioning information stored about a plugin in the
// plugin catalog.
type VersionedPlugin struct {
Type string `json:"type"` // string instead of consts.PluginType so that we get the string form in API responses.
Name string `json:"name"`
Version string `json:"version"`
SHA256 string `json:"sha256,omitempty"`
Builtin bool `json:"builtin"`
Type string `json:"type"` // string instead of consts.PluginType so that we get the string form in API responses.
Name string `json:"name"`
Version string `json:"version"`
SHA256 string `json:"sha256,omitempty"`
Builtin bool `json:"builtin"`
DeprecationStatus string `json:"deprecation_status,omitempty"`
// Pre-parsed semver struct of the Version field
SemanticVersion *version.Version `json:"-"`

View File

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

View File

@ -2989,14 +2989,18 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
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
expectedRespData := map[string]interface{}{
"name": "mysql-database-plugin",
"command": "",
"args": []string(nil),
"sha256": "",
"builtin": true,
"version": c.pluginCatalog.getBuiltinVersion(consts.PluginTypeDatabase, "mysql-database-plugin"),
"name": "mysql-database-plugin",
"command": "",
"args": []string(nil),
"sha256": "",
"builtin": true,
"version": c.pluginCatalog.getBuiltinVersion(consts.PluginTypeDatabase, "mysql-database-plugin"),
"deprecation_status": deprecationStatus.String(),
}
if !reflect.DeepEqual(actualRespData, expectedRespData) {
t.Fatalf("expected did not match actual, got %#v\n expected %#v\n", actualRespData, expectedRespData)

View File

@ -853,15 +853,17 @@ func (c *PluginCatalog) listInternal(ctx context.Context, pluginType consts.Plug
version := c.getBuiltinVersion(pluginType, plugin)
semanticVersion, err := semver.NewVersion(version)
deprecationStatus, _ := c.builtinRegistry.DeprecationStatus(plugin, pluginType)
if err != nil {
return nil, err
}
result = append(result, pluginutil.VersionedPlugin{
Name: plugin,
Type: pluginType.String(),
Version: version,
Builtin: true,
SemanticVersion: semanticVersion,
Name: plugin,
Type: pluginType.String(),
Version: version,
Builtin: true,
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'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
Display information about a plugin
@ -16,13 +22,26 @@ Display information about a plugin
```shell-session
$ vault plugin info auth my-custom-plugin
Key Value
--- -----
args []
builtin false
command my-custom-plugin
name my-custom-plugin
sha256 d3f0a8be02f6c074cf38c9c99d4d04c9c6466249
Key Value
--- -----
args []
builtin false
command my-custom-plugin
deprecation_status n/a
name my-custom-plugin
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

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.
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
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
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
formats are "table", "json", or "yaml". This can also be specified via the
`VAULT_FORMAT` environment variable.
### Command Options
- `-detailed` `(bool: false)` - Print detailed information such as version and
deprecation status about each plugin.