Update mount table and CLI with plugin version for auth (#16856)
This commit is contained in:
parent
96b97017b1
commit
09ad6ab72c
|
@ -247,6 +247,7 @@ type MountInput struct {
|
|||
SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
|
||||
ExternalEntropyAccess bool `json:"external_entropy_access" mapstructure:"external_entropy_access"`
|
||||
Options map[string]string `json:"options"`
|
||||
Version string `json:"version,omitempty"`
|
||||
|
||||
// Deprecated: Newer server responses should be returning this information in the
|
||||
// Type field (json: "type") instead.
|
||||
|
@ -281,6 +282,10 @@ type MountOutput struct {
|
|||
Local bool `json:"local"`
|
||||
SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
|
||||
ExternalEntropyAccess bool `json:"external_entropy_access" mapstructure:"external_entropy_access"`
|
||||
Version string `json:"version"`
|
||||
RunningVersion string `json:"running_version"`
|
||||
Sha string `json:"sha"`
|
||||
RunningSha string `json:"running_sha"`
|
||||
}
|
||||
|
||||
type MountConfigOutput struct {
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListMounts(t *testing.T) {
|
||||
mockVaultServer := httptest.NewServer(http.HandlerFunc(mockVaultMountsHandler))
|
||||
defer mockVaultServer.Close()
|
||||
|
||||
cfg := DefaultConfig()
|
||||
cfg.Address = mockVaultServer.URL
|
||||
client, err := NewClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err := client.Sys().ListMounts()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedMounts := map[string]struct {
|
||||
Type string
|
||||
Version string
|
||||
}{
|
||||
"cubbyhole/": {Type: "cubbyhole", Version: "v1.0.0"},
|
||||
"identity/": {Type: "identity", Version: ""},
|
||||
"secret/": {Type: "kv", Version: ""},
|
||||
"sys/": {Type: "system", Version: ""},
|
||||
}
|
||||
|
||||
for path, mount := range resp {
|
||||
expected, ok := expectedMounts[path]
|
||||
if !ok {
|
||||
t.Errorf("Unexpected mount: %s: %+v", path, mount)
|
||||
continue
|
||||
}
|
||||
if expected.Type != mount.Type || expected.Version != mount.Version {
|
||||
t.Errorf("Mount did not match: %s -> expected %+v but got %+v", path, expected, mount)
|
||||
}
|
||||
}
|
||||
|
||||
for path, expected := range expectedMounts {
|
||||
mount, ok := resp[path]
|
||||
if !ok {
|
||||
t.Errorf("Expected mount not found mount: %s: %+v", path, expected)
|
||||
continue
|
||||
}
|
||||
if expected.Type != mount.Type || expected.Version != mount.Version {
|
||||
t.Errorf("Mount did not match: %s -> expected %+v but got %+v", path, expected, mount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mockVaultMountsHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte(listMountsResponse))
|
||||
}
|
||||
|
||||
const listMountsResponse = `{
|
||||
"request_id": "3cd881e9-ea50-2e06-90b2-5641667485fa",
|
||||
"lease_id": "",
|
||||
"lease_duration": 0,
|
||||
"renewable": false,
|
||||
"data": {
|
||||
"cubbyhole/": {
|
||||
"accessor": "cubbyhole_2e3fc28d",
|
||||
"config": {
|
||||
"default_lease_ttl": 0,
|
||||
"force_no_cache": false,
|
||||
"max_lease_ttl": 0
|
||||
},
|
||||
"description": "per-token private secret storage",
|
||||
"external_entropy_access": false,
|
||||
"local": true,
|
||||
"options": null,
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"seal_wrap": false,
|
||||
"sha": "",
|
||||
"type": "cubbyhole",
|
||||
"uuid": "575063dc-5ef8-4487-c842-22c494c19a6f",
|
||||
"version": "v1.0.0"
|
||||
},
|
||||
"identity/": {
|
||||
"accessor": "identity_6e01c327",
|
||||
"config": {
|
||||
"default_lease_ttl": 0,
|
||||
"force_no_cache": false,
|
||||
"max_lease_ttl": 0,
|
||||
"passthrough_request_headers": [
|
||||
"Authorization"
|
||||
]
|
||||
},
|
||||
"description": "identity store",
|
||||
"external_entropy_access": false,
|
||||
"local": false,
|
||||
"options": null,
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"seal_wrap": false,
|
||||
"sha": "",
|
||||
"type": "identity",
|
||||
"uuid": "187d7eba-3471-554b-c2d9-1479612c8046",
|
||||
"version": ""
|
||||
},
|
||||
"secret/": {
|
||||
"accessor": "kv_3e2f282f",
|
||||
"config": {
|
||||
"default_lease_ttl": 0,
|
||||
"force_no_cache": false,
|
||||
"max_lease_ttl": 0
|
||||
},
|
||||
"description": "key/value secret storage",
|
||||
"external_entropy_access": false,
|
||||
"local": false,
|
||||
"options": {
|
||||
"version": "2"
|
||||
},
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"seal_wrap": false,
|
||||
"sha": "",
|
||||
"type": "kv",
|
||||
"uuid": "13375e0f-876e-7e96-0a3e-076f37b6b69d",
|
||||
"version": ""
|
||||
},
|
||||
"sys/": {
|
||||
"accessor": "system_93503264",
|
||||
"config": {
|
||||
"default_lease_ttl": 0,
|
||||
"force_no_cache": false,
|
||||
"max_lease_ttl": 0,
|
||||
"passthrough_request_headers": [
|
||||
"Accept"
|
||||
]
|
||||
},
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
"external_entropy_access": false,
|
||||
"local": false,
|
||||
"options": null,
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"seal_wrap": true,
|
||||
"sha": "",
|
||||
"type": "system",
|
||||
"uuid": "1373242d-cc4d-c023-410b-7f336e7ba0a8",
|
||||
"version": ""
|
||||
}
|
||||
}
|
||||
}`
|
|
@ -22,6 +22,8 @@ type ListPluginsResponse struct {
|
|||
// PluginsByType is the list of plugins by type.
|
||||
PluginsByType map[consts.PluginType][]string `json:"types"`
|
||||
|
||||
Details []PluginDetails `json:"details,omitempty"`
|
||||
|
||||
// Names is the list of names of the plugins.
|
||||
//
|
||||
// Deprecated: Newer server responses should be returning PluginsByType (json:
|
||||
|
@ -29,6 +31,13 @@ type ListPluginsResponse struct {
|
|||
Names []string `json:"names"`
|
||||
}
|
||||
|
||||
type PluginDetails struct {
|
||||
Type string `json:"string"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Builtin bool `json:"builtin"`
|
||||
}
|
||||
|
||||
// ListPlugins wraps ListPluginsWithContext using context.Background.
|
||||
func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) {
|
||||
return c.ListPluginsWithContext(context.Background(), i)
|
||||
|
@ -98,6 +107,7 @@ func (c *Sys) ListPluginsWithContext(ctx context.Context, i *ListPluginsInput) (
|
|||
|
||||
result := &ListPluginsResponse{
|
||||
PluginsByType: make(map[consts.PluginType][]string),
|
||||
Details: []PluginDetails{},
|
||||
}
|
||||
if i.Type == consts.PluginTypeUnknown {
|
||||
for _, pluginType := range consts.PluginTypes {
|
||||
|
@ -129,6 +139,12 @@ func (c *Sys) ListPluginsWithContext(ctx context.Context, i *ListPluginsInput) (
|
|||
result.PluginsByType[i.Type] = respKeys
|
||||
}
|
||||
|
||||
if detailed, ok := secret.Data["detailed"]; ok {
|
||||
if err := mapstructure.Decode(detailed, &result.Details); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
@ -194,6 +210,9 @@ type RegisterPluginInput struct {
|
|||
|
||||
// SHA256 is the shasum of the plugin.
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
|
||||
// Version is the optional version of the plugin being registered
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterPlugin wraps RegisterPluginWithContext using context.Background.
|
||||
|
@ -227,6 +246,9 @@ type DeregisterPluginInput struct {
|
|||
|
||||
// Type of the plugin. Required.
|
||||
Type consts.PluginType `json:"type"`
|
||||
|
||||
// Version of the plugin. Optional.
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// DeregisterPlugin wraps DeregisterPluginWithContext using context.Background.
|
||||
|
@ -242,7 +264,7 @@ func (c *Sys) DeregisterPluginWithContext(ctx context.Context, i *DeregisterPlug
|
|||
|
||||
path := catalogPathByType(i.Type, i.Name)
|
||||
req := c.c.NewRequest(http.MethodDelete, path)
|
||||
|
||||
req.Params.Set("version", i.Version)
|
||||
resp, err := c.c.rawRequestWithContext(ctx, req)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
|
|
|
@ -9,8 +9,27 @@ import (
|
|||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
)
|
||||
|
||||
func TestRegisterPlugin(t *testing.T) {
|
||||
mockVaultServer := httptest.NewServer(http.HandlerFunc(mockVaultHandlerRegister))
|
||||
defer mockVaultServer.Close()
|
||||
|
||||
cfg := DefaultConfig()
|
||||
cfg.Address = mockVaultServer.URL
|
||||
client, err := NewClient(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = client.Sys().RegisterPluginWithContext(context.Background(), &RegisterPluginInput{
|
||||
Version: "v1.0.0",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPlugins(t *testing.T) {
|
||||
mockVaultServer := httptest.NewServer(http.HandlerFunc(mockVaultHandler))
|
||||
mockVaultServer := httptest.NewServer(http.HandlerFunc(mockVaultHandlerList))
|
||||
defer mockVaultServer.Close()
|
||||
|
||||
cfg := DefaultConfig()
|
||||
|
@ -44,7 +63,7 @@ func TestListPlugins(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func mockVaultHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
func mockVaultHandlerList(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte(listUntypedResponse))
|
||||
}
|
||||
|
||||
|
@ -77,3 +96,9 @@ const listUntypedResponse = `{
|
|||
"warnings": null,
|
||||
"auth": null
|
||||
}`
|
||||
|
||||
func mockVaultHandlerRegister(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte(registerResponse))
|
||||
}
|
||||
|
||||
const registerResponse = `{}`
|
||||
|
|
|
@ -62,11 +62,12 @@ func Backend(ctx context.Context, conf *logical.BackendConfig) (*PluginBackend,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
version := conf.Config["plugin_version"]
|
||||
|
||||
sys := conf.System
|
||||
|
||||
// NewBackend with isMetadataMode set to true
|
||||
raw, err := bplugin.NewBackend(ctx, name, pluginType, sys, conf, true)
|
||||
// NewBackendWithVersion with isMetadataMode set to true
|
||||
raw, err := bplugin.NewBackendWithVersion(ctx, name, pluginType, sys, conf, true, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -119,7 +120,7 @@ func (b *PluginBackend) startBackend(ctx context.Context, storage logical.Storag
|
|||
// Ensure proper cleanup of the backend (i.e. call client.Kill())
|
||||
b.Backend.Cleanup(ctx)
|
||||
|
||||
nb, err := bplugin.NewBackend(ctx, pluginName, pluginType, b.config.System, b.config, false)
|
||||
nb, err := bplugin.NewBackendWithVersion(ctx, pluginName, pluginType, b.config.System, b.config, false, b.config.Config["plugin_version"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -183,3 +183,13 @@ func (v testSystemView) LookupPlugin(context.Context, string, consts.PluginType)
|
|||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v testSystemView) LookupPluginVersion(context.Context, string, consts.PluginType, string) (*pluginutil.PluginRunner, error) {
|
||||
return &pluginutil.PluginRunner{
|
||||
Name: "test-plugin-runner",
|
||||
Builtin: true,
|
||||
BuiltinFactory: func() (interface{}, error) {
|
||||
return v.factory, nil
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:change
|
||||
plugins: Add plugin version to auth register, list, and mount table
|
||||
```
|
|
@ -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,
|
||||
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"
|
||||
}
|
||||
|
|
|
@ -413,6 +413,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -427,6 +431,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -440,6 +448,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -454,6 +466,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
|
@ -468,6 +484,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -482,6 +502,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -495,6 +519,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -509,6 +537,10 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
|
|
@ -41,6 +41,10 @@ func TestSysAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"token/": map[string]interface{}{
|
||||
|
@ -56,6 +60,10 @@ func TestSysAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -117,6 +125,10 @@ func TestSysEnableAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"token/": map[string]interface{}{
|
||||
"description": "token based credentials",
|
||||
|
@ -131,6 +143,10 @@ func TestSysEnableAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"foo/": map[string]interface{}{
|
||||
|
@ -146,6 +162,10 @@ func TestSysEnableAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"token/": map[string]interface{}{
|
||||
"description": "token based credentials",
|
||||
|
@ -160,6 +180,10 @@ func TestSysEnableAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -224,6 +248,10 @@ func TestSysDisableAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"token/": map[string]interface{}{
|
||||
|
@ -239,6 +267,10 @@ func TestSysDisableAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -495,6 +527,10 @@ func TestSysRemountAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"token/": map[string]interface{}{
|
||||
"description": "token based credentials",
|
||||
|
@ -509,6 +545,10 @@ func TestSysRemountAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"bar/": map[string]interface{}{
|
||||
|
@ -524,6 +564,10 @@ func TestSysRemountAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"token/": map[string]interface{}{
|
||||
"description": "token based credentials",
|
||||
|
@ -538,6 +582,10 @@ func TestSysRemountAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
|
|
@ -42,6 +42,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -56,6 +60,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -69,6 +77,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -83,6 +95,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
|
@ -97,6 +113,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -111,6 +131,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -124,6 +148,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -138,6 +166,10 @@ func TestSysMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -199,6 +231,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -212,6 +248,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -226,6 +266,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -239,6 +283,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -253,6 +301,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"foo/": map[string]interface{}{
|
||||
|
@ -267,6 +319,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -280,6 +336,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -294,6 +354,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -307,6 +371,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -321,6 +389,10 @@ func TestSysMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -417,6 +489,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -430,6 +506,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -444,6 +524,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -457,6 +541,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -471,6 +559,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"bar/": map[string]interface{}{
|
||||
|
@ -485,6 +577,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -498,6 +594,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -512,6 +612,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -525,6 +629,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -539,6 +647,10 @@ func TestSysRemount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -600,6 +712,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -614,6 +730,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -627,6 +747,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -641,6 +765,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
|
@ -655,6 +783,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -669,6 +801,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -682,6 +818,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -696,6 +836,10 @@ func TestSysUnmount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -843,6 +987,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -856,6 +1004,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -870,6 +1022,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -883,6 +1039,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -897,6 +1057,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"foo/": map[string]interface{}{
|
||||
|
@ -911,6 +1075,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -924,6 +1092,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -938,6 +1110,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -951,6 +1127,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -965,6 +1145,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
@ -1052,6 +1236,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -1065,6 +1253,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -1079,6 +1271,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -1092,6 +1288,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -1106,6 +1306,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
},
|
||||
"foo/": map[string]interface{}{
|
||||
|
@ -1120,6 +1324,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"secret/": map[string]interface{}{
|
||||
"description": "key/value secret storage",
|
||||
|
@ -1133,6 +1341,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]interface{}{"version": "1"},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"description": "system endpoints used for control, policy and debugging",
|
||||
|
@ -1147,6 +1359,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -1160,6 +1376,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -1174,6 +1394,10 @@ func TestSysTuneMount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": interface{}(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"running_version": "",
|
||||
"version": "",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
plugin "github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/sdk/helper/wrapping"
|
||||
|
@ -15,7 +15,8 @@ import (
|
|||
// Looker defines the plugin Lookup function that looks into the plugin catalog
|
||||
// for available plugins and returns a PluginRunner
|
||||
type Looker interface {
|
||||
LookupPlugin(context.Context, string, consts.PluginType) (*PluginRunner, error)
|
||||
LookupPlugin(ctx context.Context, pluginName string, pluginType consts.PluginType) (*PluginRunner, error)
|
||||
LookupPluginVersion(ctx context.Context, pluginName string, pluginType consts.PluginType, version string) (*PluginRunner, error)
|
||||
}
|
||||
|
||||
// RunnerUtil interface defines the functions needed by the runner to wrap the
|
||||
|
|
|
@ -54,7 +54,11 @@ type SystemView interface {
|
|||
|
||||
// LookupPlugin looks into the plugin catalog for a plugin with the given
|
||||
// name. Returns a PluginRunner or an error if a plugin can not be found.
|
||||
LookupPlugin(context.Context, string, consts.PluginType) (*pluginutil.PluginRunner, error)
|
||||
LookupPlugin(ctx context.Context, pluginName string, pluginType consts.PluginType) (*pluginutil.PluginRunner, error)
|
||||
|
||||
// LookupPluginVersion looks into the plugin catalog for a plugin with the given
|
||||
// name and version. Returns a PluginRunner or an error if a plugin can not be found.
|
||||
LookupPluginVersion(ctx context.Context, pluginName string, pluginType consts.PluginType, version string) (*pluginutil.PluginRunner, error)
|
||||
|
||||
// NewPluginClient returns a client for managing the lifecycle of plugin
|
||||
// processes
|
||||
|
@ -168,6 +172,10 @@ func (d StaticSystemView) LookupPlugin(_ context.Context, _ string, _ consts.Plu
|
|||
return nil, errors.New("LookupPlugin is not implemented in StaticSystemView")
|
||||
}
|
||||
|
||||
func (d StaticSystemView) LookupPluginVersion(_ context.Context, _ string, _ consts.PluginType, _ string) (*pluginutil.PluginRunner, error) {
|
||||
return nil, errors.New("LookupPluginVersion is not implemented in StaticSystemView")
|
||||
}
|
||||
|
||||
func (d StaticSystemView) MlockEnabled() bool {
|
||||
return d.EnableMlock
|
||||
}
|
||||
|
|
|
@ -107,6 +107,10 @@ func (s *gRPCSystemViewClient) LookupPlugin(_ context.Context, _ string, _ const
|
|||
return nil, fmt.Errorf("cannot call LookupPlugin from a plugin backend")
|
||||
}
|
||||
|
||||
func (s *gRPCSystemViewClient) LookupPluginVersion(_ context.Context, _ string, _ consts.PluginType, _ string) (*pluginutil.PluginRunner, error) {
|
||||
return nil, fmt.Errorf("cannot call LookupPluginVersion from a plugin backend")
|
||||
}
|
||||
|
||||
func (s *gRPCSystemViewClient) MlockEnabled() bool {
|
||||
reply, err := s.client.MlockEnabled(context.Background(), &pb.Empty{})
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
plugin "github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/sdk/helper/pluginutil"
|
||||
"github.com/hashicorp/vault/sdk/logical"
|
||||
|
@ -28,13 +28,13 @@ func (b *BackendPluginClient) Cleanup(ctx context.Context) {
|
|||
b.client.Kill()
|
||||
}
|
||||
|
||||
// NewBackend will return an instance of an RPC-based client implementation of the backend for
|
||||
// NewBackendWithVersion will return an instance of an RPC-based client implementation of the backend for
|
||||
// external plugins, or a concrete implementation of the backend if it is a builtin backend.
|
||||
// The backend is returned as a logical.Backend interface. The isMetadataMode param determines whether
|
||||
// the plugin should run in metadata mode.
|
||||
func NewBackend(ctx context.Context, pluginName string, pluginType consts.PluginType, sys pluginutil.LookRunnerUtil, conf *logical.BackendConfig, isMetadataMode bool) (logical.Backend, error) {
|
||||
func NewBackendWithVersion(ctx context.Context, pluginName string, pluginType consts.PluginType, sys pluginutil.LookRunnerUtil, conf *logical.BackendConfig, isMetadataMode bool, version string) (logical.Backend, error) {
|
||||
// Look for plugin in the plugin catalog
|
||||
pluginRunner, err := sys.LookupPlugin(ctx, pluginName, pluginType)
|
||||
pluginRunner, err := sys.LookupPluginVersion(ctx, pluginName, pluginType, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -66,6 +66,14 @@ func NewBackend(ctx context.Context, pluginName string, pluginType consts.Plugin
|
|||
return backend, nil
|
||||
}
|
||||
|
||||
// NewBackend will return an instance of an RPC-based client implementation of the backend for
|
||||
// external plugins, or a concrete implementation of the backend if it is a builtin backend.
|
||||
// The backend is returned as a logical.Backend interface. The isMetadataMode param determines whether
|
||||
// the plugin should run in metadata mode.
|
||||
func NewBackend(ctx context.Context, pluginName string, pluginType consts.PluginType, sys pluginutil.LookRunnerUtil, conf *logical.BackendConfig, isMetadataMode bool) (logical.Backend, error) {
|
||||
return NewBackendWithVersion(ctx, pluginName, pluginType, sys, conf, isMetadataMode, "")
|
||||
}
|
||||
|
||||
func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger, isMetadataMode bool) (logical.Backend, error) {
|
||||
// pluginMap is the map of plugins we can dispense.
|
||||
pluginSet := map[int]plugin.PluginSet{
|
||||
|
|
|
@ -911,7 +911,7 @@ func (c *Core) newCredentialBackend(ctx context.Context, entry *MountEntry, sysV
|
|||
|
||||
f, ok := c.credentialBackends[t]
|
||||
if !ok {
|
||||
plug, err := c.pluginCatalog.Get(ctx, t, consts.PluginTypeCredential, "")
|
||||
plug, err := c.pluginCatalog.Get(ctx, t, consts.PluginTypeCredential, entry.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -938,6 +938,7 @@ func (c *Core) newCredentialBackend(ctx context.Context, entry *MountEntry, sysV
|
|||
}
|
||||
|
||||
conf["plugin_type"] = consts.PluginTypeCredential.String()
|
||||
conf["plugin_version"] = entry.Version
|
||||
|
||||
authLogger := c.baseLogger.Named(fmt.Sprintf("auth.%s.%s", t, entry.Accessor))
|
||||
c.AddLogger(authLogger)
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
package vault
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/sdk/framework"
|
||||
)
|
||||
|
||||
var (
|
||||
compileOnce sync.Once
|
||||
pluginBytes []byte
|
||||
)
|
||||
|
||||
func testCoreWithPlugin(t *testing.T) (*Core, string, string) {
|
||||
t.Helper()
|
||||
pluginName, pluginSha256, pluginDir := compilePlugin(t)
|
||||
conf := &CoreConfig{
|
||||
BuiltinRegistry: NewMockBuiltinRegistry(),
|
||||
PluginDirectory: pluginDir,
|
||||
}
|
||||
core := TestCoreWithSealAndUI(t, conf)
|
||||
core, _, _ = testCoreUnsealed(t, core)
|
||||
return core, pluginName, pluginSha256
|
||||
}
|
||||
|
||||
// to mount a plugin, we need a working binary plugin, so we compile one here.
|
||||
func compilePlugin(t *testing.T) (string, string, string) {
|
||||
pluginType := "approle"
|
||||
pluginName := "vault-plugin-auth-" + pluginType
|
||||
|
||||
dir := ""
|
||||
// detect if we are in the "vault/" or the root directory and compensate
|
||||
if _, err := os.Stat("builtin"); os.IsNotExist(err) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dir = filepath.Dir(wd)
|
||||
}
|
||||
|
||||
pluginDir, cleanup := MakeTestPluginDir(t)
|
||||
t.Cleanup(func() { cleanup(t) })
|
||||
|
||||
pluginPath := path.Join(pluginDir, pluginName)
|
||||
|
||||
// cache the compilation to only run once
|
||||
compileOnce.Do(func() {
|
||||
cmd := exec.Command("go", "build", "-o", pluginPath, fmt.Sprintf("builtin/credential/%s/cmd/%s/main.go", pluginType, pluginType))
|
||||
cmd.Dir = dir
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error running go build %v output: %s", err, output))
|
||||
}
|
||||
pluginBytes, err = os.ReadFile(pluginPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
// write the cached plugin if necessary
|
||||
var err error
|
||||
if _, err := os.Stat(pluginPath); os.IsNotExist(err) {
|
||||
err = os.WriteFile(pluginPath, pluginBytes, 0o777)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sha := sha256.New()
|
||||
_, err = sha.Write(pluginBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return pluginName, fmt.Sprintf("%x", sha.Sum(nil)), pluginDir
|
||||
}
|
||||
|
||||
func TestCore_EnableExternalCredentialPlugin(t *testing.T) {
|
||||
c, pluginName, pluginSha256 := testCoreWithPlugin(t)
|
||||
d := &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"version": "v1.0.0",
|
||||
"command": pluginName,
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
resp, err := c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Error() != nil {
|
||||
t.Fatalf("%#v", resp)
|
||||
}
|
||||
me := &MountEntry{
|
||||
Table: credentialTableType,
|
||||
Path: "foo",
|
||||
Type: pluginName,
|
||||
Version: "v1.0.0",
|
||||
}
|
||||
err = c.enableCredential(namespace.RootContext(nil), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
match := c.router.MatchingMount(namespace.RootContext(nil), "auth/foo/bar")
|
||||
if match != "auth/foo/" {
|
||||
t.Fatalf("missing mount, match: %q", match)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCore_EnableExternalCredentialPlugin_MultipleVersions(t *testing.T) {
|
||||
c, pluginName, pluginSha256 := testCoreWithPlugin(t)
|
||||
d := &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"version": "v1.0.0",
|
||||
"command": pluginName,
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
resp, err := c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Error() != nil {
|
||||
t.Fatalf("%#v", resp)
|
||||
}
|
||||
|
||||
d = &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"version": "v1.0.1",
|
||||
"command": pluginName,
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
resp, err = c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Error() != nil {
|
||||
t.Fatalf("%#v", resp)
|
||||
}
|
||||
|
||||
me := &MountEntry{
|
||||
Table: credentialTableType,
|
||||
Path: "foo",
|
||||
Type: pluginName,
|
||||
Version: "v1.0.0",
|
||||
}
|
||||
err = c.enableCredential(namespace.RootContext(nil), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
match := c.router.MatchingMount(namespace.RootContext(nil), "auth/foo/bar")
|
||||
if match != "auth/foo/" {
|
||||
t.Fatalf("missing mount, match: %q", match)
|
||||
}
|
||||
|
||||
raw, _ := c.router.root.Get(match)
|
||||
if raw.(*routeEntry).mountEntry.Version != "v1.0.0" {
|
||||
t.Errorf("Expected mount to be version v1.0.0 but got %s", raw.(*routeEntry).mountEntry.Version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCore_EnableExternalCredentialPlugin_MultipleVersions_MountSecond(t *testing.T) {
|
||||
c, pluginName, pluginSha256 := testCoreWithPlugin(t)
|
||||
d := &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"command": pluginName,
|
||||
"version": "v1.0.0",
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
resp, err := c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Error() != nil {
|
||||
t.Fatalf("%#v", resp)
|
||||
}
|
||||
|
||||
d = &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"version": "v1.0.1",
|
||||
"command": pluginName,
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
resp, err = c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Error() != nil {
|
||||
t.Fatalf("%#v", resp)
|
||||
}
|
||||
|
||||
me := &MountEntry{
|
||||
Table: credentialTableType,
|
||||
Path: "foo",
|
||||
Type: pluginName,
|
||||
Version: "v1.0.1",
|
||||
}
|
||||
err = c.enableCredential(namespace.RootContext(nil), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
match := c.router.MatchingMount(namespace.RootContext(nil), "auth/foo/bar")
|
||||
if match != "auth/foo/" {
|
||||
t.Fatalf("missing mount, match: %q", match)
|
||||
}
|
||||
|
||||
raw, _ := c.router.root.Get(match)
|
||||
if raw.(*routeEntry).mountEntry.Version != "v1.0.1" {
|
||||
t.Errorf("Expected mount to be version v1.0.1 but got %s", raw.(*routeEntry).mountEntry.Version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCore_EnableExternalCredentialPlugin_NoVersionsOkay(t *testing.T) {
|
||||
c, pluginName, pluginSha256 := testCoreWithPlugin(t)
|
||||
d := &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"command": pluginName,
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
resp, err := c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Error() != nil {
|
||||
t.Fatalf("%#v", resp)
|
||||
}
|
||||
|
||||
me := &MountEntry{
|
||||
Table: credentialTableType,
|
||||
Path: "foo",
|
||||
Type: pluginName,
|
||||
}
|
||||
err = c.enableCredential(namespace.RootContext(nil), me)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
match := c.router.MatchingMount(namespace.RootContext(nil), "auth/foo/bar")
|
||||
if match != "auth/foo/" {
|
||||
t.Fatalf("missing mount, match: %q", match)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCore_EnableExternalCredentialPlugin_NoVersionOnRegister(t *testing.T) {
|
||||
c, pluginName, pluginSha256 := testCoreWithPlugin(t)
|
||||
d := &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"command": pluginName,
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
resp, err := c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Error() != nil {
|
||||
t.Fatalf("%#v", resp)
|
||||
}
|
||||
|
||||
me := &MountEntry{
|
||||
Table: credentialTableType,
|
||||
Path: "foo",
|
||||
Type: pluginName,
|
||||
Version: "v1.0.0",
|
||||
}
|
||||
err = c.enableCredential(namespace.RootContext(nil), me)
|
||||
if err == nil || !errors.Is(err, ErrPluginNotFound) {
|
||||
t.Fatalf("Expected to get plugin not found but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCore_EnableExternalCredentialPlugin_InvalidName(t *testing.T) {
|
||||
c, pluginName, pluginSha256 := testCoreWithPlugin(t)
|
||||
d := &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": pluginName,
|
||||
"sha256": pluginSha256,
|
||||
"version": "v1.0.0",
|
||||
"command": pluginName + "xyz",
|
||||
},
|
||||
Schema: c.systemBackend.pluginsCatalogCRUDPath().Fields,
|
||||
}
|
||||
_, err := c.systemBackend.handlePluginCatalogUpdate(context.Background(), nil, d)
|
||||
if err == nil || !strings.Contains(err.Error(), "no such file or directory") {
|
||||
t.Fatalf("should have gotten a no such file or directory error inserting the plugin: %v", err)
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
metrics "github.com/armon/go-metrics"
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/vault/helper/metricsutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/sdk/helper/jsonutil"
|
||||
|
|
|
@ -234,13 +234,19 @@ func (d dynamicSystemView) NewPluginClient(ctx context.Context, config pluginuti
|
|||
// LookupPlugin looks for a plugin with the given name in the plugin catalog. It
|
||||
// returns a PluginRunner or an error if no plugin was found.
|
||||
func (d dynamicSystemView) LookupPlugin(ctx context.Context, name string, pluginType consts.PluginType) (*pluginutil.PluginRunner, error) {
|
||||
return d.LookupPluginVersion(ctx, name, pluginType, "")
|
||||
}
|
||||
|
||||
// LookupPluginVersion looks for a plugin with the given name and version in the plugin catalog. It
|
||||
// returns a PluginRunner or an error if no plugin was found.
|
||||
func (d dynamicSystemView) LookupPluginVersion(ctx context.Context, name string, pluginType consts.PluginType, version string) (*pluginutil.PluginRunner, error) {
|
||||
if d.core == nil {
|
||||
return nil, fmt.Errorf("system view core is nil")
|
||||
}
|
||||
if d.core.pluginCatalog == nil {
|
||||
return nil, fmt.Errorf("system view core plugin catalog is nil")
|
||||
}
|
||||
r, err := d.core.pluginCatalog.Get(ctx, name, pluginType, "")
|
||||
r, err := d.core.pluginCatalog.Get(ctx, name, pluginType, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -620,7 +620,8 @@ func getVersion(d *framework.FieldData) (string, error) {
|
|||
}
|
||||
|
||||
// Canonicalize the version string.
|
||||
version = semanticVersion.String()
|
||||
// Add the 'v' back in, since semantic version strips it out, and we want to be consistent with internal plugins.
|
||||
version = "v" + semanticVersion.String()
|
||||
}
|
||||
|
||||
return version, nil
|
||||
|
@ -888,6 +889,10 @@ func mountInfo(entry *MountEntry) map[string]interface{} {
|
|||
"external_entropy_access": entry.ExternalEntropyAccess,
|
||||
"options": entry.Options,
|
||||
"uuid": entry.UUID,
|
||||
"version": entry.Version,
|
||||
"sha": entry.Sha,
|
||||
"running_version": entry.RunningVersion,
|
||||
"running_sha": entry.RunningSha,
|
||||
}
|
||||
entryConfig := map[string]interface{}{
|
||||
"default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()),
|
||||
|
@ -981,6 +986,14 @@ func (b *SystemBackend) handleMount(ctx context.Context, req *logical.Request, d
|
|||
sealWrap := data.Get("seal_wrap").(bool)
|
||||
externalEntropyAccess := data.Get("external_entropy_access").(bool)
|
||||
options := data.Get("options").(map[string]string)
|
||||
version := data.Get("version").(string)
|
||||
if version != "" {
|
||||
v, err := semver.NewSemver(version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
version = "v" + v.String()
|
||||
}
|
||||
|
||||
var config MountConfig
|
||||
var apiConfig APIMountConfig
|
||||
|
@ -1123,6 +1136,7 @@ func (b *SystemBackend) handleMount(ctx context.Context, req *logical.Request, d
|
|||
SealWrap: sealWrap,
|
||||
ExternalEntropyAccess: externalEntropyAccess,
|
||||
Options: options,
|
||||
Version: version,
|
||||
}
|
||||
|
||||
// Attempt mount
|
||||
|
@ -2223,6 +2237,14 @@ func (b *SystemBackend) handleEnableAuth(ctx context.Context, req *logical.Reque
|
|||
sealWrap := data.Get("seal_wrap").(bool)
|
||||
externalEntropyAccess := data.Get("external_entropy_access").(bool)
|
||||
options := data.Get("options").(map[string]string)
|
||||
version := data.Get("version").(string)
|
||||
if version != "" {
|
||||
v, err := semver.NewSemver(version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
version = "v" + v.String()
|
||||
}
|
||||
|
||||
var config MountConfig
|
||||
var apiConfig APIMountConfig
|
||||
|
@ -2354,6 +2376,7 @@ func (b *SystemBackend) handleEnableAuth(ctx context.Context, req *logical.Reque
|
|||
SealWrap: sealWrap,
|
||||
ExternalEntropyAccess: externalEntropyAccess,
|
||||
Options: options,
|
||||
Version: version,
|
||||
}
|
||||
|
||||
// Attempt enabling
|
||||
|
|
|
@ -1600,6 +1600,10 @@ func (b *SystemBackend) authPaths() []*framework.Path {
|
|||
Type: framework.TypeKVPairs,
|
||||
Description: strings.TrimSpace(sysHelp["auth_options"][0]),
|
||||
},
|
||||
"version": {
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["plugin-catalog_version"][0]),
|
||||
},
|
||||
},
|
||||
Operations: map[logical.Operation]framework.OperationHandler{
|
||||
logical.ReadOperation: &framework.PathOperation{
|
||||
|
@ -1971,6 +1975,10 @@ func (b *SystemBackend) mountPaths() []*framework.Path {
|
|||
Type: framework.TypeKVPairs,
|
||||
Description: strings.TrimSpace(sysHelp["mount_options"][0]),
|
||||
},
|
||||
"version": {
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["plugin-catalog_version"][0]),
|
||||
},
|
||||
},
|
||||
|
||||
Operations: map[logical.Operation]framework.OperationHandler{
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/go-test/deep"
|
||||
hclog "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
semver "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/vault/audit"
|
||||
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
|
||||
|
@ -172,6 +172,10 @@ func TestSystemBackend_mounts(t *testing.T) {
|
|||
"options": map[string]string{
|
||||
"version": "1",
|
||||
},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"type": "system",
|
||||
|
@ -188,6 +192,10 @@ func TestSystemBackend_mounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -203,6 +211,10 @@ func TestSystemBackend_mounts(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -219,6 +231,10 @@ func TestSystemBackend_mounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
}
|
||||
if diff := deep.Equal(resp.Data, exp); len(diff) > 0 {
|
||||
|
@ -285,6 +301,10 @@ func TestSystemBackend_mount(t *testing.T) {
|
|||
"options": map[string]string{
|
||||
"version": "1",
|
||||
},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"type": "system",
|
||||
|
@ -301,6 +321,10 @@ func TestSystemBackend_mount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -316,6 +340,10 @@ func TestSystemBackend_mount(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -332,6 +360,10 @@ func TestSystemBackend_mount(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"prod/secret/": map[string]interface{}{
|
||||
"description": "",
|
||||
|
@ -349,6 +381,10 @@ func TestSystemBackend_mount(t *testing.T) {
|
|||
"options": map[string]string{
|
||||
"version": "1",
|
||||
},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
}
|
||||
if diff := deep.Equal(resp.Data, exp); len(diff) > 0 {
|
||||
|
@ -1821,6 +1857,10 @@ func TestSystemBackend_authTable(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
}
|
||||
if diff := deep.Equal(resp.Data, exp); diff != nil {
|
||||
|
@ -1885,6 +1925,10 @@ func TestSystemBackend_enableAuth(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": true,
|
||||
"options": map[string]string{},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"token/": map[string]interface{}{
|
||||
"type": "token",
|
||||
|
@ -1901,6 +1945,10 @@ func TestSystemBackend_enableAuth(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
}
|
||||
if diff := deep.Equal(resp.Data, exp); diff != nil {
|
||||
|
@ -2893,21 +2941,25 @@ func TestSystemBackend_rotate(t *testing.T) {
|
|||
}
|
||||
|
||||
func testSystemBackend(t *testing.T) logical.Backend {
|
||||
t.Helper()
|
||||
c, _, _ := TestCoreUnsealed(t)
|
||||
return c.systemBackend
|
||||
}
|
||||
|
||||
func testSystemBackendRaw(t *testing.T) logical.Backend {
|
||||
t.Helper()
|
||||
c, _, _ := TestCoreUnsealedRaw(t)
|
||||
return c.systemBackend
|
||||
}
|
||||
|
||||
func testCoreSystemBackend(t *testing.T) (*Core, logical.Backend, string) {
|
||||
t.Helper()
|
||||
c, _, root := TestCoreUnsealed(t)
|
||||
return c, c.systemBackend, root
|
||||
}
|
||||
|
||||
func testCoreSystemBackendRaw(t *testing.T) (*Core, logical.Backend, string) {
|
||||
t.Helper()
|
||||
c, _, root := TestCoreUnsealedRaw(t)
|
||||
return c, c.systemBackend, root
|
||||
}
|
||||
|
@ -3033,7 +3085,7 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
|
|||
"args": []string{"--test"},
|
||||
"sha256": "31",
|
||||
"builtin": false,
|
||||
"version": "0.1.0",
|
||||
"version": "v0.1.0",
|
||||
}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("expected did not match actual, got %#v\n expected %#v\n", actual, expected)
|
||||
|
@ -3270,6 +3322,10 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
|||
"options": map[string]string{
|
||||
"version": "1",
|
||||
},
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"sys/": map[string]interface{}{
|
||||
"type": "system",
|
||||
|
@ -3286,6 +3342,10 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": true,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"cubbyhole/": map[string]interface{}{
|
||||
"description": "per-token private secret storage",
|
||||
|
@ -3301,6 +3361,10 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
|||
"local": true,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
"identity/": map[string]interface{}{
|
||||
"description": "identity store",
|
||||
|
@ -3317,6 +3381,10 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
|||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"options": map[string]string(nil),
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
},
|
||||
"auth": map[string]interface{}{
|
||||
|
@ -3335,6 +3403,10 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
|
|||
"uuid": resp.Data["auth"].(map[string]interface{})["token/"].(map[string]interface{})["uuid"],
|
||||
"local": false,
|
||||
"seal_wrap": false,
|
||||
"sha": "",
|
||||
"running_sha": "",
|
||||
"version": "",
|
||||
"running_version": "",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
uuid "github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/builtin/plugin"
|
||||
"github.com/hashicorp/vault/helper/metricsutil"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
|
@ -328,6 +328,12 @@ type MountEntry struct {
|
|||
// without separately managing their locks individually. See SyncCache() for
|
||||
// the specific values that are being cached.
|
||||
synthesizedConfigCache sync.Map
|
||||
|
||||
// version info
|
||||
Version string `json:"version,omitempty"`
|
||||
Sha string `json:"sha,omitempty"`
|
||||
RunningVersion string `json:"running_version,omitempty"`
|
||||
RunningSha string `json:"running_sha,omitempty"`
|
||||
}
|
||||
|
||||
// MountConfig is used to hold settable options
|
||||
|
@ -1419,7 +1425,7 @@ func (c *Core) newLogicalBackend(ctx context.Context, entry *MountEntry, sysView
|
|||
|
||||
f, ok := c.logicalBackends[t]
|
||||
if !ok {
|
||||
plug, err := c.pluginCatalog.Get(ctx, t, consts.PluginTypeSecrets, "")
|
||||
plug, err := c.pluginCatalog.Get(ctx, t, consts.PluginTypeSecrets, entry.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -2424,3 +2424,37 @@ func CreateTestClusterWithRollbackPeriod(t testing.T, newPeriod time.Duration, b
|
|||
// Return the cluster.
|
||||
return cluster
|
||||
}
|
||||
|
||||
// MakeTestPluginDir creates a temporary directory suitable for holding plugins.
|
||||
// This helper also resolves symlinks to make tests happy on OS X.
|
||||
func MakeTestPluginDir(t testing.T) (string, func(t testing.T)) {
|
||||
if t != nil {
|
||||
t.Helper()
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
if t == nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// OSX tempdir are /var, but actually symlinked to /private/var
|
||||
dir, err = filepath.EvalSymlinks(dir)
|
||||
if err != nil {
|
||||
if t == nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return dir, func(t testing.T) {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
if t == nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue