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:
parent
102f5f6832
commit
9849af8663
|
@ -32,10 +32,11 @@ type ListPluginsResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PluginDetails struct {
|
type PluginDetails struct {
|
||||||
Type string `json:"string"`
|
Type string `json:"string"`
|
||||||
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.
|
||||||
|
@ -158,11 +159,12 @@ type GetPluginInput struct {
|
||||||
|
|
||||||
// GetPluginResponse is the response from the GetPlugin call.
|
// GetPluginResponse is the response from the GetPlugin call.
|
||||||
type GetPluginResponse struct {
|
type GetPluginResponse struct {
|
||||||
Args []string `json:"args"`
|
Args []string `json:"args"`
|
||||||
Builtin bool `json:"builtin"`
|
Builtin bool `json:"builtin"`
|
||||||
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.
|
||||||
|
|
|
@ -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.
|
||||||
|
```
|
|
@ -107,11 +107,12 @@ func (c *PluginInfoCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"args": resp.Args,
|
"args": resp.Args,
|
||||||
"builtin": resp.Builtin,
|
"builtin": resp.Builtin,
|
||||||
"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 != "" {
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(flattenedNames)
|
|
||||||
}
|
}
|
||||||
list := append([]string{"Plugins"}, flattenedNames...)
|
c.UI.Output(tableOutput(c.simpleResponse(resp), nil))
|
||||||
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
|
||||||
|
}
|
||||||
|
|
|
@ -88,11 +88,12 @@ func (r *PluginRunner) RunMetadataMode(ctx context.Context, wrapper RunnerUtil,
|
||||||
// VersionedPlugin holds any versioning information stored about a plugin in the
|
// VersionedPlugin holds any versioning information stored about a plugin in the
|
||||||
// plugin catalog.
|
// plugin catalog.
|
||||||
type VersionedPlugin struct {
|
type VersionedPlugin struct {
|
||||||
Type string `json:"type"` // string instead of consts.PluginType so that we get the string form in API responses.
|
Type string `json:"type"` // string instead of consts.PluginType so that we get the string form in API responses.
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
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:"-"`
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -2989,14 +2989,18 @@ 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",
|
||||||
"command": "",
|
"command": "",
|
||||||
"args": []string(nil),
|
"args": []string(nil),
|
||||||
"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)
|
||||||
|
|
|
@ -853,15 +853,17 @@ 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
|
||||||
}
|
}
|
||||||
result = append(result, pluginutil.VersionedPlugin{
|
result = append(result, pluginutil.VersionedPlugin{
|
||||||
Name: plugin,
|
Name: plugin,
|
||||||
Type: pluginType.String(),
|
Type: pluginType.String(),
|
||||||
Version: version,
|
Version: version,
|
||||||
Builtin: true,
|
Builtin: true,
|
||||||
SemanticVersion: semanticVersion,
|
SemanticVersion: semanticVersion,
|
||||||
|
DeprecationStatus: deprecationStatus.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -16,13 +22,26 @@ Display information about a plugin
|
||||||
```shell-session
|
```shell-session
|
||||||
$ vault plugin info auth my-custom-plugin
|
$ vault plugin info auth my-custom-plugin
|
||||||
|
|
||||||
Key Value
|
Key Value
|
||||||
--- -----
|
--- -----
|
||||||
args []
|
args []
|
||||||
builtin false
|
builtin false
|
||||||
command my-custom-plugin
|
command my-custom-plugin
|
||||||
name my-custom-plugin
|
deprecation_status n/a
|
||||||
sha256 d3f0a8be02f6c074cf38c9c99d4d04c9c6466249
|
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
|
## Usage
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue