mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27:54 +00:00
Update mount table and CLI with plugin version for auth (#16856)
This commit is contained in:
committed by
GitHub
parent
5e44064931
commit
9d97decb26
@@ -37,6 +37,7 @@ type AuthEnableCommand struct {
|
||||
flagExternalEntropyAccess bool
|
||||
flagTokenType string
|
||||
flagVersion int
|
||||
flagPluginVersion string
|
||||
}
|
||||
|
||||
func (c *AuthEnableCommand) Synopsis() string {
|
||||
@@ -199,6 +200,13 @@ func (c *AuthEnableCommand) Flags() *FlagSets {
|
||||
Usage: "Select the version of the auth method to run. Not supported by all auth methods.",
|
||||
})
|
||||
|
||||
f.StringVar(&StringVar{
|
||||
Name: "plugin-version",
|
||||
Target: &c.flagPluginVersion,
|
||||
Default: "",
|
||||
Usage: "Select the version of the plugin to enable.",
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
@@ -262,6 +270,7 @@ func (c *AuthEnableCommand) Run(args []string) int {
|
||||
|
||||
authOpts := &api.EnableAuthOptions{
|
||||
Type: authType,
|
||||
Version: c.flagPluginVersion,
|
||||
Description: c.flagDescription,
|
||||
Local: c.flagLocal,
|
||||
SealWrap: c.flagSealWrap,
|
||||
|
||||
@@ -118,10 +118,10 @@ func (c *AuthListCommand) simpleMounts(auths map[string]*api.AuthMount) []string
|
||||
}
|
||||
sort.Strings(paths)
|
||||
|
||||
out := []string{"Path | Type | Accessor | Description"}
|
||||
out := []string{"Path | Type | Accessor | Description | Version"}
|
||||
for _, path := range paths {
|
||||
mount := auths[path]
|
||||
out = append(out, fmt.Sprintf("%s | %s | %s | %s", path, mount.Type, mount.Accessor, mount.Description))
|
||||
out = append(out, fmt.Sprintf("%s | %s | %s | %s | %s", path, mount.Type, mount.Accessor, mount.Description, mount.Version))
|
||||
}
|
||||
|
||||
return out
|
||||
@@ -145,7 +145,7 @@ func (c *AuthListCommand) detailedMounts(auths map[string]*api.AuthMount) []stri
|
||||
}
|
||||
}
|
||||
|
||||
out := []string{"Path | Plugin | Accessor | Default TTL | Max TTL | Token Type | Replication | Seal Wrap | External Entropy Access | Options | Description | UUID"}
|
||||
out := []string{"Path | Plugin | Accessor | Default TTL | Max TTL | Token Type | Replication | Seal Wrap | External Entropy Access | Options | Description | UUID | Version"}
|
||||
for _, path := range paths {
|
||||
mount := auths[path]
|
||||
|
||||
@@ -162,7 +162,7 @@ func (c *AuthListCommand) detailedMounts(auths map[string]*api.AuthMount) []stri
|
||||
pluginName = mount.Config.PluginName
|
||||
}
|
||||
|
||||
out = append(out, fmt.Sprintf("%s | %s | %s | %s | %s | %s | %s | %t | %v | %s | %s | %s",
|
||||
out = append(out, fmt.Sprintf("%s | %s | %s | %s | %s | %s | %s | %t | %v | %s | %s | %s | %s",
|
||||
path,
|
||||
pluginName,
|
||||
mount.Accessor,
|
||||
@@ -175,6 +175,7 @@ func (c *AuthListCommand) detailedMounts(auths map[string]*api.AuthMount) []stri
|
||||
mount.Options,
|
||||
mount.Description,
|
||||
mount.UUID,
|
||||
mount.Version,
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
semver "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/mitchellh/cli"
|
||||
@@ -17,6 +18,8 @@ var (
|
||||
|
||||
type PluginDeregisterCommand struct {
|
||||
*BaseCommand
|
||||
|
||||
flagVersion string
|
||||
}
|
||||
|
||||
func (c *PluginDeregisterCommand) Synopsis() string {
|
||||
@@ -28,20 +31,36 @@ func (c *PluginDeregisterCommand) Help() string {
|
||||
Usage: vault plugin deregister [options] TYPE NAME
|
||||
|
||||
Deregister an existing plugin in the catalog. If the plugin does not exist,
|
||||
no action is taken (the command is idempotent). The argument of type
|
||||
no action is taken (the command is idempotent). The TYPE argument
|
||||
takes "auth", "database", or "secret".
|
||||
|
||||
Deregister the plugin named my-custom-plugin:
|
||||
Deregister the unversioned auth plugin named my-custom-plugin:
|
||||
|
||||
$ vault plugin deregister auth my-custom-plugin
|
||||
|
||||
Deregister the auth plugin named my-custom-plugin, version 1.0.0:
|
||||
|
||||
$ vault plugin deregister -version=v1.0.0 auth my-custom-plugin
|
||||
|
||||
` + c.Flags().Help()
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PluginDeregisterCommand) Flags() *FlagSets {
|
||||
return c.flagSet(FlagSetHTTP)
|
||||
set := c.flagSet(FlagSetHTTP)
|
||||
|
||||
f := set.NewFlagSet("Command Options")
|
||||
|
||||
f.StringVar(&StringVar{
|
||||
Name: "version",
|
||||
Target: &c.flagVersion,
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: "Version of the plugin to deregister. If unset, " +
|
||||
"only an unversioned plugin may be deregistered.",
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *PluginDeregisterCommand) AutocompleteArgs() complete.Predictor {
|
||||
@@ -62,21 +81,19 @@ func (c *PluginDeregisterCommand) Run(args []string) int {
|
||||
|
||||
var pluginNameRaw, pluginTypeRaw string
|
||||
args = f.Args()
|
||||
switch {
|
||||
case len(args) < 1:
|
||||
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1 or 2, got %d)", len(args)))
|
||||
switch len(args) {
|
||||
case 0:
|
||||
c.UI.Error("Not enough arguments (expected 1, or 2, got 0)")
|
||||
return 1
|
||||
case len(args) > 2:
|
||||
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1 or 2, got %d)", len(args)))
|
||||
return 1
|
||||
|
||||
// These cases should come after invalid cases have been checked
|
||||
case len(args) == 1:
|
||||
case 1:
|
||||
pluginTypeRaw = "unknown"
|
||||
pluginNameRaw = args[0]
|
||||
case len(args) == 2:
|
||||
case 2:
|
||||
pluginTypeRaw = args[0]
|
||||
pluginNameRaw = args[1]
|
||||
default:
|
||||
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, or 2, got %d)", len(args)))
|
||||
return 1
|
||||
}
|
||||
|
||||
client, err := c.Client()
|
||||
@@ -91,10 +108,18 @@ func (c *PluginDeregisterCommand) Run(args []string) int {
|
||||
return 2
|
||||
}
|
||||
pluginName := strings.TrimSpace(pluginNameRaw)
|
||||
if c.flagVersion != "" {
|
||||
_, err := semver.NewSemver(c.flagVersion)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("version %q is not a valid semantic version: %v", c.flagVersion, err))
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
if err := client.Sys().DeregisterPlugin(&api.DeregisterPluginInput{
|
||||
Name: pluginName,
|
||||
Type: pluginType,
|
||||
Name: pluginName,
|
||||
Type: pluginType,
|
||||
Version: c.flagVersion,
|
||||
}); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error deregistering plugin named %s: %s", pluginName, err))
|
||||
return 2
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
@@ -76,7 +77,7 @@ func TestPluginDeregisterCommand_Run(t *testing.T) {
|
||||
t.Run("integration", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pluginDir, cleanup := testPluginDir(t)
|
||||
pluginDir, cleanup := vault.MakeTestPluginDir(t)
|
||||
defer cleanup(t)
|
||||
|
||||
client, _, closer := testVaultServerPluginDir(t, pluginDir)
|
||||
@@ -131,6 +132,101 @@ func TestPluginDeregisterCommand_Run(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("integration with version", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pluginDir, cleanup := vault.MakeTestPluginDir(t)
|
||||
defer cleanup(t)
|
||||
|
||||
client, _, closer := testVaultServerPluginDir(t, pluginDir)
|
||||
defer closer()
|
||||
|
||||
pluginName := "my-plugin"
|
||||
_, _, version := testPluginCreateAndRegisterVersioned(t, client, pluginDir, pluginName, consts.PluginTypeCredential)
|
||||
|
||||
ui, cmd := testPluginDeregisterCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
"-version=" + version,
|
||||
consts.PluginTypeCredential.String(),
|
||||
pluginName,
|
||||
})
|
||||
if exp := 0; code != exp {
|
||||
t.Errorf("expected %d to be %d", code, exp)
|
||||
}
|
||||
|
||||
expected := "Success! Deregistered plugin (if it was registered): "
|
||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||
if !strings.Contains(combined, expected) {
|
||||
t.Errorf("expected %q to contain %q", combined, expected)
|
||||
}
|
||||
|
||||
resp, err := client.Sys().ListPlugins(&api.ListPluginsInput{
|
||||
Type: consts.PluginTypeUnknown,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, p := range resp.Details {
|
||||
if p.Name == pluginName {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if found {
|
||||
t.Errorf("expected %q to not be in %#v", pluginName, resp.Details)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("integration with missing version", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pluginDir, cleanup := vault.MakeTestPluginDir(t)
|
||||
defer cleanup(t)
|
||||
|
||||
client, _, closer := testVaultServerPluginDir(t, pluginDir)
|
||||
defer closer()
|
||||
|
||||
pluginName := "my-plugin"
|
||||
testPluginCreateAndRegisterVersioned(t, client, pluginDir, pluginName, consts.PluginTypeCredential)
|
||||
|
||||
ui, cmd := testPluginDeregisterCommand(t)
|
||||
cmd.client = client
|
||||
|
||||
code := cmd.Run([]string{
|
||||
consts.PluginTypeCredential.String(),
|
||||
pluginName,
|
||||
})
|
||||
if exp := 0; code != exp {
|
||||
t.Errorf("expected %d to be %d", code, exp)
|
||||
}
|
||||
|
||||
expected := "Success! Deregistered plugin (if it was registered): "
|
||||
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
|
||||
if !strings.Contains(combined, expected) {
|
||||
t.Errorf("expected %q to contain %q", combined, expected)
|
||||
}
|
||||
|
||||
resp, err := client.Sys().ListPlugins(&api.ListPluginsInput{
|
||||
Type: consts.PluginTypeUnknown,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, p := range resp.Details {
|
||||
if p.Name == pluginName {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("expected %q to be in %#v", pluginName, resp.Details)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("communication_failure", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
@@ -73,7 +74,7 @@ func TestPluginInfoCommand_Run(t *testing.T) {
|
||||
t.Run("default", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pluginDir, cleanup := testPluginDir(t)
|
||||
pluginDir, cleanup := vault.MakeTestPluginDir(t)
|
||||
defer cleanup(t)
|
||||
|
||||
client, _, closer := testVaultServerPluginDir(t, pluginDir)
|
||||
@@ -104,7 +105,7 @@ func TestPluginInfoCommand_Run(t *testing.T) {
|
||||
t.Run("field", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pluginDir, cleanup := testPluginDir(t)
|
||||
pluginDir, cleanup := vault.MakeTestPluginDir(t)
|
||||
defer cleanup(t)
|
||||
|
||||
client, _, closer := testVaultServerPluginDir(t, pluginDir)
|
||||
|
||||
@@ -21,6 +21,7 @@ type PluginRegisterCommand struct {
|
||||
flagArgs []string
|
||||
flagCommand string
|
||||
flagSHA256 string
|
||||
flagVersion string
|
||||
}
|
||||
|
||||
func (c *PluginRegisterCommand) Synopsis() string {
|
||||
@@ -37,12 +38,13 @@ Usage: vault plugin register [options] TYPE NAME
|
||||
|
||||
Register the plugin named my-custom-plugin:
|
||||
|
||||
$ vault plugin register -sha256=d3f0a8b... auth my-custom-plugin
|
||||
$ vault plugin register -sha256=d3f0a8b... -version=v1.0.0 auth my-custom-plugin
|
||||
|
||||
Register a plugin with custom arguments:
|
||||
|
||||
$ vault plugin register \
|
||||
-sha256=d3f0a8b... \
|
||||
-version=v1.0.0 \
|
||||
-args=--with-glibc,--with-cgo \
|
||||
auth my-custom-plugin
|
||||
|
||||
@@ -79,6 +81,13 @@ func (c *PluginRegisterCommand) Flags() *FlagSets {
|
||||
Usage: "SHA256 of the plugin binary. This is required for all plugins.",
|
||||
})
|
||||
|
||||
f.StringVar(&StringVar{
|
||||
Name: "version",
|
||||
Target: &c.flagVersion,
|
||||
Completion: complete.PredictAnything,
|
||||
Usage: "Version of the plugin. Optional.",
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
@@ -144,6 +153,7 @@ func (c *PluginRegisterCommand) Run(args []string) int {
|
||||
Args: c.flagArgs,
|
||||
Command: command,
|
||||
SHA256: c.flagSHA256,
|
||||
Version: c.flagVersion,
|
||||
}); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error registering plugin %s: %s", pluginName, err))
|
||||
return 2
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
@@ -77,7 +78,7 @@ func TestPluginRegisterCommand_Run(t *testing.T) {
|
||||
t.Run("integration", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pluginDir, cleanup := testPluginDir(t)
|
||||
pluginDir, cleanup := vault.MakeTestPluginDir(t)
|
||||
defer cleanup(t)
|
||||
|
||||
client, _, closer := testVaultServerPluginDir(t, pluginDir)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
@@ -82,7 +83,7 @@ func TestPluginReloadCommand_Run(t *testing.T) {
|
||||
t.Run("integration", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pluginDir, cleanup := testPluginDir(t)
|
||||
pluginDir, cleanup := vault.MakeTestPluginDir(t)
|
||||
defer cleanup(t)
|
||||
|
||||
client, _, closer := testVaultServerPluginDir(t, pluginDir)
|
||||
|
||||
@@ -6,36 +6,12 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
)
|
||||
|
||||
// testPluginDir creates a temporary directory suitable for holding plugins.
|
||||
// This helper also resolves symlinks to make tests happy on OS X.
|
||||
func testPluginDir(tb testing.TB) (string, func(tb testing.TB)) {
|
||||
tb.Helper()
|
||||
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
|
||||
// OSX tempdir are /var, but actually symlinked to /private/var
|
||||
dir, err = filepath.EvalSymlinks(dir)
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
|
||||
return dir, func(tb testing.TB) {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testPluginCreate creates a sample plugin in a tempdir and returns the shasum
|
||||
// and filepath to the plugin.
|
||||
func testPluginCreate(tb testing.TB, dir, name string) (string, string) {
|
||||
@@ -78,3 +54,22 @@ func testPluginCreateAndRegister(tb testing.TB, client *api.Client, dir, name st
|
||||
|
||||
return pth, sha256Sum
|
||||
}
|
||||
|
||||
// testPluginCreateAndRegisterVersioned creates a versioned plugin and registers it in the catalog.
|
||||
func testPluginCreateAndRegisterVersioned(tb testing.TB, client *api.Client, dir, name string, pluginType consts.PluginType) (string, string, string) {
|
||||
tb.Helper()
|
||||
|
||||
pth, sha256Sum := testPluginCreate(tb, dir, name)
|
||||
|
||||
if err := client.Sys().RegisterPlugin(&api.RegisterPluginInput{
|
||||
Name: name,
|
||||
Type: pluginType,
|
||||
Command: name,
|
||||
SHA256: sha256Sum,
|
||||
Version: "v1.0.0",
|
||||
}); err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
|
||||
return pth, sha256Sum, "v1.0.0"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user