2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2018-01-18 21:49:20 +00:00
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2018-04-03 00:46:59 +00:00
|
|
|
log "github.com/hashicorp/go-hclog"
|
2018-01-18 21:49:20 +00:00
|
|
|
gplugin "github.com/hashicorp/go-plugin"
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
|
|
"github.com/hashicorp/vault/sdk/plugin/mock"
|
2018-01-18 21:49:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_impl(t *testing.T) {
|
2019-02-12 17:31:03 +00:00
|
|
|
var _ gplugin.Plugin = new(GRPCBackendPlugin)
|
|
|
|
var _ logical.Backend = new(backendGRPCPluginClient)
|
2018-01-18 21:49:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_HandleRequest(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
resp, err := b.HandleRequest(context.Background(), &logical.Request{
|
|
|
|
Operation: logical.CreateOperation,
|
|
|
|
Path: "kv/foo",
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"value": "bar",
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if resp.Data["value"] != "bar" {
|
|
|
|
t.Fatalf("bad: %#v", resp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_SpecialPaths(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
paths := b.SpecialPaths()
|
|
|
|
if paths == nil {
|
|
|
|
t.Fatal("SpecialPaths() returned nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_System(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
sys := b.System()
|
|
|
|
if sys == nil {
|
|
|
|
t.Fatal("System() returned nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
actual := sys.DefaultLeaseTTL()
|
|
|
|
expected := 300 * time.Second
|
|
|
|
|
|
|
|
if actual != expected {
|
|
|
|
t.Fatalf("bad: %v, expected %v", actual, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_Logger(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
logger := b.Logger()
|
|
|
|
if logger == nil {
|
|
|
|
t.Fatal("Logger() returned nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_HandleExistenceCheck(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
checkFound, exists, err := b.HandleExistenceCheck(context.Background(), &logical.Request{
|
|
|
|
Operation: logical.CreateOperation,
|
|
|
|
Path: "kv/foo",
|
|
|
|
Data: map[string]interface{}{"value": "bar"},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !checkFound {
|
|
|
|
t.Fatal("existence check not found for path 'kv/foo")
|
|
|
|
}
|
|
|
|
if exists {
|
|
|
|
t.Fatal("existence check should have returned 'false' for 'kv/foo'")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_Cleanup(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
b.Cleanup(context.Background())
|
2018-01-18 21:49:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_InvalidateKey(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
resp, err := b.HandleRequest(ctx, &logical.Request{
|
2018-01-18 21:49:20 +00:00
|
|
|
Operation: logical.ReadOperation,
|
|
|
|
Path: "internal",
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if resp.Data["value"] == "" {
|
|
|
|
t.Fatalf("bad: %#v, expected non-empty value", resp)
|
|
|
|
}
|
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
b.InvalidateKey(ctx, "internal")
|
2018-01-18 21:49:20 +00:00
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
resp, err = b.HandleRequest(ctx, &logical.Request{
|
2018-01-18 21:49:20 +00:00
|
|
|
Operation: logical.ReadOperation,
|
|
|
|
Path: "internal",
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if resp.Data["value"] != "" {
|
|
|
|
t.Fatalf("bad: expected empty response data, got %#v", resp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGRPCBackendPlugin_Setup(t *testing.T) {
|
|
|
|
_, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
}
|
|
|
|
|
2019-07-05 23:55:40 +00:00
|
|
|
func TestGRPCBackendPlugin_Initialize(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
err := b.Initialize(context.Background(), &logical.InitializationRequest{})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
func TestGRPCBackendPlugin_Version(t *testing.T) {
|
|
|
|
b, cleanup := testGRPCBackend(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
versioner, ok := b.(logical.PluginVersioner)
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("Expected %T to implement logical.PluginVersioner interface", b)
|
|
|
|
}
|
|
|
|
|
|
|
|
version := versioner.PluginVersion().Version
|
2022-09-23 10:19:38 +00:00
|
|
|
if version != "v0.0.0+mock" {
|
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
t.Fatalf("Got version %s, expected 'mock'", version)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-18 21:49:20 +00:00
|
|
|
func testGRPCBackend(t *testing.T) (logical.Backend, func()) {
|
|
|
|
// Create a mock provider
|
|
|
|
pluginMap := map[string]gplugin.Plugin{
|
2019-02-12 17:31:03 +00:00
|
|
|
"backend": &GRPCBackendPlugin{
|
|
|
|
Factory: mock.Factory,
|
|
|
|
Logger: log.New(&log.LoggerOptions{
|
|
|
|
Level: log.Debug,
|
|
|
|
Output: os.Stderr,
|
|
|
|
JSONFormat: true,
|
|
|
|
}),
|
2018-01-18 21:49:20 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
client, _ := gplugin.TestPluginGRPCConn(t, pluginMap)
|
|
|
|
cleanup := func() {
|
|
|
|
client.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Request the backend
|
|
|
|
raw, err := client.Dispense(BackendPluginName)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
b := raw.(logical.Backend)
|
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
err = b.Setup(context.Background(), &logical.BackendConfig{
|
2018-04-03 00:46:59 +00:00
|
|
|
Logger: logging.NewVaultLogger(log.Debug),
|
2018-01-18 21:49:20 +00:00
|
|
|
System: &logical.StaticSystemView{
|
|
|
|
DefaultLeaseTTLVal: 300 * time.Second,
|
|
|
|
MaxLeaseTTLVal: 1800 * time.Second,
|
|
|
|
},
|
|
|
|
StorageView: &logical.InmemStorage{},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return b, cleanup
|
|
|
|
}
|