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 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.
|
||||
|
|
|
@ -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{}{
|
||||
"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 != "" {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:"-"`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue