Placeholder Plugin Providers for Repos and added testPlugin struct (#1532)
* Create minimalistic plugin map and test plugin. * Pass secrets and attributes to the plugin when creating catalogs or sets. Add tests for CreateSet and CreateCatalog repo methods. * make fmt and extract out getPrivateCatalog and getCatalog helper methods. * Exporting TestPluginServer so it can be used in the handlers. * Keep separate persisted data from host catalogs lookups which facilitate passing it onto the plugins. * Add TODO to merge get Catalog and get Persisted data. * Adding tests for unimplemented being returned by the plugin. * Use GetFields() instead of AsMap() to confirm attributes should be populated. Make clone consistent between catalog and sets. Co-authored-by: Jeff Mitchell <jeffrey.mitchell@gmail.com>
This commit is contained in:
1 parent
ea939a4445
commit
bbfef2802f
30 files changed
+669
-227
No files matched your search
@@ -54,9 +54,7 @@ begin;
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp,
|
||||
version wt_version,
|
||||
attributes bytea not null
|
||||
constraint attributes_must_not_be_empty
|
||||
check(length(attributes) > 0),
|
||||
attributes bytea not null,
|
||||
constraint host_catalog_fkey
|
||||
foreign key (scope_id, public_id)
|
||||
references host_catalog (scope_id, public_id)
|
||||
@@ -126,9 +124,7 @@ begin;
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp,
|
||||
version wt_version,
|
||||
attributes bytea not null
|
||||
constraint attributes_must_not_be_empty
|
||||
check(length(attributes) > 0),
|
||||
attributes bytea not null,
|
||||
constraint host_plugin_set_catalog_id_name_uq
|
||||
unique(catalog_id, name),
|
||||
constraint host_set_fkey
|
||||
|
||||
@@ -7742,9 +7742,7 @@ alter table wh_session_connection_accumulating_fact
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp,
|
||||
version wt_version,
|
||||
attributes bytea not null
|
||||
constraint attributes_must_not_be_empty
|
||||
check(length(attributes) > 0),
|
||||
attributes bytea not null,
|
||||
constraint host_catalog_fkey
|
||||
foreign key (scope_id, public_id)
|
||||
references host_catalog (scope_id, public_id)
|
||||
@@ -7814,9 +7812,7 @@ alter table wh_session_connection_accumulating_fact
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp,
|
||||
version wt_version,
|
||||
attributes bytea not null
|
||||
constraint attributes_must_not_be_empty
|
||||
check(length(attributes) > 0),
|
||||
attributes bytea not null,
|
||||
constraint host_plugin_set_catalog_id_name_uq
|
||||
unique(catalog_id, name),
|
||||
constraint host_set_fkey
|
||||
@@ -7864,7 +7860,7 @@ create table host_set_preferred_endpoint (
|
||||
constraint priority_must_be_greater_than_zero
|
||||
check(priority > 0),
|
||||
condition text not null
|
||||
constraint condition_must_not_be_empty
|
||||
constraint condition_must_not_be_too_short
|
||||
check(length(trim(condition)) > 4) -- minimum is 'dns:*'
|
||||
constraint condition_must_not_be_too_long
|
||||
check(length(trim(condition)) < 255)
|
||||
|
||||
@@ -5,12 +5,12 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/host/plugin/store"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// A HostCatalog contains plugin host sets. It is owned by
|
||||
@@ -19,7 +19,7 @@ type HostCatalog struct {
|
||||
*store.HostCatalog
|
||||
tableName string `gorm:"-"`
|
||||
|
||||
secrets map[string]interface{} `gorm:"-"`
|
||||
secrets *structpb.Struct `gorm:"-"`
|
||||
}
|
||||
|
||||
// NewHostCatalog creates a new in memory HostCatalog assigned to a scopeId
|
||||
@@ -28,23 +28,22 @@ type HostCatalog struct {
|
||||
func NewHostCatalog(ctx context.Context, scopeId, pluginId string, opt ...Option) (*HostCatalog, error) {
|
||||
const op = "plugin.NewHostCatalog"
|
||||
opts := getOpts(opt...)
|
||||
|
||||
attrs, err := proto.Marshal(opts.withAttributes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidParameter))
|
||||
}
|
||||
|
||||
hc := &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: scopeId,
|
||||
PluginId: pluginId,
|
||||
Name: opts.withName,
|
||||
Description: opts.withDescription,
|
||||
Attributes: attrs,
|
||||
},
|
||||
secrets: opts.withSecrets,
|
||||
}
|
||||
|
||||
if opts.withAttributes != nil {
|
||||
attrs, err := json.Marshal(opts.withAttributes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidParameter))
|
||||
}
|
||||
hc.Attributes = attrs
|
||||
}
|
||||
return hc, nil
|
||||
}
|
||||
|
||||
@@ -58,16 +57,16 @@ func allocHostCatalog() *HostCatalog {
|
||||
// secret. The secret shallow copied.
|
||||
func (c *HostCatalog) clone() *HostCatalog {
|
||||
cp := proto.Clone(c.HostCatalog)
|
||||
newSecret := proto.Clone(c.secrets)
|
||||
|
||||
hc := &HostCatalog{
|
||||
HostCatalog: cp.(*store.HostCatalog),
|
||||
secrets: newSecret.(*structpb.Struct),
|
||||
}
|
||||
if c.secrets != nil {
|
||||
newSecret := make(map[string]interface{}, len(c.secrets))
|
||||
for k, v := range c.secrets {
|
||||
newSecret[k] = v
|
||||
}
|
||||
hc.secrets = newSecret
|
||||
// proto.Clone will convert slices with length and capacity of 0 to nil.
|
||||
// Fix this since gorm treats empty slices differently than nil.
|
||||
if c.Attributes != nil && len(c.Attributes) == 0 && hc.Attributes == nil {
|
||||
hc.Attributes = []byte{}
|
||||
}
|
||||
return hc
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
@@ -11,6 +10,7 @@ import (
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping"
|
||||
"github.com/hashicorp/go-kms-wrapping/structwrapping"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// HostCatalogSecret contains the encrypted secret for a host catalog.
|
||||
@@ -22,7 +22,7 @@ type HostCatalogSecret struct {
|
||||
|
||||
// newHostCatalogSecret creates an in memory host catalog secret.
|
||||
// All options are ignored.
|
||||
func newHostCatalogSecret(ctx context.Context, catalogId string, secret map[string]interface{}, _ ...Option) (*HostCatalogSecret, error) {
|
||||
func newHostCatalogSecret(ctx context.Context, catalogId string, secret *structpb.Struct, _ ...Option) (*HostCatalogSecret, error) {
|
||||
const op = "plugin.newHostCatlogSecret"
|
||||
hcs := &HostCatalogSecret{
|
||||
HostCatalogSecret: &store.HostCatalogSecret{
|
||||
@@ -31,7 +31,7 @@ func newHostCatalogSecret(ctx context.Context, catalogId string, secret map[stri
|
||||
}
|
||||
|
||||
if secret != nil {
|
||||
attrs, err := json.Marshal(secret)
|
||||
attrs, err := proto.Marshal(secret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidParameter))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -14,7 +13,9 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/plugin/host"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
func TestHostCatalogSecret_New(t *testing.T) {
|
||||
@@ -28,7 +29,7 @@ func TestHostCatalogSecret_New(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
catalogId string
|
||||
attrs map[string]interface{}
|
||||
attrs *structpb.Struct
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@@ -64,13 +65,19 @@ func TestHostCatalogSecret_New(t *testing.T) {
|
||||
name: "valid",
|
||||
args: args{
|
||||
catalogId: cat.GetPublicId(),
|
||||
attrs: map[string]interface{}{"foo": "bar"},
|
||||
attrs: func() *structpb.Struct {
|
||||
st, err := structpb.NewStruct(map[string]interface{}{"foo": "bar"})
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
want: &HostCatalogSecret{
|
||||
HostCatalogSecret: &store.HostCatalogSecret{
|
||||
CatalogId: cat.GetPublicId(),
|
||||
Secret: func() []byte {
|
||||
b, err := json.Marshal(map[string]interface{}{"foo": "bar"})
|
||||
st, err := structpb.NewStruct(map[string]interface{}{"foo": "bar"})
|
||||
require.NoError(t, err)
|
||||
b, err := proto.Marshal(st)
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}(),
|
||||
@@ -124,7 +131,8 @@ func TestHostCatalogSecret_Custom_Queries(t *testing.T) {
|
||||
databaseWrapper, err := kkms.GetWrapper(ctx, prj.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
|
||||
hcs, err := newHostCatalogSecret(ctx, cat.GetPublicId(), map[string]interface{}{"foo": "bar"})
|
||||
hcs, err := newHostCatalogSecret(ctx, cat.GetPublicId(),
|
||||
&structpb.Struct{Fields: map[string]*structpb.Value{"foo": structpb.NewStringValue("bar")}})
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, hcs.encrypt(ctx, databaseWrapper))
|
||||
q, v := hcs.insertQuery()
|
||||
@@ -141,7 +149,8 @@ func TestHostCatalogSecret_Custom_Queries(t *testing.T) {
|
||||
assert.Empty(t, cmp.Diff(hcs, found, protocmp.Transform()))
|
||||
|
||||
// Update the secret and see the value updated.
|
||||
updated, err := newHostCatalogSecret(ctx, cat.GetPublicId(), map[string]interface{}{"updated": "value"})
|
||||
updated, err := newHostCatalogSecret(ctx, cat.GetPublicId(),
|
||||
&structpb.Struct{Fields: map[string]*structpb.Value{"updated": structpb.NewStringValue("value")}})
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, updated.encrypt(ctx, databaseWrapper))
|
||||
q, v = updated.insertQuery()
|
||||
|
||||
@@ -2,7 +2,6 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -13,7 +12,9 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/plugin/host"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
func TestHostCatalog_Create(t *testing.T) {
|
||||
@@ -45,7 +46,7 @@ func TestHostCatalog_Create(t *testing.T) {
|
||||
want: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
wantCreateErr: true,
|
||||
@@ -59,7 +60,7 @@ func TestHostCatalog_Create(t *testing.T) {
|
||||
want: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
wantCreateErr: true,
|
||||
@@ -74,7 +75,7 @@ func TestHostCatalog_Create(t *testing.T) {
|
||||
HostCatalog: &store.HostCatalog{
|
||||
PluginId: plg.GetPublicId(),
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -92,7 +93,7 @@ func TestHostCatalog_Create(t *testing.T) {
|
||||
PluginId: plg.GetPublicId(),
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Name: "test-name",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -110,7 +111,7 @@ func TestHostCatalog_Create(t *testing.T) {
|
||||
PluginId: plg.GetPublicId(),
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Description: "test-description",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -120,7 +121,7 @@ func TestHostCatalog_Create(t *testing.T) {
|
||||
pluginId: plg.GetPublicId(),
|
||||
scopeId: prj.GetPublicId(),
|
||||
opts: []Option{
|
||||
WithAttributes(map[string]interface{}{"foo": "bar"}),
|
||||
WithAttributes(&structpb.Struct{Fields: map[string]*structpb.Value{"foo": structpb.NewStringValue("bar")}}),
|
||||
},
|
||||
},
|
||||
want: func() *HostCatalog {
|
||||
@@ -131,7 +132,7 @@ func TestHostCatalog_Create(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var err error
|
||||
hc.Attributes, err = json.Marshal(map[string]interface{}{"foo": "bar"})
|
||||
hc.Attributes, err = proto.Marshal(&structpb.Struct{Fields: map[string]*structpb.Value{"foo": structpb.NewStringValue("bar")}})
|
||||
require.NoError(t, err)
|
||||
return hc
|
||||
}(),
|
||||
|
||||
@@ -2,7 +2,6 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/host/plugin/store"
|
||||
@@ -22,23 +21,21 @@ type HostSet struct {
|
||||
func NewHostSet(ctx context.Context, catalogId string, opt ...Option) (*HostSet, error) {
|
||||
const op = "plugin.NewHostSet"
|
||||
opts := getOpts(opt...)
|
||||
attrs, err := proto.Marshal(opts.withAttributes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidParameter))
|
||||
}
|
||||
|
||||
set := &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: catalogId,
|
||||
Name: opts.withName,
|
||||
Description: opts.withDescription,
|
||||
Attributes: attrs,
|
||||
PreferredEndpoints: opts.withPreferredEndpoints,
|
||||
},
|
||||
}
|
||||
|
||||
if opts.withAttributes != nil {
|
||||
attrs, err := json.Marshal(opts.withAttributes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidParameter))
|
||||
}
|
||||
set.Attributes = attrs
|
||||
}
|
||||
|
||||
return set, nil
|
||||
}
|
||||
|
||||
@@ -64,9 +61,13 @@ func allocHostSet() *HostSet {
|
||||
|
||||
func (s *HostSet) clone() *HostSet {
|
||||
cp := proto.Clone(s.HostSet)
|
||||
return &HostSet{
|
||||
hs := &HostSet{
|
||||
HostSet: cp.(*store.HostSet),
|
||||
}
|
||||
if s.Attributes != nil && len(s.Attributes) == 0 && hs.Attributes == nil {
|
||||
hs.Attributes = []byte{}
|
||||
}
|
||||
return hs
|
||||
}
|
||||
|
||||
func (s *HostSet) oplog(op oplog.OpType) oplog.Metadata {
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/plugin/host"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
func TestHostSet_Create(t *testing.T) {
|
||||
@@ -37,7 +39,7 @@ func TestHostSet_Create(t *testing.T) {
|
||||
catalogId: "",
|
||||
},
|
||||
want: &HostSet{HostSet: &store.HostSet{
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
}},
|
||||
wantErr: true,
|
||||
},
|
||||
@@ -49,7 +51,7 @@ func TestHostSet_Create(t *testing.T) {
|
||||
want: &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: cat.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -65,7 +67,7 @@ func TestHostSet_Create(t *testing.T) {
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: cat.GetPublicId(),
|
||||
Name: "test-name",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -81,7 +83,7 @@ func TestHostSet_Create(t *testing.T) {
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: cat.GetPublicId(),
|
||||
Name: "test-name",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
@@ -98,7 +100,7 @@ func TestHostSet_Create(t *testing.T) {
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: cat2.GetPublicId(),
|
||||
Name: "test-name",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -114,7 +116,7 @@ func TestHostSet_Create(t *testing.T) {
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: cat.GetPublicId(),
|
||||
Description: "test-description",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -123,13 +125,18 @@ func TestHostSet_Create(t *testing.T) {
|
||||
args: args{
|
||||
catalogId: cat.GetPublicId(),
|
||||
opts: []Option{
|
||||
WithAttributes(map[string]interface{}{"foo": "bar"}),
|
||||
WithAttributes(&structpb.Struct{Fields: map[string]*structpb.Value{"foo": structpb.NewStringValue("bar")}}),
|
||||
},
|
||||
},
|
||||
want: &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: cat.GetPublicId(),
|
||||
Attributes: []byte(`{"foo":"bar"}`),
|
||||
CatalogId: cat.GetPublicId(),
|
||||
Attributes: func() []byte {
|
||||
st := &structpb.Struct{Fields: map[string]*structpb.Value{"foo": structpb.NewStringValue("bar")}}
|
||||
b, err := proto.Marshal(st)
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -145,7 +152,7 @@ func TestHostSet_Create(t *testing.T) {
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: cat.GetPublicId(),
|
||||
PreferredEndpoints: []string{"cidr:1.2.3.4"},
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/plugin/host"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -101,7 +102,9 @@ func TestPluginSet_ImmutableFields(t *testing.T) {
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
plg := host.TestPlugin(t, conn, "test", "prefix")
|
||||
cat := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
new := TestSet(t, conn, kmsCache, cat)
|
||||
new := TestSet(t, conn, kmsCache, cat, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{},
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package plugin
|
||||
|
||||
import "google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
// getOpts - iterate the inbound Options and return a struct
|
||||
func getOpts(opt ...Option) options {
|
||||
opts := getDefaultOptions()
|
||||
@@ -16,16 +18,14 @@ type Option func(*options)
|
||||
type options struct {
|
||||
withName string
|
||||
withDescription string
|
||||
withAttributes map[string]interface{}
|
||||
withSecrets map[string]interface{}
|
||||
withAttributes *structpb.Struct
|
||||
withSecrets *structpb.Struct
|
||||
withPreferredEndpoints []string
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
return options{
|
||||
withDescription: "",
|
||||
withName: "",
|
||||
withAttributes: make(map[string]interface{}),
|
||||
withAttributes: &structpb.Struct{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,14 +44,14 @@ func WithName(name string) Option {
|
||||
}
|
||||
|
||||
// WithAttributes provides an optional attributes field.
|
||||
func WithAttributes(attrs map[string]interface{}) Option {
|
||||
func WithAttributes(attrs *structpb.Struct) Option {
|
||||
return func(o *options) {
|
||||
o.withAttributes = attrs
|
||||
}
|
||||
}
|
||||
|
||||
// WithSecrets provides an optional secrets field.
|
||||
func WithSecrets(secrets map[string]interface{}) Option {
|
||||
func WithSecrets(secrets *structpb.Struct) Option {
|
||||
return func(o *options) {
|
||||
o.withSecrets = secrets
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/host"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
)
|
||||
|
||||
// A Repository stores and retrieves the persistent types in the plugin
|
||||
@@ -16,6 +17,11 @@ type Repository struct {
|
||||
reader db.Reader
|
||||
writer db.Writer
|
||||
kms *kms.Kms
|
||||
|
||||
// plugins is a map from plugin resource id to host plugin client.
|
||||
// TODO: When we are using go-plugin change from using a plgpb.HostPluginServiceServer
|
||||
// to the client.
|
||||
plugins map[string]plgpb.HostPluginServiceServer
|
||||
// defaultLimit provides a default for limiting the number of results
|
||||
// returned from the repo
|
||||
defaultLimit int
|
||||
@@ -25,7 +31,7 @@ type Repository struct {
|
||||
// only be used for one transaction and it is not safe for concurrent go
|
||||
// routines to access it. WithLimit option is used as a repo wide default
|
||||
// limit applied to all ListX methods.
|
||||
func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, opt ...host.Option) (*Repository, error) {
|
||||
func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, plgm map[string]plgpb.HostPluginServiceServer, opt ...host.Option) (*Repository, error) {
|
||||
const op = "plugin.NewRepository"
|
||||
switch {
|
||||
case r == nil:
|
||||
@@ -34,6 +40,8 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, opt ...host.Option) (
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "db.Writer")
|
||||
case kms == nil:
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "kms")
|
||||
case plgm == nil:
|
||||
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "plgm")
|
||||
}
|
||||
|
||||
opts, err := host.GetOpts(opt...)
|
||||
@@ -45,10 +53,16 @@ func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms, opt ...host.Option) (
|
||||
opts.WithLimit = db.DefaultLimit
|
||||
}
|
||||
|
||||
plgs := make(map[string]plgpb.HostPluginServiceServer, len(plgm))
|
||||
for k, v := range plgm {
|
||||
plgs[k] = v
|
||||
}
|
||||
|
||||
return &Repository{
|
||||
reader: r,
|
||||
writer: w,
|
||||
kms: kms,
|
||||
plugins: plgs,
|
||||
defaultLimit: opts.WithLimit,
|
||||
}, nil
|
||||
}
|
||||
@@ -10,6 +10,12 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
hostplg "github.com/hashicorp/boundary/internal/plugin/host"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// CreateCatalog inserts c into the repository and returns a new
|
||||
@@ -44,7 +50,6 @@ func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, _ ...Opt
|
||||
}
|
||||
c = c.clone()
|
||||
|
||||
// TODO: Capture this in a plugin manager and call the plugin's OnCreateCatalog function
|
||||
plg := hostplg.NewPlugin("", "")
|
||||
plg.PublicId = c.PluginId
|
||||
if err := r.reader.LookupByPublicId(ctx, plg); err != nil {
|
||||
@@ -60,27 +65,41 @@ func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, _ ...Opt
|
||||
}
|
||||
c.PublicId = id
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, c.ScopeId, kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
plgClient, ok := r.plugins[plg.GetPublicId()]
|
||||
if !ok || plgClient == nil {
|
||||
return nil, errors.New(ctx, errors.Internal, op, fmt.Sprintf("expected plugin %q not available", plg.GetPluginName()))
|
||||
}
|
||||
dbWrapper, err := r.kms.GetWrapper(ctx, c.ScopeId, kms.KeyPurposeDatabase)
|
||||
plgHc, err := toPluginCatalog(ctx, c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get db wrapper"))
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
plgResp, err := plgClient.OnCreateCatalog(ctx, &plgpb.OnCreateCatalogRequest{Catalog: plgHc})
|
||||
if err != nil {
|
||||
if status.Code(err) != codes.Unimplemented {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
}
|
||||
|
||||
var hcSecret *HostCatalogSecret
|
||||
if c.secrets != nil {
|
||||
// TODO: Create the secret using the returned value from the call to the plugin.
|
||||
hcSecret, err = newHostCatalogSecret(ctx, id, c.secrets)
|
||||
if plgResp != nil && plgResp.GetPersisted().GetData() != nil {
|
||||
hcSecret, err = newHostCatalogSecret(ctx, id, plgResp.GetPersisted().GetData())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
dbWrapper, err := r.kms.GetWrapper(ctx, c.ScopeId, kms.KeyPurposeDatabase)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get db wrapper"))
|
||||
}
|
||||
if err := hcSecret.encrypt(ctx, dbWrapper); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
}
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, c.ScopeId, kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
}
|
||||
|
||||
var newHostCatalog *HostCatalog
|
||||
_, err = r.writer.DoTx(
|
||||
ctx,
|
||||
@@ -137,9 +156,8 @@ func (r *Repository) LookupCatalog(ctx context.Context, id string, _ ...Option)
|
||||
if id == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
c := allocHostCatalog()
|
||||
c.PublicId = id
|
||||
if err := r.reader.LookupByPublicId(ctx, c); err != nil {
|
||||
c, err := r.getCatalog(ctx, id)
|
||||
if err != nil {
|
||||
if errors.IsNotFoundError(err) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -169,3 +187,75 @@ func (r *Repository) ListCatalogs(ctx context.Context, scopeIds []string, opt ..
|
||||
}
|
||||
return hostCatalogs, nil
|
||||
}
|
||||
|
||||
// getCatalog retrieves the *HostCatalog with the provided id. If it is not found or there
|
||||
// is an problem getting it from the database an error is returned instead.
|
||||
func (r *Repository) getCatalog(ctx context.Context, id string) (*HostCatalog, error) {
|
||||
const op = "plugin.(Repository).getCatalog"
|
||||
c := allocHostCatalog()
|
||||
c.PublicId = id
|
||||
if err := r.reader.LookupByPublicId(ctx, c); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for: %s", id)))
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// getPersistedDataForCatalog returns the persisted data for a catalog if
|
||||
// present. c must have a valid Public Id and Scope Id set.
|
||||
// TODO: consider merging the functions for getting catalog and persisted data into a view.
|
||||
func (r *Repository) getPersistedDataForCatalog(ctx context.Context, c *HostCatalog) (*plgpb.HostCatalogPersisted, error) {
|
||||
const op = "plugin.(Repository).getPersistedDataForCatalog"
|
||||
if c.PublicId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "empty public id")
|
||||
}
|
||||
if c.ScopeId == "" {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "empty scope id")
|
||||
}
|
||||
cSecret := allocHostCatalogSecret()
|
||||
if err := r.reader.LookupWhere(ctx, cSecret, "catalog_id=?", c.GetPublicId()); err != nil {
|
||||
if errors.IsNotFoundError(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if cSecret == nil {
|
||||
return nil, nil
|
||||
}
|
||||
dbWrapper, err := r.kms.GetWrapper(ctx, c.ScopeId, kms.KeyPurposeDatabase)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get db wrapper"))
|
||||
}
|
||||
if err := cSecret.decrypt(ctx, dbWrapper); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
data := &structpb.Struct{}
|
||||
if err := proto.Unmarshal(cSecret.GetSecret(), data); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unmarshaling secret"))
|
||||
}
|
||||
return &plgpb.HostCatalogPersisted{Data: data}, nil
|
||||
}
|
||||
|
||||
// toPluginCatalog returns a host catalog, with it's secret if available, in the format expected
|
||||
// by the host plugin system.
|
||||
func toPluginCatalog(ctx context.Context, in *HostCatalog) (*pb.HostCatalog, error) {
|
||||
const op = "plugin.toPluginCatalog"
|
||||
if in == nil {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "nil storage plugin")
|
||||
}
|
||||
hc := &pb.HostCatalog{
|
||||
Id: in.GetPublicId(),
|
||||
ScopeId: in.GetScopeId(),
|
||||
}
|
||||
if in.GetAttributes() != nil {
|
||||
attrs := &structpb.Struct{}
|
||||
if err := proto.Unmarshal(in.GetAttributes(), attrs); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to unmarshal attributes"))
|
||||
}
|
||||
hc.Attributes = attrs
|
||||
}
|
||||
if in.secrets != nil {
|
||||
hc.Secrets = in.secrets
|
||||
}
|
||||
return hc, nil
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/host/plugin/store"
|
||||
@@ -13,8 +14,12 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
hostplg "github.com/hashicorp/boundary/internal/plugin/host"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
func TestRepository_CreateCatalog(t *testing.T) {
|
||||
@@ -24,13 +29,27 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
wrapper := db.TestWrapper(t)
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
plg := hostplg.TestPlugin(t, conn, "test", "test")
|
||||
unimplementedPlugin := hostplg.TestPlugin(t, conn, "unimplemented", "unimplemented")
|
||||
|
||||
// gotPluginAttrs tracks which attributes a plugin has received through a closure and can be compared in the
|
||||
// test against the expected values sent to the plugin.
|
||||
var gotPluginAttrs *structpb.Struct
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{
|
||||
OnCreateCatalogFn: func(_ context.Context, req *plgpb.OnCreateCatalogRequest) (*plgpb.OnCreateCatalogResponse, error) {
|
||||
gotPluginAttrs = req.GetCatalog().GetAttributes()
|
||||
return &plgpb.OnCreateCatalogResponse{Persisted: &plgpb.HostCatalogPersisted{Data: req.GetCatalog().GetSecrets()}}, nil
|
||||
},
|
||||
},
|
||||
unimplementedPlugin.GetPublicId(): &plgpb.UnimplementedHostPluginServiceServer{},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
in *HostCatalog
|
||||
opts []Option
|
||||
want *HostCatalog
|
||||
wantSecret []byte
|
||||
wantSecret *structpb.Struct
|
||||
wantIsErr errors.Code
|
||||
}{
|
||||
{
|
||||
@@ -47,7 +66,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
in: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -57,7 +76,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
in: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -78,14 +97,31 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
want: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid-unimplemented-plugin",
|
||||
in: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: unimplementedPlugin.GetPublicId(),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
want: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: unimplementedPlugin.GetPublicId(),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -95,7 +131,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: "unknown_plugin",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -107,7 +143,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
Name: "test-name-repo",
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
want: &HostCatalog{
|
||||
@@ -115,7 +151,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
Name: "test-name-repo",
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -126,7 +162,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
Description: "test-description-repo",
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
want: &HostCatalog{
|
||||
@@ -134,7 +170,36 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
Description: "test-description-repo",
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid-with-attributes",
|
||||
in: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: func() []byte {
|
||||
st, err := structpb.NewStruct(map[string]interface{}{"k1": "foo"})
|
||||
require.NoError(t, err)
|
||||
b, err := proto.Marshal(st)
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}(),
|
||||
},
|
||||
},
|
||||
want: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: func() []byte {
|
||||
st, err := structpb.NewStruct(map[string]interface{}{"k1": "foo"})
|
||||
require.NoError(t, err)
|
||||
b, err := proto.Marshal(st)
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -145,23 +210,35 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
Description: "test-description-repo",
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
},
|
||||
secrets: map[string]interface{}{
|
||||
"k1": "v1",
|
||||
"k2": 2,
|
||||
"k3": nil,
|
||||
Attributes: []byte{},
|
||||
},
|
||||
secrets: func() *structpb.Struct {
|
||||
st, err := structpb.NewStruct(map[string]interface{}{
|
||||
"k1": "v1",
|
||||
"k2": 2,
|
||||
"k3": nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
want: &HostCatalog{
|
||||
HostCatalog: &store.HostCatalog{
|
||||
Description: "test-description-repo",
|
||||
ScopeId: prj.GetPublicId(),
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
},
|
||||
wantSecret: []byte(`{"k1":"v1","k2":2,"k3":null}`),
|
||||
wantSecret: func() *structpb.Struct {
|
||||
st, err := structpb.NewStruct(map[string]interface{}{
|
||||
"k1": "v1",
|
||||
"k2": 2,
|
||||
"k3": nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -170,7 +247,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
kmsCache := kms.TestKms(t, conn, wrapper)
|
||||
repo, err := NewRepository(rw, rw, kmsCache)
|
||||
repo, err := NewRepository(rw, rw, kmsCache, plgm)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(repo)
|
||||
got, err := repo.CreateCatalog(ctx, tt.in, tt.opts...)
|
||||
@@ -188,6 +265,12 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
assert.Equal(tt.want.Description, got.Description)
|
||||
assert.Equal(got.CreateTime, got.UpdateTime)
|
||||
|
||||
// wantedPluginAttributes := &structpb.Struct{}
|
||||
// require.NoError(t, proto.Unmarshal(tt.want.GetAttributes(), wantedPluginAttributes))
|
||||
gotB, err := proto.Marshal(gotPluginAttrs)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(tt.want.GetAttributes(), gotB)
|
||||
|
||||
assert.NoError(db.TestVerifyOplog(t, rw, got.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)))
|
||||
|
||||
cSecret := allocHostCatalogSecret()
|
||||
@@ -205,14 +288,17 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
dbWrapper, err := kmsCache.GetWrapper(ctx, got.GetScopeId(), kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, cSecret.decrypt(ctx, dbWrapper))
|
||||
assert.Equal(string(tt.wantSecret), string(cSecret.Secret))
|
||||
|
||||
st := &structpb.Struct{}
|
||||
require.NoError(t, proto.Unmarshal(cSecret.Secret, st))
|
||||
assert.Empty(cmp.Diff(tt.wantSecret, st, protocmp.Transform()))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("invalid-duplicate-names", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(repo)
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
@@ -221,7 +307,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
ScopeId: prj.GetPublicId(),
|
||||
Name: "test-name-repo",
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -242,7 +328,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
t.Run("valid-duplicate-names-diff-scopes", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(repo)
|
||||
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
@@ -250,7 +336,7 @@ func TestRepository_CreateCatalog(t *testing.T) {
|
||||
HostCatalog: &store.HostCatalog{
|
||||
Name: "test-name-repo",
|
||||
PluginId: plg.GetPublicId(),
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
}
|
||||
in2 := in.clone()
|
||||
@@ -292,6 +378,9 @@ func TestRepository_LookupCatalog(t *testing.T) {
|
||||
wrapper := db.TestWrapper(t)
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
plg := hostplg.TestPlugin(t, conn, "test", "test")
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{},
|
||||
}
|
||||
cat := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
badId, err := newHostCatalogId(ctx, plg.GetIdPrefix())
|
||||
assert.NoError(t, err)
|
||||
@@ -326,7 +415,7 @@ func TestRepository_LookupCatalog(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(repo)
|
||||
|
||||
@@ -354,10 +443,13 @@ func TestRepository_ListCatalogs_Multiple_Scopes(t *testing.T) {
|
||||
wrapper := db.TestWrapper(t)
|
||||
rw := db.New(conn)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
plg := hostplg.TestPlugin(t, conn, "test", "test")
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{},
|
||||
}
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, repo)
|
||||
plg := hostplg.TestPlugin(t, conn, "test", "test")
|
||||
|
||||
const numPerScope = 10
|
||||
var projs []string
|
||||
|
||||
@@ -14,6 +14,12 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
hostplg "github.com/hashicorp/boundary/internal/plugin/host"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostsets"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// CreateSet inserts s into the repository and returns a new HostSet
|
||||
@@ -45,14 +51,15 @@ func (r *Repository) CreateSet(ctx context.Context, scopeId string, s *HostSet,
|
||||
}
|
||||
s = s.clone()
|
||||
|
||||
c := allocHostCatalog()
|
||||
c.PublicId = s.GetCatalogId()
|
||||
if err := r.reader.LookupByPublicId(ctx, c); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get host catalog"))
|
||||
c, err := r.getCatalog(ctx, s.CatalogId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("looking up catalog"))
|
||||
}
|
||||
per, err := r.getPersistedDataForCatalog(ctx, c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("looking up persisted data"))
|
||||
}
|
||||
|
||||
// TODO: Contain the following plugin logic inside a plugin manager as well as
|
||||
// calling the plugin which we have looked up.
|
||||
plg := hostplg.NewPlugin("", "")
|
||||
plg.PublicId = c.GetPluginId()
|
||||
if err := r.reader.LookupByPublicId(ctx, plg); err != nil {
|
||||
@@ -65,6 +72,24 @@ func (r *Repository) CreateSet(ctx context.Context, scopeId string, s *HostSet,
|
||||
}
|
||||
s.PublicId = id
|
||||
|
||||
plgClient, ok := r.plugins[plg.GetPublicId()]
|
||||
if !ok || plgClient == nil {
|
||||
return nil, errors.New(ctx, errors.Internal, op, fmt.Sprintf("plugin with plugin name %q not available", plg.GetPluginName()))
|
||||
}
|
||||
plgHc, err := toPluginCatalog(ctx, c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
plgHs, err := toPluginSet(ctx, s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if _, err := plgClient.OnCreateSet(ctx, &plgpb.OnCreateSetRequest{Catalog: plgHc, Set: plgHs, Persisted: per}); err != nil {
|
||||
if status.Code(err) != codes.Unimplemented {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
}
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, scopeId, kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
@@ -294,3 +319,22 @@ type hostSetAgg struct {
|
||||
|
||||
// TableName returns the table name for gorm
|
||||
func (agg *hostSetAgg) TableName() string { return "host_plugin_host_set_with_value_obj" }
|
||||
|
||||
// toPluginSet returns a host set in the format expected by the host plugin system.
|
||||
func toPluginSet(ctx context.Context, in *HostSet) (*pb.HostSet, error) {
|
||||
const op = "plugin.toPluginCatalog"
|
||||
if in == nil {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "nil storage plugin")
|
||||
}
|
||||
hs := &pb.HostSet{
|
||||
Id: in.GetPublicId(),
|
||||
}
|
||||
if in.GetAttributes() != nil {
|
||||
attrs := &structpb.Struct{}
|
||||
if err := proto.Unmarshal(in.GetAttributes(), attrs); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to marshal attributes"))
|
||||
}
|
||||
hs.Attributes = attrs
|
||||
}
|
||||
return hs, nil
|
||||
}
|
||||
@@ -16,9 +16,12 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
hostplg "github.com/hashicorp/boundary/internal/plugin/host"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
func TestRepository_CreateSet(t *testing.T) {
|
||||
@@ -29,8 +32,20 @@ func TestRepository_CreateSet(t *testing.T) {
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
_, prj := iam.TestScopes(t, iamRepo)
|
||||
plg := hostplg.TestPlugin(t, conn, "create", "create")
|
||||
unimplementedPlugin := hostplg.TestPlugin(t, conn, "unimplemented", "unimplemented")
|
||||
|
||||
var pluginReceivedAttrs *structpb.Struct
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{OnCreateSetFn: func(ctx context.Context, req *plgpb.OnCreateSetRequest) (*plgpb.OnCreateSetResponse, error) {
|
||||
pluginReceivedAttrs = req.GetSet().GetAttributes()
|
||||
return &plgpb.OnCreateSetResponse{}, nil
|
||||
}},
|
||||
unimplementedPlugin.GetPublicId(): &plgpb.UnimplementedHostPluginServiceServer{},
|
||||
}
|
||||
|
||||
catalog := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
attrs := []byte("{}")
|
||||
unimplementedPluginCatalog := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
attrs := []byte{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -126,6 +141,23 @@ func TestRepository_CreateSet(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid-unimplemented-plugin",
|
||||
in: &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: unimplementedPluginCatalog.PublicId,
|
||||
Name: "valid-unimplemented-plugin",
|
||||
Attributes: attrs,
|
||||
},
|
||||
},
|
||||
want: &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: unimplementedPluginCatalog.PublicId,
|
||||
Name: "valid-unimplemented-plugin",
|
||||
Attributes: attrs,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid-with-description",
|
||||
in: &HostSet{
|
||||
@@ -143,13 +175,38 @@ func TestRepository_CreateSet(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid-with-custom-attributes",
|
||||
in: &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: catalog.PublicId,
|
||||
Description: ("test-description-repo"),
|
||||
Attributes: func() []byte {
|
||||
b, err := proto.Marshal(&structpb.Struct{Fields: map[string]*structpb.Value{"k1": structpb.NewStringValue("foo")}})
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}(),
|
||||
},
|
||||
},
|
||||
want: &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: catalog.PublicId,
|
||||
Description: ("test-description-repo"),
|
||||
Attributes: func() []byte {
|
||||
b, err := proto.Marshal(&structpb.Struct{Fields: map[string]*structpb.Value{"k1": structpb.NewStringValue("foo")}})
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
require.NoError(err)
|
||||
require.NotNil(repo)
|
||||
got, err := repo.CreateSet(context.Background(), prj.GetPublicId(), tt.in, tt.opts...)
|
||||
@@ -166,13 +223,17 @@ func TestRepository_CreateSet(t *testing.T) {
|
||||
assert.Equal(tt.want.Name, got.GetName())
|
||||
assert.Equal(tt.want.Description, got.GetDescription())
|
||||
assert.Equal(got.GetCreateTime(), got.GetUpdateTime())
|
||||
wantedPluginAttributes := &structpb.Struct{}
|
||||
require.NoError(proto.Unmarshal(tt.want.Attributes, wantedPluginAttributes))
|
||||
assert.Empty(cmp.Diff(wantedPluginAttributes, pluginReceivedAttrs, protocmp.Transform()))
|
||||
|
||||
assert.NoError(db.TestVerifyOplog(t, rw, got.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("invalid-duplicate-names", func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
require.NoError(err)
|
||||
require.NotNil(repo)
|
||||
|
||||
@@ -183,7 +244,7 @@ func TestRepository_CreateSet(t *testing.T) {
|
||||
HostSet: &store.HostSet{
|
||||
CatalogId: catalog.PublicId,
|
||||
Name: "test-name-repo",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -203,7 +264,7 @@ func TestRepository_CreateSet(t *testing.T) {
|
||||
|
||||
t.Run("valid-duplicate-names-diff-catalogs", func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
require.NoError(err)
|
||||
require.NotNil(repo)
|
||||
|
||||
@@ -214,7 +275,7 @@ func TestRepository_CreateSet(t *testing.T) {
|
||||
in := &HostSet{
|
||||
HostSet: &store.HostSet{
|
||||
Name: "test-name-repo",
|
||||
Attributes: []byte("{}"),
|
||||
Attributes: []byte{},
|
||||
},
|
||||
}
|
||||
in2 := in.clone()
|
||||
@@ -250,9 +311,14 @@ func TestRepository_LookupSet(t *testing.T) {
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
_, prj := iam.TestScopes(t, iamRepo)
|
||||
plg := hostplg.TestPlugin(t, conn, "lookup", "lookup")
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{},
|
||||
}
|
||||
|
||||
catalog := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
hostSet := TestSet(t, conn, kms, catalog)
|
||||
hostSet := TestSet(t, conn, kms, catalog, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{},
|
||||
})
|
||||
hostSetId, err := newHostSetId(ctx, plg.GetIdPrefix())
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -281,7 +347,7 @@ func TestRepository_LookupSet(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(err)
|
||||
require.NotNil(repo)
|
||||
got, err := repo.LookupSet(ctx, tt.in)
|
||||
@@ -307,13 +373,16 @@ func TestRepository_ListSets(t *testing.T) {
|
||||
|
||||
_, prj := iam.TestScopes(t, iamRepo)
|
||||
plg := hostplg.TestPlugin(t, conn, "list", "list")
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{},
|
||||
}
|
||||
catalogA := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
catalogB := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
|
||||
hostSets := []*HostSet{
|
||||
TestSet(t, conn, kms, catalogA),
|
||||
TestSet(t, conn, kms, catalogA),
|
||||
TestSet(t, conn, kms, catalogA),
|
||||
TestSet(t, conn, kms, catalogA, plgm),
|
||||
TestSet(t, conn, kms, catalogA, plgm),
|
||||
TestSet(t, conn, kms, catalogA, plgm),
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@@ -343,7 +412,7 @@ func TestRepository_ListSets(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, kms)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(err)
|
||||
require.NotNil(repo)
|
||||
got, err := repo.ListSets(context.Background(), tt.in, tt.opts...)
|
||||
@@ -371,11 +440,14 @@ func TestRepository_ListSets_Limits(t *testing.T) {
|
||||
|
||||
_, prj := iam.TestScopes(t, iamRepo)
|
||||
plg := hostplg.TestPlugin(t, conn, "listlimit", "listlimit")
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &TestPluginServer{},
|
||||
}
|
||||
catalog := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
count := 10
|
||||
var hostSets []*HostSet
|
||||
for i := 0; i < count; i++ {
|
||||
hostSets = append(hostSets, TestSet(t, conn, kms, catalog))
|
||||
hostSets = append(hostSets, TestSet(t, conn, kms, catalog, plgm))
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@@ -426,7 +498,7 @@ func TestRepository_ListSets_Limits(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, kms, tt.repoOpts...)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm, tt.repoOpts...)
|
||||
assert.NoError(err)
|
||||
require.NotNil(repo)
|
||||
got, err := repo.ListSets(context.Background(), hostSets[0].CatalogId, tt.listOpts...)
|
||||
|
||||
@@ -3,6 +3,7 @@ package plugin
|
||||
import (
|
||||
"testing"
|
||||
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -18,11 +19,14 @@ func TestRepository_New(t *testing.T) {
|
||||
wrapper := db.TestWrapper(t)
|
||||
kmsCache := kms.TestKms(t, conn, wrapper)
|
||||
|
||||
plgs := map[string]plgpb.HostPluginServiceServer{}
|
||||
|
||||
type args struct {
|
||||
r db.Reader
|
||||
w db.Writer
|
||||
kms *kms.Kms
|
||||
opts []host.Option
|
||||
r db.Reader
|
||||
w db.Writer
|
||||
kms *kms.Kms
|
||||
plugins map[string]plgpb.HostPluginServiceServer
|
||||
opts []host.Option
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@@ -34,38 +38,43 @@ func TestRepository_New(t *testing.T) {
|
||||
{
|
||||
name: "valid",
|
||||
args: args{
|
||||
r: rw,
|
||||
w: rw,
|
||||
kms: kmsCache,
|
||||
r: rw,
|
||||
w: rw,
|
||||
kms: kmsCache,
|
||||
plugins: plgs,
|
||||
},
|
||||
want: &Repository{
|
||||
reader: rw,
|
||||
writer: rw,
|
||||
kms: kmsCache,
|
||||
plugins: plgs,
|
||||
defaultLimit: db.DefaultLimit,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid-with-limit",
|
||||
args: args{
|
||||
r: rw,
|
||||
w: rw,
|
||||
kms: kmsCache,
|
||||
opts: []host.Option{host.WithLimit(5)},
|
||||
r: rw,
|
||||
w: rw,
|
||||
kms: kmsCache,
|
||||
plugins: plgs,
|
||||
opts: []host.Option{host.WithLimit(5)},
|
||||
},
|
||||
want: &Repository{
|
||||
reader: rw,
|
||||
writer: rw,
|
||||
kms: kmsCache,
|
||||
plugins: plgs,
|
||||
defaultLimit: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil-reader",
|
||||
args: args{
|
||||
r: nil,
|
||||
w: rw,
|
||||
kms: kmsCache,
|
||||
r: nil,
|
||||
w: rw,
|
||||
kms: kmsCache,
|
||||
plugins: plgs,
|
||||
},
|
||||
want: nil,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -73,9 +82,10 @@ func TestRepository_New(t *testing.T) {
|
||||
{
|
||||
name: "nil-writer",
|
||||
args: args{
|
||||
r: rw,
|
||||
w: nil,
|
||||
kms: kmsCache,
|
||||
r: rw,
|
||||
w: nil,
|
||||
kms: kmsCache,
|
||||
plugins: plgs,
|
||||
},
|
||||
want: nil,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -83,9 +93,21 @@ func TestRepository_New(t *testing.T) {
|
||||
{
|
||||
name: "nil-kms",
|
||||
args: args{
|
||||
r: rw,
|
||||
w: rw,
|
||||
kms: nil,
|
||||
r: rw,
|
||||
w: rw,
|
||||
kms: nil,
|
||||
plugins: plgs,
|
||||
},
|
||||
want: nil,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "nil-plugins",
|
||||
args: args{
|
||||
r: rw,
|
||||
w: rw,
|
||||
kms: kmsCache,
|
||||
plugins: nil,
|
||||
},
|
||||
want: nil,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -93,9 +115,10 @@ func TestRepository_New(t *testing.T) {
|
||||
{
|
||||
name: "all-nils",
|
||||
args: args{
|
||||
r: nil,
|
||||
w: nil,
|
||||
kms: nil,
|
||||
r: nil,
|
||||
w: nil,
|
||||
kms: nil,
|
||||
plugins: nil,
|
||||
},
|
||||
want: nil,
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -105,7 +128,7 @@ func TestRepository_New(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
got, err := NewRepository(tt.args.r, tt.args.w, tt.args.kms, tt.args.opts...)
|
||||
got, err := NewRepository(tt.args.r, tt.args.w, tt.args.kms, tt.args.plugins, tt.args.opts...)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "want err: %q got: %q", tt.wantIsErr, err)
|
||||
assert.Nil(got)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.15.8
|
||||
// protoc v3.17.3
|
||||
// source: controller/storage/host/plugin/store/v1/host.proto
|
||||
|
||||
// Package store provides protobufs for storing types in the plugin host
|
||||
@@ -56,8 +56,8 @@ type HostCatalog struct {
|
||||
// @inject_tag: `gorm:"default:null"`
|
||||
Version uint32 `protobuf:"varint,8,opt,name=version,proto3" json:"version,omitempty" gorm:"default:null"`
|
||||
// attributes is a jsonb formatted field.
|
||||
// @inject_tag: `gorm:"default:null"`
|
||||
Attributes []byte `protobuf:"bytes,9,opt,name=attributes,proto3" json:"attributes,omitempty" gorm:"default:null"`
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
Attributes []byte `protobuf:"bytes,9,opt,name=attributes,proto3" json:"attributes,omitempty" gorm:"not_null"`
|
||||
}
|
||||
|
||||
func (x *HostCatalog) Reset() {
|
||||
@@ -184,8 +184,8 @@ type HostSet struct {
|
||||
// @inject_tag: `gorm:"default:null"`
|
||||
Version uint32 `protobuf:"varint,7,opt,name=version,proto3" json:"version,omitempty" gorm:"default:null"`
|
||||
// attributes is a byte field containing marshaled JSON data
|
||||
// @inject_tag: `gorm:"default:null"`
|
||||
Attributes []byte `protobuf:"bytes,8,opt,name=attributes,proto3" json:"attributes,omitempty" gorm:"default:null"`
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
Attributes []byte `protobuf:"bytes,8,opt,name=attributes,proto3" json:"attributes,omitempty" gorm:"not_null"`
|
||||
// preferred_endpoints stores string preference values
|
||||
// @inject_tag: `gorm:"-"`
|
||||
PreferredEndpoints []string `protobuf:"bytes,9,rep,name=preferred_endpoints,json=preferredEndpoints,proto3" json:"preferred_endpoints,omitempty" gorm:"-"`
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/plugin/host"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -40,13 +41,13 @@ func TestCatalog(t *testing.T, conn *gorm.DB, scopeId, pluginId string, opt ...O
|
||||
// TestSet creates a plugin host sets in the provided DB
|
||||
// with the provided catalog id. The catalog must have been created
|
||||
// previously. The test will fail if any errors are encountered.
|
||||
func TestSet(t *testing.T, conn *gorm.DB, kmsCache *kms.Kms, hc *HostCatalog, opt ...Option) *HostSet {
|
||||
func TestSet(t *testing.T, conn *gorm.DB, kmsCache *kms.Kms, hc *HostCatalog, plgm map[string]plgpb.HostPluginServiceServer, opt ...Option) *HostSet {
|
||||
t.Helper()
|
||||
require := require.New(t)
|
||||
ctx := context.Background()
|
||||
rw := db.New(conn)
|
||||
|
||||
repo, err := NewRepository(rw, rw, kmsCache)
|
||||
repo, err := NewRepository(rw, rw, kmsCache, plgm)
|
||||
require.NoError(err)
|
||||
|
||||
set, err := NewHostSet(ctx, hc.PublicId, opt...)
|
||||
@@ -66,3 +67,64 @@ func TestSet(t *testing.T, conn *gorm.DB, kmsCache *kms.Kms, hc *HostCatalog, op
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
// TestPluginServer provides a host plugin service server where each method can be overwritten for tests.
|
||||
type TestPluginServer struct {
|
||||
OnCreateCatalogFn func(context.Context, *plgpb.OnCreateCatalogRequest) (*plgpb.OnCreateCatalogResponse, error)
|
||||
OnUpdateCatalogFn func(context.Context, *plgpb.OnUpdateCatalogRequest) (*plgpb.OnUpdateCatalogResponse, error)
|
||||
OnDeleteCatalogFn func(context.Context, *plgpb.OnDeleteCatalogRequest) (*plgpb.OnDeleteCatalogResponse, error)
|
||||
OnCreateSetFn func(context.Context, *plgpb.OnCreateSetRequest) (*plgpb.OnCreateSetResponse, error)
|
||||
OnUpdateSetFn func(context.Context, *plgpb.OnUpdateSetRequest) (*plgpb.OnUpdateSetResponse, error)
|
||||
OnDeleteSetFn func(context.Context, *plgpb.OnDeleteSetRequest) (*plgpb.OnDeleteSetResponse, error)
|
||||
ListHostsFn func(context.Context, *plgpb.ListHostsRequest) (*plgpb.ListHostsResponse, error)
|
||||
plgpb.UnimplementedHostPluginServiceServer
|
||||
}
|
||||
|
||||
func (t TestPluginServer) OnCreateCatalog(ctx context.Context, req *plgpb.OnCreateCatalogRequest) (*plgpb.OnCreateCatalogResponse, error) {
|
||||
if t.OnCreateCatalogFn == nil {
|
||||
return t.UnimplementedHostPluginServiceServer.OnCreateCatalog(ctx, req)
|
||||
}
|
||||
return t.OnCreateCatalogFn(ctx, req)
|
||||
}
|
||||
|
||||
func (t TestPluginServer) OnUpdateCatalog(ctx context.Context, req *plgpb.OnUpdateCatalogRequest) (*plgpb.OnUpdateCatalogResponse, error) {
|
||||
if t.OnUpdateCatalogFn == nil {
|
||||
return t.UnimplementedHostPluginServiceServer.OnUpdateCatalog(ctx, req)
|
||||
}
|
||||
return t.OnUpdateCatalogFn(ctx, req)
|
||||
}
|
||||
|
||||
func (t TestPluginServer) OnDeleteCatalog(ctx context.Context, req *plgpb.OnDeleteCatalogRequest) (*plgpb.OnDeleteCatalogResponse, error) {
|
||||
if t.OnDeleteCatalogFn == nil {
|
||||
return t.UnimplementedHostPluginServiceServer.OnDeleteCatalog(ctx, req)
|
||||
}
|
||||
return t.OnDeleteCatalogFn(ctx, req)
|
||||
}
|
||||
|
||||
func (t TestPluginServer) OnCreateSet(ctx context.Context, req *plgpb.OnCreateSetRequest) (*plgpb.OnCreateSetResponse, error) {
|
||||
if t.OnCreateSetFn == nil {
|
||||
return t.UnimplementedHostPluginServiceServer.OnCreateSet(ctx, req)
|
||||
}
|
||||
return t.OnCreateSetFn(ctx, req)
|
||||
}
|
||||
|
||||
func (t TestPluginServer) OnUpdateSet(ctx context.Context, req *plgpb.OnUpdateSetRequest) (*plgpb.OnUpdateSetResponse, error) {
|
||||
if t.OnUpdateSetFn == nil {
|
||||
return t.UnimplementedHostPluginServiceServer.OnUpdateSet(ctx, req)
|
||||
}
|
||||
return t.OnUpdateSetFn(ctx, req)
|
||||
}
|
||||
|
||||
func (t TestPluginServer) OnDeleteSet(ctx context.Context, req *plgpb.OnDeleteSetRequest) (*plgpb.OnDeleteSetResponse, error) {
|
||||
if t.OnDeleteSetFn == nil {
|
||||
return t.UnimplementedHostPluginServiceServer.OnDeleteSet(ctx, req)
|
||||
}
|
||||
return t.OnDeleteSetFn(ctx, req)
|
||||
}
|
||||
|
||||
func (t TestPluginServer) ListHosts(ctx context.Context, req *plgpb.ListHostsRequest) (*plgpb.ListHostsResponse, error) {
|
||||
if t.ListHostsFn == nil {
|
||||
return t.UnimplementedHostPluginServiceServer.ListHosts(ctx, req)
|
||||
}
|
||||
return t.ListHostsFn(ctx, req)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/plugin/host"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -46,7 +47,7 @@ func Test_TestSet(t *testing.T) {
|
||||
assert.NotEmpty(plg.GetPublicId())
|
||||
|
||||
c := TestCatalog(t, conn, prj.GetPublicId(), plg.GetPublicId())
|
||||
set := TestSet(t, conn, kmsCache, c, WithName("foo"), WithDescription("bar"))
|
||||
set := TestSet(t, conn, kmsCache, c, map[string]plgpb.HostPluginServiceServer{plg.GetPublicId(): &TestPluginServer{}}, WithName("foo"), WithDescription("bar"))
|
||||
assert.NotEmpty(set.GetPublicId())
|
||||
assert.True(strings.HasPrefix(set.GetPublicId(), fmt.Sprintf("%s_%s", HostSetPrefix, "prefix")))
|
||||
assert.Equal("foo", set.GetName())
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
hostplg "github.com/hashicorp/boundary/internal/plugin/host"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -26,7 +27,9 @@ func TestPreferredEndpoint_Create(t *testing.T) {
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
plg := hostplg.TestPlugin(t, conn, "create", "create")
|
||||
catalog := plugin.TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
set := plugin.TestSet(t, conn, kmsCache, catalog)
|
||||
set := plugin.TestSet(t, conn, kmsCache, catalog, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
})
|
||||
|
||||
type args struct {
|
||||
hostSetId string
|
||||
@@ -154,7 +157,9 @@ func TestPreferredEndpoint_Delete(t *testing.T) {
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
plg := hostplg.TestPlugin(t, conn, "create", "create")
|
||||
catalog := plugin.TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
set := plugin.TestSet(t, conn, kmsCache, catalog)
|
||||
set := plugin.TestSet(t, conn, kmsCache, catalog, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plgpb.UnimplementedHostPluginServiceServer{},
|
||||
})
|
||||
|
||||
peFunc := func(priority uint32, condition string) *host.PreferredEndpoint {
|
||||
ep, err := host.NewPreferredEndpoint(ctx, set.PublicId, priority, condition)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.15.8
|
||||
// protoc v3.17.3
|
||||
// source: controller/storage/plugin/host/store/v1/plugin.proto
|
||||
|
||||
// Package store provides protobufs for storing types in the host package.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.15.8
|
||||
// protoc v3.17.3
|
||||
// source: controller/storage/plugin/store/v1/plugin.proto
|
||||
|
||||
// Package store provides protobufs for storing types in the host package.
|
||||
|
||||
@@ -43,7 +43,7 @@ message HostCatalog {
|
||||
uint32 version = 8;
|
||||
|
||||
// attributes is a jsonb formatted field.
|
||||
// @inject_tag: `gorm:"default:null"`
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
bytes attributes = 9;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ message HostSet {
|
||||
uint32 version = 7;
|
||||
|
||||
// attributes is a byte field containing marshaled JSON data
|
||||
// @inject_tag: `gorm:"default:null"`
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
bytes attributes = 8;
|
||||
|
||||
// preferred_endpoints stores string preference values
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/servers/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-secure-stdlib/mlock"
|
||||
"github.com/patrickmn/go-cache"
|
||||
@@ -136,7 +137,7 @@ func New(ctx context.Context, conf *Config) (*Controller, error) {
|
||||
return static.NewRepository(dbase, dbase, c.kms)
|
||||
}
|
||||
c.PluginHostRepoFn = func() (*hostplugin.Repository, error) {
|
||||
return hostplugin.NewRepository(dbase, dbase, c.kms)
|
||||
return hostplugin.NewRepository(dbase, dbase, c.kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
c.HostPluginRepoFn = func() (*host.Repository, error) {
|
||||
return host.NewRepository(dbase, dbase, c.kms)
|
||||
|
||||
@@ -2,7 +2,6 @@ package host_catalogs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -26,6 +25,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
@@ -603,16 +603,13 @@ func toProto(ctx context.Context, in host.Catalog, opt ...handlers.Option) (*pb.
|
||||
if outputFields.Has(globals.AttributesField) {
|
||||
switch h := in.(type) {
|
||||
case *plugin.HostCatalog:
|
||||
attrs := map[string]interface{}{}
|
||||
err := json.Unmarshal(h.Attributes, &attrs)
|
||||
attrs := &structpb.Struct{}
|
||||
err := proto.Unmarshal(h.Attributes, attrs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if len(attrs) > 0 {
|
||||
out.Attributes, err = structpb.NewStruct(attrs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if len(attrs.GetFields()) > 0 {
|
||||
out.Attributes = attrs
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -645,10 +642,10 @@ func toStoragePluginCatalog(ctx context.Context, scopeId, plgId string, item *pb
|
||||
opts = append(opts, plugin.WithDescription(desc.GetValue()))
|
||||
}
|
||||
if attrs := item.GetAttributes(); attrs != nil {
|
||||
opts = append(opts, plugin.WithAttributes(attrs.AsMap()))
|
||||
opts = append(opts, plugin.WithAttributes(attrs))
|
||||
}
|
||||
if secrets := item.GetSecrets(); secrets != nil {
|
||||
opts = append(opts, plugin.WithSecrets(secrets.AsMap()))
|
||||
opts = append(opts, plugin.WithSecrets(secrets))
|
||||
}
|
||||
hc, err := plugin.NewHostCatalog(ctx, scopeId, plgId, opts...)
|
||||
if err != nil {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs"
|
||||
scopepb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"google.golang.org/genproto/protobuf/field_mask"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -62,7 +63,7 @@ func TestGet_Static(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
@@ -151,7 +152,7 @@ func TestGet_Plugin(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
@@ -240,7 +241,7 @@ func TestList(t *testing.T) {
|
||||
return iam.TestRepo(t, conn, wrapper), nil
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
@@ -433,7 +434,7 @@ func TestDelete(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
@@ -503,7 +504,7 @@ func TestDelete_twice(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
@@ -538,7 +539,7 @@ func TestCreate_Static(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
@@ -688,9 +689,6 @@ func TestCreate_Plugin(t *testing.T) {
|
||||
repo := func() (*static.Repository, error) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
}
|
||||
@@ -700,6 +698,15 @@ func TestCreate_Plugin(t *testing.T) {
|
||||
|
||||
name := "test"
|
||||
plg := host.TestPlugin(t, conn, name, name)
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{
|
||||
OnCreateCatalogFn: func(ctx context.Context, req *plgpb.OnCreateCatalogRequest) (*plgpb.OnCreateCatalogResponse, error) {
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
defaultHc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
defaultHcCreated := defaultHc.GetCreateTime().GetTimestamp().AsTime()
|
||||
toMerge := &pbs.CreateHostCatalogRequest{}
|
||||
@@ -845,7 +852,7 @@ func TestUpdate(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
|
||||
@@ -2,7 +2,6 @@ package host_sets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -24,6 +23,7 @@ import (
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostsets"
|
||||
"github.com/hashicorp/go-secure-stdlib/strutil"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
@@ -756,16 +756,13 @@ func toProto(ctx context.Context, in host.Set, hosts []host.Host, opt ...handler
|
||||
out.PreferredEndpoints = h.GetPreferredEndpoints()
|
||||
}
|
||||
if outputFields.Has(globals.AttributesField) {
|
||||
attrs := map[string]interface{}{}
|
||||
err := json.Unmarshal(h.Attributes, &attrs)
|
||||
attrs := &structpb.Struct{}
|
||||
err := proto.Unmarshal(h.Attributes, attrs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if len(attrs) > 0 {
|
||||
out.Attributes, err = structpb.NewStruct(attrs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if len(attrs.GetFields()) > 0 {
|
||||
out.Attributes = attrs
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -799,7 +796,7 @@ func toStoragePluginSet(ctx context.Context, catalogId string, item *pb.HostSet)
|
||||
opts = append(opts, plugin.WithDescription(item.GetDescription().GetValue()))
|
||||
}
|
||||
if item.GetAttributes() != nil {
|
||||
opts = append(opts, plugin.WithAttributes(item.GetAttributes().AsMap()))
|
||||
opts = append(opts, plugin.WithAttributes(item.GetAttributes()))
|
||||
}
|
||||
if item.GetPreferredEndpoints() != nil {
|
||||
opts = append(opts, plugin.WithPreferredEndpoints(item.GetPreferredEndpoints()))
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostsets"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/genproto/protobuf/field_mask"
|
||||
@@ -54,7 +55,7 @@ func TestGet_Static(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
|
||||
hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
|
||||
@@ -147,14 +148,16 @@ func TestGet_Plugin(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
|
||||
name := "test"
|
||||
prefEndpoints := []string{"cidr:1.2.3.4", "cidr:2.3.4.5/24"}
|
||||
plg := hostplugin.TestPlugin(t, conn, name, name)
|
||||
hc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
hs := plugin.TestSet(t, conn, kms, hc, plugin.WithPreferredEndpoints(prefEndpoints))
|
||||
hs := plugin.TestSet(t, conn, kms, hc, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
}, plugin.WithPreferredEndpoints(prefEndpoints))
|
||||
|
||||
toMerge := &pbs.GetHostSetRequest{}
|
||||
|
||||
@@ -241,7 +244,7 @@ func TestList_Static(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
hcs := static.TestCatalogs(t, conn, proj.GetPublicId(), 2)
|
||||
hc, hcNoHosts := hcs[0], hcs[1]
|
||||
@@ -338,18 +341,21 @@ func TestList_Plugin(t *testing.T) {
|
||||
repoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
}
|
||||
name := "test"
|
||||
plg := hostplugin.TestPlugin(t, conn, name, name)
|
||||
plgm := map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms, plgm)
|
||||
}
|
||||
hc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
hcNoHosts := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
preferredEndpoints := []string{"cidr:1.2.3.4", "dns:*.foobar.com"}
|
||||
|
||||
var wantHs []*pb.HostSet
|
||||
for i := 0; i < 10; i++ {
|
||||
h := plugin.TestSet(t, conn, kms, hc, plugin.WithPreferredEndpoints(preferredEndpoints))
|
||||
h := plugin.TestSet(t, conn, kms, hc, plgm, plugin.WithPreferredEndpoints(preferredEndpoints))
|
||||
wantHs = append(wantHs, &pb.HostSet{
|
||||
Id: h.GetPublicId(),
|
||||
HostCatalogId: h.GetCatalogId(),
|
||||
@@ -443,7 +449,7 @@ func TestDelete(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
|
||||
h := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
|
||||
@@ -522,7 +528,7 @@ func TestDelete_twice(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
|
||||
h := static.TestSets(t, conn, hc.GetPublicId(), 1)[0]
|
||||
@@ -558,7 +564,7 @@ func TestCreate_Static(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0]
|
||||
|
||||
@@ -700,11 +706,17 @@ func TestCreate_Plugin(t *testing.T) {
|
||||
repoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
}
|
||||
name := "test"
|
||||
plg := hostplugin.TestPlugin(t, conn, name, name)
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{
|
||||
OnCreateSetFn: func(ctx context.Context, req *plgpb.OnCreateSetRequest) (*plgpb.OnCreateSetResponse, error) {
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
hc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
|
||||
testAttrs, err := structpb.NewStruct(map[string]interface{}{
|
||||
@@ -956,7 +968,7 @@ func TestUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
tested, err := host_sets.NewService(repoFn, plgRepoFn)
|
||||
require.NoError(t, err, "Failed to create a new host set service.")
|
||||
@@ -1295,7 +1307,7 @@ func TestAddHostSetHosts(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
s, err := host_sets.NewService(repoFn, plgRepoFn)
|
||||
require.NoError(t, err, "Error when getting new host set service.")
|
||||
@@ -1415,7 +1427,7 @@ func TestSetHostSetHosts(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
s, err := host_sets.NewService(repoFn, plgRepoFn)
|
||||
require.NoError(t, err, "Error when getting new host set service.")
|
||||
@@ -1531,7 +1543,7 @@ func TestRemoveHostSetHosts(t *testing.T) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
plgRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms)
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceServer{})
|
||||
}
|
||||
s, err := host_sets.NewService(repoFn, plgRepoFn)
|
||||
require.NoError(t, err, "Error when getting new host set service.")
|
||||
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
credpb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -983,7 +984,9 @@ func TestAddTargetHostSets(t *testing.T) {
|
||||
|
||||
plg := host.TestPlugin(t, conn, "test", "test")
|
||||
pluginHc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc)
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
})
|
||||
|
||||
addCases := []struct {
|
||||
name string
|
||||
@@ -1115,7 +1118,9 @@ func TestSetTargetHostSets(t *testing.T) {
|
||||
|
||||
plg := host.TestPlugin(t, conn, "test", "test")
|
||||
pluginHc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc)
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
})
|
||||
|
||||
setCases := []struct {
|
||||
name string
|
||||
@@ -1241,7 +1246,9 @@ func TestRemoveTargetHostSets(t *testing.T) {
|
||||
|
||||
plg := host.TestPlugin(t, conn, "test", "test")
|
||||
pluginHc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc)
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
})
|
||||
|
||||
removeCases := []struct {
|
||||
name string
|
||||
@@ -1379,7 +1386,9 @@ func TestAddTargetHostSources(t *testing.T) {
|
||||
|
||||
plg := host.TestPlugin(t, conn, "test", "test")
|
||||
pluginHc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc)
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
})
|
||||
|
||||
addCases := []struct {
|
||||
name string
|
||||
@@ -1511,7 +1520,9 @@ func TestSetTargetHostSources(t *testing.T) {
|
||||
|
||||
plg := host.TestPlugin(t, conn, "test", "test")
|
||||
pluginHc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc)
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
})
|
||||
|
||||
setCases := []struct {
|
||||
name string
|
||||
@@ -1631,7 +1642,9 @@ func TestRemoveTargetHostSources(t *testing.T) {
|
||||
|
||||
plg := host.TestPlugin(t, conn, "test", "test")
|
||||
pluginHc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc)
|
||||
pluginHs := plugin.TestSet(t, conn, kms, pluginHc, map[string]plgpb.HostPluginServiceServer{
|
||||
plg.GetPublicId(): &plugin.TestPluginServer{},
|
||||
})
|
||||
|
||||
removeCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.15.8
|
||||
// protoc v3.17.3
|
||||
// source: plugin/v1/host_plugin_service.proto
|
||||
|
||||
package plugin
|
||||
|
||||
Reference in new issue
Block a user