refact(target): Change repository to take CredentialLibraries

This change removes the hard-coded credential purpose for the Credential
Libraries. It also moves the logic of creating CredentialLibraries from
CredentialSources out of the repository and into the targets.Service.
This refactor will allow for additional credential purposes to be
supported in both the service and the repository.
This commit is contained in:
Timothy Messier committed 2021-10-29 10:01:52 -04:00
1 parent 8ae6e9892f
commit 2cc58ff901
20 files changed
+1213 -133

No files matched your search

+1
View File
@@ -129,6 +129,7 @@ protobuild:
@protoc-go-inject-tag -input=./internal/kms/store/session_key.pb.go
@protoc-go-inject-tag -input=./internal/kms/store/oidc_key.pb.go
@protoc-go-inject-tag -input=./internal/target/store/target.pb.go
@protoc-go-inject-tag -input=./internal/target/targettest/store/target.pb.go
@protoc-go-inject-tag -input=./internal/target/tcp/store/target.pb.go
@protoc-go-inject-tag -input=./internal/auth/oidc/store/oidc.pb.go
@protoc-go-inject-tag -input=./internal/scheduler/job/store/job.pb.go
+11
View File
@@ -28,6 +28,10 @@ type Library interface {
// Purpose is the purpose of the credential.
type Purpose string
func (p Purpose) String() string {
return string(p)
}
// Credential purpose values.
const (
// ApplicationPurpose is a credential used for application specific
@@ -45,6 +49,13 @@ const (
EgressPurpose Purpose = "egress"
)
// ValidPurposes are the set of all credential Purposes.
var ValidPurposes = []Purpose{
ApplicationPurpose,
IngressPurpose,
EgressPurpose,
}
// SecretData represents secret data.
type SecretData interface{}
@@ -165,16 +165,21 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrappe
ctx := context.Background()
stores := vault.TestCredentialStores(t, conn, wrapper, tar.GetScopeId(), 1)
libs := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
libs := []*target.CredentialLibrary{
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.IngressPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose),
}
targetRepo, err := target.NewRepository(rw, rw, kms)
require.NoError(t, err)
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), []string{libs[0].PublicId, libs[1].PublicId})
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs)
require.NoError(t, err)
creds := []*session.DynamicCredential{
session.NewDynamicCredential(libs[0].GetPublicId(), credential.ApplicationPurpose),
session.NewDynamicCredential(libs[0].GetPublicId(), credential.IngressPurpose),
session.NewDynamicCredential(libs[1].GetPublicId(), credential.EgressPurpose),
session.NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose),
session.NewDynamicCredential(libIds[0].GetPublicId(), credential.IngressPurpose),
session.NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose),
}
return creds
}
@@ -0,0 +1,73 @@
syntax = "proto3";
package controller.storage.target.targettest.store.v1;
option go_package = "github.com/hashicorp/boundary/internal/target/targettest/store;store";
import "controller/storage/timestamp/v1/timestamp.proto";
import "controller/custom_options/v1/options.proto";
message Target {
// public_id is used to access the targettest.Target via an API
// @inject_tag: gorm:"primary_key"
string public_id = 10;
// scope id for the targettest.Target
// @inject_tag: `gorm:"default:null"`
string scope_id = 20;
// name is the optional friendly name used to
// access the targettest.Target via an API
// @inject_tag: `gorm:"default:null"`
string name = 30
[(custom_options.v1.mask_mapping) = { this: "name" that: "name" }];
// description of the targettest.Target
// @inject_tag: `gorm:"default:null"`
string description = 40 [(custom_options.v1.mask_mapping) = {
this: "description"
that: "description"
}];
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp create_time = 50;
// update_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp update_time = 60;
// version allows optimistic locking of the targettest.Target when modifying the
// targettest.Target
// @inject_tag: `gorm:"default:null"`
uint32 version = 70;
// default port of the targettest.Target
// @inject_tag: `gorm:"default:null"`
uint32 default_port = 80 [(custom_options.v1.mask_mapping) = {
this: "DefaultPort"
that: "attributes.default_port"
}];
// Maximum total lifetime of a created session, in seconds
// @inject_tag: `gorm:"default:null"`
uint32 session_max_seconds = 100 [(custom_options.v1.mask_mapping) = {
this: "SessionMaxSeconds"
that: "session_max_seconds"
}];
// Maximum number of connections in a session
// @inject_tag: `gorm:"default:null"`
int32 session_connection_limit = 110 [(custom_options.v1.mask_mapping) = {
this: "SessionConnectionLimit"
that: "session_connection_limit"
}];
// A boolean expression that allows filtering the workers that can handle a session
// @inject_tag: `gorm:"default:null"`
string worker_filter = 120 [(custom_options.v1.mask_mapping) = {
this: "WorkerFilter"
that: "worker_filter"
}];
}
@@ -1346,12 +1346,17 @@ func (s Service) removeHostSourcesInRepo(ctx context.Context, targetId string, h
return out, hs, cl, nil
}
func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
}
out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false))
credLibs, err := createCredLibs(targetId, applicationIds, nil, nil)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
}
out, hs, credSources, err := repo.AddTargetCredentialSources(ctx, targetId, version, credLibs)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to add credential sources to target: %v.", err)
@@ -1362,13 +1367,19 @@ func (s Service) addCredentialSourcesInRepo(ctx context.Context, targetId string
return out, hs, credSources, nil
}
func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
const op = "targets.(Service).setCredentialSourcesInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
}
_, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false))
credLibs, err := createCredLibs(targetId, applicationIds, nil, nil)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
}
_, _, _, err = repo.SetTargetCredentialSources(ctx, targetId, version, credLibs)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
@@ -1384,13 +1395,18 @@ func (s Service) setCredentialSourcesInRepo(ctx context.Context, targetId string
return out, hs, credSources, nil
}
func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, ids []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
func (s Service) removeCredentialSourcesInRepo(ctx context.Context, targetId string, applicationIds []string, version uint32) (target.Target, []target.HostSource, []target.CredentialSource, error) {
const op = "targets.(Service).removeCredentialSourcesInRepo"
repo, err := s.repoFn()
if err != nil {
return nil, nil, nil, err
}
_, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, strutil.RemoveDuplicates(ids, false))
credLibs, err := createCredLibs(targetId, applicationIds, nil, nil)
if err != nil {
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to set credential sources in target: %v.", err)
}
_, err = repo.DeleteTargetCredentialSources(ctx, targetId, version, credLibs)
if err != nil {
// TODO: Figure out a way to surface more helpful error info beyond the Internal error.
return nil, nil, nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to remove credential sources from target: %v.", err)
@@ -2003,3 +2019,23 @@ func validateAuthorizeSessionRequest(req *pbs.AuthorizeSessionRequest) error {
}
return nil
}
func createCredLibs(targetId string, applicationIds, ingressIds, egressIds []string) ([]*target.CredentialLibrary, error) {
credLibs := make([]*target.CredentialLibrary, 0, len(applicationIds)+len(ingressIds)+len(egressIds))
byPurpose := map[credential.Purpose][]string{
credential.ApplicationPurpose: strutil.RemoveDuplicates(applicationIds, false),
credential.IngressPurpose: strutil.RemoveDuplicates(ingressIds, false),
credential.EgressPurpose: strutil.RemoveDuplicates(egressIds, false),
}
for purpose, ids := range byPurpose {
for _, id := range ids {
l, err := target.NewCredentialLibrary(targetId, id, purpose)
if err != nil {
return nil, err
}
credLibs = append(credLibs, l)
}
}
return credLibs, nil
}
@@ -14,6 +14,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
@@ -1704,13 +1705,13 @@ func TestAddTargetLibraries(t *testing.T) {
},
{
name: "Add library on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for libraries", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add duplicated libraries on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for libraries", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultLibraryIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
@@ -1840,19 +1841,19 @@ func TestSetTargetLibraries(t *testing.T) {
},
{
name: "Set on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setLibraries: []string{cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Set duplicate libraries on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setLibraries: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultLibraryIds: []string{cls[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setLibraries: []string{},
resultLibraryIds: nil,
},
@@ -1966,13 +1967,13 @@ func TestRemoveTargetLibraries(t *testing.T) {
},
{
name: "Remove 1 of 2 libraries",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeLibs: []string{cls[1].GetPublicId()},
resultLibIds: []string{cls[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 libraries",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeLibs: []string{
cls[1].GetPublicId(), cls[1].GetPublicId(),
},
@@ -1980,7 +1981,7 @@ func TestRemoveTargetLibraries(t *testing.T) {
},
{
name: "Remove all libraries from target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeLibs: []string{
cls[0].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2101,13 +2102,13 @@ func TestAddTargetSources(t *testing.T) {
},
{
name: "Add source on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated for sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addSources: []string{cls[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
{
name: "Add duplicated sources on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicated for sources", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
addSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultSourceIds: []string{cls[0].GetPublicId(), cls[1].GetPublicId()},
},
@@ -2237,19 +2238,19 @@ func TestSetTargetCredentialSources(t *testing.T) {
},
{
name: "Set on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set duplicate sources on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{cls[1].GetPublicId(), cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[1].GetPublicId()},
},
{
name: "Set empty on populated target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialSources([]string{cls[0].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "another populated", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose)})),
setCredentialSources: []string{},
resultCredentialSourceIds: nil,
},
@@ -2363,13 +2364,13 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
},
{
name: "Remove 1 of 2 sources",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove partial", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeCredentialSources: []string{cls[1].GetPublicId()},
resultCredentialSourceIds: []string{cls[0].GetPublicId()},
},
{
name: "Remove 1 duplicate set of 2 sources",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove duplicate", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeCredentialSources: []string{
cls[1].GetPublicId(), cls[1].GetPublicId(),
},
@@ -2377,7 +2378,7 @@ func TestRemoveTargetCredentialSources(t *testing.T) {
},
{
name: "Remove all sources from target",
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialSources([]string{cls[0].GetPublicId(), cls[1].GetPublicId()})),
tar: tcp.TestTarget(t, conn, proj.GetPublicId(), "remove all", target.WithCredentialLibraries([]*target.CredentialLibrary{target.TestNewCredentialLibrary("", cls[0].GetPublicId(), credential.ApplicationPurpose), target.TestNewCredentialLibrary("", cls[1].GetPublicId(), credential.ApplicationPurpose)})),
removeCredentialSources: []string{
cls[0].GetPublicId(), cls[1].GetPublicId(),
},
+15 -8
View File
@@ -1649,21 +1649,28 @@ func testSessionCredentialParams(t *testing.T, conn *db.DB, wrapper wrapping.Wra
rw := db.New(conn)
ctx := context.Background()
stores := vault.TestCredentialStores(t, conn, wrapper, params.ScopeId, 1)
libs := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
kms := kms.TestKms(t, conn, wrapper)
targetRepo, err := target.NewRepository(rw, rw, kms)
require.NoError(err)
tcpTarget, _, _, err := targetRepo.LookupTarget(ctx, params.TargetId)
tar, _, _, err := targetRepo.LookupTarget(ctx, params.TargetId)
require.NoError(err)
require.NotNil(tcpTarget)
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tcpTarget.GetPublicId(), tcpTarget.GetVersion(), []string{libs[0].PublicId, libs[1].PublicId})
require.NotNil(tar)
stores := vault.TestCredentialStores(t, conn, wrapper, params.ScopeId, 1)
libIds := vault.TestCredentialLibraries(t, conn, wrapper, stores[0].GetPublicId(), 2)
libs := []*target.CredentialLibrary{
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.ApplicationPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[0].GetPublicId(), credential.IngressPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), libIds[1].GetPublicId(), credential.EgressPurpose),
}
_, _, _, err = targetRepo.AddTargetCredentialSources(ctx, tar.GetPublicId(), tar.GetVersion(), libs)
require.NoError(err)
creds := []*DynamicCredential{
NewDynamicCredential(libs[0].GetPublicId(), credential.ApplicationPurpose),
NewDynamicCredential(libs[0].GetPublicId(), credential.IngressPurpose),
NewDynamicCredential(libs[1].GetPublicId(), credential.EgressPurpose),
NewDynamicCredential(libIds[0].GetPublicId(), credential.ApplicationPurpose),
NewDynamicCredential(libIds[0].GetPublicId(), credential.IngressPurpose),
NewDynamicCredential(libIds[1].GetPublicId(), credential.EgressPurpose),
}
params.DynamicCredentials = creds
return params
+2 -2
View File
@@ -21,7 +21,7 @@ type CredentialLibrary struct {
// NewCredentialLibrary creates a new in memory CredentialLibrary
// representing the relationship between targetId and credentialLibraryId.
func NewCredentialLibrary(targetId, credentialLibraryId string, _ ...Option) (*CredentialLibrary, error) {
func NewCredentialLibrary(targetId, credentialLibraryId string, purpose credential.Purpose) (*CredentialLibrary, error) {
const op = "target.NewCredentialLibrary"
if targetId == "" {
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "no target id")
@@ -34,7 +34,7 @@ func NewCredentialLibrary(targetId, credentialLibraryId string, _ ...Option) (*C
CredentialLibrary: &store.CredentialLibrary{
TargetId: targetId,
CredentialLibraryId: credentialLibraryId,
CredentialPurpose: string(credential.ApplicationPurpose), // application is the only purpose currently supported
CredentialPurpose: string(purpose),
},
}
return t, nil
+1 -1
View File
@@ -55,7 +55,7 @@ func TestCredentialLibrary_New(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
got, err := target.NewCredentialLibrary(tt.args.targetId, tt.args.libraryId)
got, err := target.NewCredentialLibrary(tt.args.targetId, tt.args.libraryId, credential.ApplicationPurpose)
if tt.wantErr != 0 {
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
assert.Nil(got)
+5 -5
View File
@@ -30,7 +30,7 @@ type options struct {
WithUserId string
WithType subtypes.Subtype
WithHostSources []string
WithCredentialSources []string
WithCredentialLibraries []*CredentialLibrary
WithSessionMaxSeconds uint32
WithSessionConnectionLimit int32
WithPublicId string
@@ -49,7 +49,7 @@ func getDefaultOptions() options {
WithUserId: "",
WithType: "",
WithHostSources: nil,
WithCredentialSources: nil,
WithCredentialLibraries: nil,
WithSessionMaxSeconds: uint32((8 * time.Hour).Seconds()),
WithSessionConnectionLimit: 1,
WithPublicId: "",
@@ -129,10 +129,10 @@ func WithHostSources(hs []string) Option {
}
}
// WithCredentialSources provides an option for providing a list of credential source ids
func WithCredentialSources(cl []string) Option {
// WithCredentialLibraries provides an option for providing a list of credential libraries.
func WithCredentialLibraries(cl []*CredentialLibrary) Option {
return func(o *options) {
o.WithCredentialSources = cl
o.WithCredentialLibraries = cl
}
}
+31 -3
View File
@@ -3,6 +3,8 @@ package target
import (
"testing"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/types/subtypes"
"github.com/stretchr/testify/assert"
)
@@ -106,11 +108,37 @@ func Test_GetOpts(t *testing.T) {
testOpts.WithWorkerFilter = `"/foo" == "bar"`
assert.Equal(opts, testOpts)
})
t.Run("WithCredentialSources", func(t *testing.T) {
t.Run("WithCredentialLibraries", func(t *testing.T) {
assert := assert.New(t)
opts := GetOpts(WithCredentialSources([]string{"alice", "bob"}))
opts := GetOpts(WithCredentialLibraries([]*CredentialLibrary{
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "alice",
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "bob",
CredentialPurpose: string(credential.EgressPurpose),
},
},
}))
testOpts := getDefaultOptions()
testOpts.WithCredentialSources = []string{"alice", "bob"}
testOpts.WithCredentialLibraries = []*CredentialLibrary{
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "alice",
CredentialPurpose: string(credential.ApplicationPurpose),
},
},
{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: "bob",
CredentialPurpose: string(credential.EgressPurpose),
},
},
}
assert.Equal(opts, testOpts)
})
}
+2 -1
View File
@@ -13,7 +13,8 @@ current_libraries (library_id) as (
-- returns the current list
select credential_library_id
from target_credential_library
where target_id = @target_id
where target_id = @target_id
and credential_purpose = @purpose
),
keep_libraries (library_id) as (
-- returns the KEEP list
+79 -40
View File
@@ -6,17 +6,46 @@ import (
"fmt"
"strings"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target/store"
)
// credentialLibrariesPurposeMap is used to group CredentialLibraries by purpose.
type credentialLibrariesPurposeMap map[string][]*CredentialLibrary
func (c credentialLibrariesPurposeMap) add(cl *CredentialLibrary) {
var s []*CredentialLibrary
var ok bool
s, ok = c[cl.CredentialPurpose]
if !ok {
s = make([]*CredentialLibrary, 0, 1)
}
s = append(s, cl)
c[cl.CredentialPurpose] = s
}
func newCredentialLibrariesPurposeMap(cls []*CredentialLibrary) credentialLibrariesPurposeMap {
clpm := make(credentialLibrariesPurposeMap)
for _, p := range credential.ValidPurposes {
clpm[p.String()] = make([]*CredentialLibrary, 0)
}
for _, cl := range cls {
clpm.add(cl)
}
return clpm
}
// AddTargetCredentialSources adds the cIds to the targetId in the repository. The target
// and the list of credential sources attached to the target, after cIds are added,
// will be returned on success.
// The targetVersion must match the current version of the targetId in the repository.
func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cIds []string, _ ...Option) (Target, []HostSource, []CredentialSource, error) {
func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) (Target, []HostSource, []CredentialSource, error) {
const op = "target.(Repository).AddTargetCredentialSources"
if targetId == "" {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
@@ -24,16 +53,12 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
if targetVersion == 0 {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing version")
}
if len(cIds) == 0 {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential source ids")
if len(cls) == 0 {
return nil, nil, nil, errors.New(ctx, errors.InvalidParameter, op, "missing credential libraries")
}
addCredLibs := make([]interface{}, 0, len(cIds))
for _, id := range cIds {
cl, err := NewCredentialLibrary(targetId, id)
if err != nil {
return nil, nil, nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory credential library"))
}
addCredLibs := make([]interface{}, 0, len(cls))
for _, cl := range cls {
addCredLibs = append(addCredLibs, cl)
}
@@ -115,7 +140,7 @@ func (r *Repository) AddTargetCredentialSources(ctx context.Context, targetId st
// DeleteTargetCredentialSources deletes credential sources from a target in the repository.
// The target's current db version must match the targetVersion or an error will be returned.
func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, csIds []string, _ ...Option) (int, error) {
func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) (int, error) {
const op = "target.(Repository).DeleteTargetCredentialSources"
if targetId == "" {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
@@ -123,16 +148,12 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
if targetVersion == 0 {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
}
if len(csIds) == 0 {
if len(cls) == 0 {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing credential source ids")
}
deleteCredLibs := make([]interface{}, 0, len(csIds))
for _, id := range csIds {
cl, err := NewCredentialLibrary(targetId, id)
if err != nil {
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory credential library"))
}
deleteCredLibs := make([]interface{}, 0, len(cls))
for _, cl := range cls {
deleteCredLibs = append(deleteCredLibs, cl)
}
@@ -208,7 +229,7 @@ func (r *Repository) DeleteTargetCredentialSources(ctx context.Context, targetId
// SetTargetCredentialSources will set the target's credential sources. Set will add
// and/or delete credential sources as need to reconcile the existing credential sources
// with the request. If clIds is empty, all the credential sources will be cleared from the target.
func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, csIds []string, _ ...Option) ([]HostSource, []CredentialSource, int, error) {
func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId string, targetVersion uint32, cls []*CredentialLibrary, _ ...Option) ([]HostSource, []CredentialSource, int, error) {
const op = "target.(Repository).SetTargetCredentialSources"
if targetId == "" {
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing target id")
@@ -217,10 +238,18 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
return nil, nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
}
changes, err := r.changes(ctx, targetId, csIds)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
clpm := newCredentialLibrariesPurposeMap(cls)
var changes []*change
for purpose, cls := range clpm {
c, err := r.changes(ctx, targetId, cls, purpose)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
}
changes = append(changes, c...)
}
if len(changes) == 0 {
// Nothing needs to be changed, return early
hostSets, err := fetchHostSources(ctx, r.reader, targetId)
@@ -236,15 +265,11 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
var deleteCredLibs, addCredLibs []interface{}
for _, c := range changes {
cl, err := NewCredentialLibrary(targetId, c.LibraryId)
if err != nil {
return nil, nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create in memory target credential library"))
}
switch c.Action {
switch c.action {
case "delete":
deleteCredLibs = append(deleteCredLibs, cl)
deleteCredLibs = append(deleteCredLibs, c.credentialLibrary)
case "add":
addCredLibs = append(addCredLibs, cl)
addCredLibs = append(addCredLibs, c.credentialLibrary)
}
}
@@ -343,28 +368,33 @@ func (r *Repository) SetTargetCredentialSources(ctx context.Context, targetId st
}
type change struct {
action string
credentialLibrary *CredentialLibrary
}
type changeQueryResult struct {
Action string
LibraryId string
}
func (r *Repository) changes(ctx context.Context, targetId string, clIds []string) ([]*change, error) {
func (r *Repository) changes(ctx context.Context, targetId string, cls []*CredentialLibrary, purpose string) ([]*change, error) {
const op = "target.(Repository).changes"
// TODO ensure that all cls have the same purpose as the given purpose?
var inClauseSpots []string
// starts at 2 because there is already a @1 in the query
for i := 2; i < len(clIds)+2; i++ {
inClauseSpots = append(inClauseSpots, fmt.Sprintf("@%d", i))
var params []interface{}
params = append(params, sql.Named("target_id", targetId), sql.Named("purpose", purpose))
for idx, cl := range cls {
params = append(params, sql.Named(fmt.Sprintf("%d", idx+1), cl.CredentialLibraryId))
inClauseSpots = append(inClauseSpots, fmt.Sprintf("@%d", idx+1))
}
inClause := strings.Join(inClauseSpots, ",")
if inClause == "" {
inClause = "''"
}
query := fmt.Sprintf(setChangesQuery, inClause)
var params []interface{}
params = append(params, sql.Named("target_id", targetId))
for idx, id := range clIds {
params = append(params, sql.Named(fmt.Sprintf("%d", idx+2), id))
}
query := fmt.Sprintf(setChangesQuery, inClause)
rows, err := r.reader.Query(ctx, query, params)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("query failed"))
@@ -373,11 +403,20 @@ func (r *Repository) changes(ctx context.Context, targetId string, clIds []strin
var changes []*change
for rows.Next() {
var chg change
var chg changeQueryResult
if err := r.reader.ScanRows(rows, &chg); err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed"))
}
changes = append(changes, &chg)
changes = append(changes, &change{
action: chg.Action,
credentialLibrary: &CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
TargetId: targetId,
CredentialLibraryId: chg.LibraryId,
CredentialPurpose: purpose,
},
},
})
}
return changes, nil
}
@@ -0,0 +1,254 @@
package target_test
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/targettest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRepository_SetTargetCredentialSources(t *testing.T) {
target.Register(targettest.Subtype, targettest.Alloc, targettest.Vet, targettest.TargetPrefix)
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
wrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, conn, wrapper)
repo, err := target.NewRepository(rw, rw, testKms)
require.NoError(t, err)
iamRepo := iam.TestRepo(t, conn, wrapper)
_, proj := iam.TestScopes(t, iamRepo)
cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 2)
lib1 := credLibs[0]
lib2 := credLibs[1]
setupFn := func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) {
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10)
cls := make([]*target.CredentialLibrary, 0, len(credLibs))
for _, cl := range credLibs {
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
}
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(t, err)
require.Equal(t, 10, len(created))
return created, cls
}
type args struct {
targetVersion uint32
cls []*target.CredentialLibrary
addToOrigLibs bool
}
tests := []struct {
name string
setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary)
args args
wantAffectedRows int
wantErr bool
wantErrCode errors.Code
}{
{
name: "clear",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{},
},
wantErr: false,
wantAffectedRows: 10,
},
{
name: "no-change",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{},
addToOrigLibs: true,
},
wantErr: false,
wantAffectedRows: 0,
},
{
name: "add-cred-sources",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: false,
wantAffectedRows: 2,
},
{
name: "add-multiple-purposes",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: false,
wantAffectedRows: 3,
},
{
name: "remove-add-change-purpose",
setup: func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) {
cls := []*target.CredentialLibrary{
target.TestNewCredentialLibrary(tar.GetPublicId(), lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary(tar.GetPublicId(), lib2.PublicId, credential.ApplicationPurpose),
}
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(t, err)
require.Equal(t, 2, len(created))
return created, cls
},
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.EgressPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.EgressPurpose),
},
addToOrigLibs: false,
},
wantErr: false,
wantAffectedRows: 4,
},
{
name: "zero version",
setup: setupFn,
args: args{
targetVersion: 0,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: true,
wantErrCode: errors.InvalidParameter,
},
{
name: "bad version",
setup: setupFn,
args: args{
targetVersion: 1000,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: true,
},
wantErr: true,
wantErrCode: errors.VersionMismatch,
},
{
name: "remove existing and add cred libs",
setup: setupFn,
args: args{
targetVersion: 2,
cls: []*target.CredentialLibrary{
target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose),
target.TestNewCredentialLibrary("", lib2.PublicId, credential.ApplicationPurpose),
},
addToOrigLibs: false,
},
wantErr: false,
wantAffectedRows: 12,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tar := targettest.TestNewTestTarget(t, conn, proj.PublicId, tt.name)
var origCredSources []target.CredentialSource
var origCredLibraries []*target.CredentialLibrary
if tt.setup != nil {
origCredSources, origCredLibraries = tt.setup(tar)
}
wantCredSources := make(map[string]*target.CredentialLibrary)
for _, cl := range tt.args.cls {
cl.TargetId = tar.GetPublicId()
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl
}
if tt.args.addToOrigLibs {
tt.args.cls = append(tt.args.cls, origCredLibraries...)
for _, cl := range origCredLibraries {
wantCredSources[cl.CredentialLibraryId+"_"+cl.CredentialPurpose] = cl
}
}
origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
assert.Equal(origCredSources, lookupCredSources)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.cls)
if tt.wantErr {
require.Error(err)
assert.Equal(0, affectedRows)
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
return
}
t.Log(err)
require.NoError(err)
assert.Equal(tt.wantAffectedRows, affectedRows)
assert.Equal(len(wantCredSources), len(got))
for _, cs := range got {
w, ok := wantCredSources[cs.Id()+"_"+string(cs.CredentialPurpose())]
assert.True(ok, "got unexpected credentialsource %v", cs)
assert.Equal(w.CredentialLibraryId, cs.Id())
assert.Equal(w.CredentialPurpose, string(cs.CredentialPurpose()))
}
foundTarget, _, _, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
if tt.name != "no-change" {
assert.Equalf(tt.args.targetVersion+1, foundTarget.GetVersion(), "%s unexpected version: %d/%d", tt.name, tt.args.targetVersion+1, foundTarget.GetVersion())
assert.Equalf(origTarget.GetVersion(), foundTarget.GetVersion()-1, "%s unexpected version: %d/%d", tt.name, origTarget.GetVersion(), foundTarget.GetVersion()-1)
}
})
}
t.Run("missing-target-id", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
cl1 := target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
})
t.Run("target-not-found", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
})
}
@@ -0,0 +1,307 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: controller/storage/target/targettest/store/v1/target.proto
package store
import (
timestamp "github.com/hashicorp/boundary/internal/db/timestamp"
_ "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Target struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_id is used to access the targettest.Target via an API
// @inject_tag: gorm:"primary_key"
PublicId string `protobuf:"bytes,10,opt,name=public_id,json=publicId,proto3" json:"public_id,omitempty" gorm:"primary_key"`
// scope id for the targettest.Target
// @inject_tag: `gorm:"default:null"`
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty" gorm:"default:null"`
// name is the optional friendly name used to
// access the targettest.Target via an API
// @inject_tag: `gorm:"default:null"`
Name string `protobuf:"bytes,30,opt,name=name,proto3" json:"name,omitempty" gorm:"default:null"`
// description of the targettest.Target
// @inject_tag: `gorm:"default:null"`
Description string `protobuf:"bytes,40,opt,name=description,proto3" json:"description,omitempty" gorm:"default:null"`
// create_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
CreateTime *timestamp.Timestamp `protobuf:"bytes,50,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
// update_time from the RDBMS
// @inject_tag: `gorm:"default:current_timestamp"`
UpdateTime *timestamp.Timestamp `protobuf:"bytes,60,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty" gorm:"default:current_timestamp"`
// version allows optimistic locking of the targettest.Target when modifying the
// targettest.Target
// @inject_tag: `gorm:"default:null"`
Version uint32 `protobuf:"varint,70,opt,name=version,proto3" json:"version,omitempty" gorm:"default:null"`
// default port of the targettest.Target
// @inject_tag: `gorm:"default:null"`
DefaultPort uint32 `protobuf:"varint,80,opt,name=default_port,json=defaultPort,proto3" json:"default_port,omitempty" gorm:"default:null"`
// Maximum total lifetime of a created session, in seconds
// @inject_tag: `gorm:"default:null"`
SessionMaxSeconds uint32 `protobuf:"varint,100,opt,name=session_max_seconds,json=sessionMaxSeconds,proto3" json:"session_max_seconds,omitempty" gorm:"default:null"`
// Maximum number of connections in a session
// @inject_tag: `gorm:"default:null"`
SessionConnectionLimit int32 `protobuf:"varint,110,opt,name=session_connection_limit,json=sessionConnectionLimit,proto3" json:"session_connection_limit,omitempty" gorm:"default:null"`
// A boolean expression that allows filtering the workers that can handle a session
// @inject_tag: `gorm:"default:null"`
WorkerFilter string `protobuf:"bytes,120,opt,name=worker_filter,json=workerFilter,proto3" json:"worker_filter,omitempty" gorm:"default:null"`
}
func (x *Target) Reset() {
*x = Target{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Target) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Target) ProtoMessage() {}
func (x *Target) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Target.ProtoReflect.Descriptor instead.
func (*Target) Descriptor() ([]byte, []int) {
return file_controller_storage_target_targettest_store_v1_target_proto_rawDescGZIP(), []int{0}
}
func (x *Target) GetPublicId() string {
if x != nil {
return x.PublicId
}
return ""
}
func (x *Target) GetScopeId() string {
if x != nil {
return x.ScopeId
}
return ""
}
func (x *Target) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Target) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *Target) GetCreateTime() *timestamp.Timestamp {
if x != nil {
return x.CreateTime
}
return nil
}
func (x *Target) GetUpdateTime() *timestamp.Timestamp {
if x != nil {
return x.UpdateTime
}
return nil
}
func (x *Target) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *Target) GetDefaultPort() uint32 {
if x != nil {
return x.DefaultPort
}
return 0
}
func (x *Target) GetSessionMaxSeconds() uint32 {
if x != nil {
return x.SessionMaxSeconds
}
return 0
}
func (x *Target) GetSessionConnectionLimit() int32 {
if x != nil {
return x.SessionConnectionLimit
}
return 0
}
func (x *Target) GetWorkerFilter() string {
if x != nil {
return x.WorkerFilter
}
return ""
}
var File_controller_storage_target_targettest_store_v1_target_proto protoreflect.FileDescriptor
var file_controller_storage_target_targettest_store_v1_target_proto_rawDesc = []byte{
0x0a, 0x3a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x74, 0x61, 0x72, 0x67,
0x65, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f,
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2d, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x74, 0x65,
0x73, 0x74, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x2f, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f,
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x05, 0x0a, 0x06, 0x54, 0x61, 0x72,
0x67, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64,
0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75,
0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x2a, 0xc2,
0xdd, 0x29, 0x26, 0x0a, 0x0b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74,
0x12, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x66,
0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75,
0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5c, 0x0a, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x64, 0x20,
0x01, 0x28, 0x0d, 0x42, 0x2c, 0xc2, 0xdd, 0x29, 0x28, 0x0a, 0x11, 0x53, 0x65, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x13, 0x73, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64,
0x73, 0x52, 0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63,
0x6f, 0x6e, 0x64, 0x73, 0x12, 0x70, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74,
0x18, 0x6e, 0x20, 0x01, 0x28, 0x05, 0x42, 0x36, 0xc2, 0xdd, 0x29, 0x32, 0x0a, 0x16, 0x53, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c,
0x69, 0x6d, 0x69, 0x74, 0x12, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x16,
0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x46, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x78, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xc2,
0xdd, 0x29, 0x1d, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65,
0x72, 0x12, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x46,
0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f,
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_controller_storage_target_targettest_store_v1_target_proto_rawDescOnce sync.Once
file_controller_storage_target_targettest_store_v1_target_proto_rawDescData = file_controller_storage_target_targettest_store_v1_target_proto_rawDesc
)
func file_controller_storage_target_targettest_store_v1_target_proto_rawDescGZIP() []byte {
file_controller_storage_target_targettest_store_v1_target_proto_rawDescOnce.Do(func() {
file_controller_storage_target_targettest_store_v1_target_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_storage_target_targettest_store_v1_target_proto_rawDescData)
})
return file_controller_storage_target_targettest_store_v1_target_proto_rawDescData
}
var file_controller_storage_target_targettest_store_v1_target_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_controller_storage_target_targettest_store_v1_target_proto_goTypes = []interface{}{
(*Target)(nil), // 0: controller.storage.target.targettest.store.v1.Target
(*timestamp.Timestamp)(nil), // 1: controller.storage.timestamp.v1.Timestamp
}
var file_controller_storage_target_targettest_store_v1_target_proto_depIdxs = []int32{
1, // 0: controller.storage.target.targettest.store.v1.Target.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
1, // 1: controller.storage.target.targettest.store.v1.Target.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_controller_storage_target_targettest_store_v1_target_proto_init() }
func file_controller_storage_target_targettest_store_v1_target_proto_init() {
if File_controller_storage_target_targettest_store_v1_target_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_controller_storage_target_targettest_store_v1_target_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Target); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_storage_target_targettest_store_v1_target_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_controller_storage_target_targettest_store_v1_target_proto_goTypes,
DependencyIndexes: file_controller_storage_target_targettest_store_v1_target_proto_depIdxs,
MessageInfos: file_controller_storage_target_targettest_store_v1_target_proto_msgTypes,
}.Build()
File_controller_storage_target_targettest_store_v1_target_proto = out.File
file_controller_storage_target_targettest_store_v1_target_proto_rawDesc = nil
file_controller_storage_target_targettest_store_v1_target_proto_goTypes = nil
file_controller_storage_target_targettest_store_v1_target_proto_depIdxs = nil
}
+262
View File
@@ -0,0 +1,262 @@
// Package targettest provides a test target subtype for use by the target
// package. Note that it leverages the tcp.Target's database table to avoid
// needing schema migrations just for tests.
package targettest
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/targettest/store"
"github.com/hashicorp/boundary/internal/types/subtypes"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
const (
Subtype = subtypes.Subtype("tcp")
TargetPrefix = "ttcp"
)
// Target is a target.Target used for tests.
type Target struct {
*store.Target
tableName string `gorm:"-"`
}
var (
_ target.Target = (*Target)(nil)
_ db.VetForWriter = (*Target)(nil)
_ oplog.ReplayableMessage = (*Target)(nil)
)
// VetForWrite implements db.VetForWrite() interface and validates the tcp target
// before it's written.
func (t *Target) VetForWrite(ctx context.Context, _ db.Reader, opType db.OpType, _ ...db.Option) error {
const op = "target_test.(Target).VetForWrite"
if t.PublicId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing public id")
}
if opType == db.CreateOp {
if t.ScopeId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing scope id")
}
if t.Name == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing name")
}
}
return nil
}
// TableName returns the tablename to override the default gorm table name
func (t *Target) TableName() string {
if t.tableName != "" {
return t.tableName
}
return "target_tcp"
}
// SetTableName sets the tablename and satisfies the ReplayableMessage
// interface. If the caller attempts to set the name to "" the name will be
// reset to the default name.
func (t *Target) SetTableName(n string) {
t.tableName = n
}
func (t *Target) GetPublicId() string {
return t.PublicId
}
func (t *Target) GetScopeId() string {
return t.ScopeId
}
func (t *Target) GetDefaultPort() uint32 {
return t.DefaultPort
}
func (t *Target) GetName() string {
return t.Name
}
func (t *Target) GetDescription() string {
return t.Description
}
func (t *Target) GetVersion() uint32 {
return t.Version
}
func (t *Target) GetType() subtypes.Subtype {
return Subtype
}
func (t *Target) GetCreateTime() *timestamp.Timestamp {
return t.CreateTime
}
func (t *Target) GetUpdateTime() *timestamp.Timestamp {
return t.UpdateTime
}
func (t *Target) GetSessionMaxSeconds() uint32 {
return t.SessionMaxSeconds
}
func (t *Target) GetSessionConnectionLimit() int32 {
return t.SessionConnectionLimit
}
func (t *Target) GetWorkerFilter() string {
return t.WorkerFilter
}
func (t *Target) Clone() target.Target {
cp := proto.Clone(t.Target)
return &Target{
Target: cp.(*store.Target),
}
}
func (t *Target) SetPublicId(_ context.Context, publicId string) error {
t.PublicId = publicId
return nil
}
func (t *Target) SetScopeId(scopeId string) {
t.ScopeId = scopeId
}
func (t *Target) SetName(name string) {
t.Name = name
}
func (t *Target) SetDescription(description string) {
t.Description = description
}
func (t *Target) SetVersion(v uint32) {
t.Version = v
}
func (t *Target) SetDefaultPort(port uint32) {
t.DefaultPort = port
}
func (t *Target) SetCreateTime(ts *timestamp.Timestamp) {
t.CreateTime = ts
}
func (t *Target) SetUpdateTime(ts *timestamp.Timestamp) {
t.UpdateTime = ts
}
func (t *Target) SetSessionMaxSeconds(s uint32) {
t.SessionMaxSeconds = s
}
func (t *Target) SetSessionConnectionLimit(l int32) {
t.SessionConnectionLimit = l
}
func (t *Target) SetWorkerFilter(f string) {
t.WorkerFilter = f
}
func (t *Target) Oplog(op oplog.OpType) oplog.Metadata {
return oplog.Metadata{
"resource-public-id": []string{t.PublicId},
"resource-type": []string{"tcp target"},
"op-type": []string{op.String()},
"scope-id": []string{t.ScopeId},
}
}
// Alloc creates an in-memory Target.
func Alloc() target.Target {
return &Target{
Target: &store.Target{},
}
}
// Vet checks that the given Target is a targettest.Target and that it is not nil.
func Vet(ctx context.Context, t target.Target) error {
const op = "targettest.Vet"
tt, ok := t.(*Target)
if !ok {
return errors.New(ctx, errors.InvalidParameter, op, "target is not a tcp.Target")
}
if tt == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing target")
}
if tt.Target == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing target store")
}
return nil
}
// New creates a targettest.Target.
func New(scopeId string, opt ...target.Option) (*Target, error) {
const op = "target_test.New"
opts := target.GetOpts(opt...)
if scopeId == "" {
return nil, errors.NewDeprecated(errors.InvalidParameter, op, "missing scope id")
}
t := &Target{
Target: &store.Target{
ScopeId: scopeId,
Name: opts.WithName,
Description: opts.WithDescription,
DefaultPort: opts.WithDefaultPort,
SessionConnectionLimit: opts.WithSessionConnectionLimit,
SessionMaxSeconds: opts.WithSessionMaxSeconds,
WorkerFilter: opts.WithWorkerFilter,
},
}
return t, nil
}
// TestNewTestTarget is a test helper for creating a targettest.Target.
func TestNewTestTarget(t *testing.T, conn *db.DB, scopeId, name string, opt ...target.Option) *Target {
t.Helper()
opt = append(opt, target.WithName(name))
opts := target.GetOpts(opt...)
require := require.New(t)
rw := db.New(conn)
tar, err := New(scopeId, opt...)
require.NoError(err)
id, err := db.NewPublicId(TargetPrefix)
require.NoError(err)
tar.PublicId = id
err = rw.Create(context.Background(), tar)
require.NoError(err)
if len(opts.WithHostSources) > 0 {
newHostSets := make([]interface{}, 0, len(opts.WithHostSources))
for _, s := range opts.WithHostSources {
hostSet, err := target.NewTargetHostSet(tar.PublicId, s)
require.NoError(err)
newHostSets = append(newHostSets, hostSet)
}
err := rw.CreateItems(context.Background(), newHostSets)
require.NoError(err)
}
if len(opts.WithCredentialLibraries) > 0 {
newCredLibs := make([]interface{}, 0, len(opts.WithCredentialLibraries))
for _, cl := range opts.WithCredentialLibraries {
cl.TargetId = tar.PublicId
newCredLibs = append(newCredLibs, cl)
}
err := rw.CreateItems(context.Background(), newCredLibs)
require.NoError(err)
}
return tar
}
@@ -6,6 +6,7 @@ import (
"testing"
"time"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
@@ -106,7 +107,12 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
assert, require := assert.New(t), require.New(t)
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, tt.name)
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, tt.args.credLibIds)
credLibs := make([]*target.CredentialLibrary, 0, len(tt.args.credLibIds))
for _, clid := range tt.args.credLibIds {
credLibs = append(credLibs, target.TestNewCredentialLibrary(projTarget.PublicId, clid, credential.ApplicationPurpose))
}
gotTarget, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, tt.args.targetVersion, credLibs)
if tt.wantErr {
require.Error(err)
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
@@ -142,18 +148,22 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
assert, require := assert.New(t), require.New(t)
projTarget := tcp.TestTarget(t, conn, staticProj.PublicId, "add-existing")
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary(projTarget.PublicId, lib1.PublicId, credential.ApplicationPurpose)
cl2 := target.TestNewCredentialLibrary(projTarget.PublicId, lib2.PublicId, credential.ApplicationPurpose)
cl3 := target.TestNewCredentialLibrary(projTarget.PublicId, lib3.PublicId, credential.ApplicationPurpose)
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []*target.CredentialLibrary{cl1})
require.NoError(err)
assert.Len(gotCredSources, 1)
assert.Equal(lib1.PublicId, gotCredSources[0].Id())
// Adding lib1 again should error
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib1.PublicId})
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.True(errors.Match(errors.T(errors.NotUnique), err))
// Adding multiple with lib1 in set should error
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib3.PublicId, lib2.PublicId, lib1.PublicId})
_, _, _, err = repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl3, cl2, cl1})
require.Error(err)
assert.True(errors.Match(errors.T(errors.NotUnique), err))
@@ -166,7 +176,8 @@ func TestRepository_AddTargetCredentialSources(t *testing.T) {
t.Run("target-not-found", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, _, _, err := repo.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.AddTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
@@ -275,29 +286,29 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
assert, require := assert.New(t), require.New(t)
cs := css[i]
target := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
tar := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
clIds := make([]string, 0, tt.args.createCnt)
cls := make([]*target.CredentialLibrary, 0, tt.args.createCnt)
if tt.args.createCnt > 0 {
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.PublicId, tt.args.createCnt)
for _, cl := range credLibs {
clIds = append(clIds, cl.PublicId)
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
}
}
_, _, addedCredSources, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds)
_, _, addedCredSources, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(err)
assert.Equal(tt.args.createCnt, len(addedCredSources))
deleteCredSources := make([]string, 0, tt.args.deleteCnt)
deleteCredSources := make([]*target.CredentialLibrary, 0, tt.args.deleteCnt)
for i := 0; i < tt.args.deleteCnt; i++ {
deleteCredSources = append(deleteCredSources, clIds[i])
deleteCredSources = append(deleteCredSources, cls[i])
}
var targetId string
switch {
case tt.args.targetIdOverride != nil:
targetId = *tt.args.targetIdOverride
default:
targetId = target.GetPublicId()
targetId = tar.GetPublicId()
}
var targetVersion uint32
switch {
@@ -317,7 +328,7 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
assert.Equal(tt.wantRowsDeleted, deletedRows)
// we should find the oplog for the delete of target credential libraries
err = db.TestVerifyOplog(t, rw, target.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
err = db.TestVerifyOplog(t, rw, tar.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second))
assert.NoError(err)
})
}
@@ -333,18 +344,22 @@ func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
lib3 := libs[2]
projTarget := tcp.TestTarget(t, conn, proj.PublicId, "add-existing")
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []string{lib1.PublicId, lib2.PublicId})
cl1 := target.TestNewCredentialLibrary(projTarget.PublicId, lib1.PublicId, credential.ApplicationPurpose)
cl2 := target.TestNewCredentialLibrary(projTarget.PublicId, lib2.PublicId, credential.ApplicationPurpose)
cl3 := target.TestNewCredentialLibrary(projTarget.PublicId, lib3.PublicId, credential.ApplicationPurpose)
_, _, gotCredSources, err := repo.AddTargetCredentialSources(context.Background(), projTarget.PublicId, 1, []*target.CredentialLibrary{cl1, cl2})
require.NoError(err)
assert.Len(gotCredSources, 2)
// Deleting an unassociated source should return an error
delCount, err := repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib3.PublicId})
delCount, err := repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl3})
require.Error(err)
assert.True(errors.Match(errors.T(errors.MultipleRecords), err))
assert.Equal(0, delCount)
// Deleting sources which includes an unassociated source should return an error
delCount, err = repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []string{lib1.PublicId, lib2.PublicId, lib3.PublicId})
delCount, err = repo.DeleteTargetCredentialSources(context.Background(), projTarget.PublicId, 2, []*target.CredentialLibrary{cl1, cl2, cl3})
require.Error(err)
assert.True(errors.Match(errors.T(errors.MultipleRecords), err))
assert.Equal(0, delCount)
@@ -373,17 +388,17 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
lib1 := credLibs[0]
lib2 := credLibs[1]
setupFn := func(target target.Target) []target.CredentialSource {
setupFn := func(tar target.Target) ([]target.CredentialSource, []*target.CredentialLibrary) {
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10)
clIds := make([]string, 0, len(credLibs))
cls := make([]*target.CredentialLibrary, 0, len(credLibs))
for _, cl := range credLibs {
clIds = append(clIds, cl.PublicId)
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), cl.PublicId, credential.ApplicationPurpose))
}
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds)
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), tar.GetPublicId(), 1, cls)
require.NoError(t, err)
require.Equal(t, 10, len(created))
return created
return created, cls
}
type args struct {
targetVersion uint32
@@ -392,7 +407,7 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
}
tests := []struct {
name string
setup func(target.Target) []target.CredentialSource
setup func(target.Target) ([]target.CredentialSource, []*target.CredentialLibrary)
args args
wantAffectedRows int
wantErr bool
@@ -471,22 +486,29 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
tar := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
var origCredSources []target.CredentialSource
var origCredLibraries []*target.CredentialLibrary
if tt.setup != nil {
origCredSources = tt.setup(tar)
origCredSources, origCredLibraries = tt.setup(tar)
}
cls := make([]*target.CredentialLibrary, 0, len(tt.args.clIds))
for _, clid := range tt.args.clIds {
cls = append(cls, target.TestNewCredentialLibrary(tar.GetPublicId(), clid, credential.ApplicationPurpose))
}
var wantIds []string
wantIds = append(wantIds, tt.args.clIds...)
if tt.args.addToOrigLibs {
origIds := make([]string, 0, len(origCredSources))
for _, cl := range origCredSources {
origIds = append(origIds, cl.Id())
cls = append(cls, origCredLibraries...)
for _, cl := range origCredLibraries {
wantIds = append(wantIds, cl.CredentialLibraryId)
}
tt.args.clIds = append(tt.args.clIds, origIds...)
}
origTarget, _, lookupCredSources, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
require.NoError(err)
assert.Equal(origCredSources, lookupCredSources)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, tt.args.clIds)
_, got, affectedRows, err := repo.SetTargetCredentialSources(context.Background(), tar.GetPublicId(), tt.args.targetVersion, cls)
if tt.wantErr {
require.Error(err)
assert.Equal(0, affectedRows)
@@ -496,10 +518,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
t.Log(err)
require.NoError(err)
assert.Equal(tt.wantAffectedRows, affectedRows)
assert.Equal(len(tt.args.clIds), len(got))
var wantIds []string
wantIds = append(wantIds, tt.args.clIds...)
assert.Equal(len(wantIds), len(got))
sort.Strings(wantIds)
var gotIds []string
@@ -523,7 +543,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
t.Run("missing-target-id", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary("", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.InvalidParameter), err), "unexpected error %s", err.Error())
@@ -531,7 +552,8 @@ func TestRepository_SetTargetCredentialSources(t *testing.T) {
t.Run("target-not-found", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []string{lib1.PublicId})
cl1 := target.TestNewCredentialLibrary("fake-target-id", lib1.PublicId, credential.ApplicationPurpose)
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []*target.CredentialLibrary{cl1})
require.Error(err)
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
@@ -5,6 +5,7 @@ import (
"testing"
"time"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
dbassert "github.com/hashicorp/boundary/internal/db/assert"
@@ -14,6 +15,7 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/hashicorp/boundary/internal/target/tcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -39,9 +41,16 @@ func TestRepository_CreateTarget(t *testing.T) {
cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
credSources := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 2)
var clIds []string
var credLibraries []*target.CredentialLibrary
var credLibIds []string
for _, cl := range credSources {
clIds = append(clIds, cl.PublicId)
credLibraries = append(credLibraries, &target.CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: cl.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
})
credLibIds = append(credLibIds, cl.PublicId)
}
type args struct {
@@ -392,11 +401,22 @@ func TestRepository_UpdateTcpTarget(t *testing.T) {
cls := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 5)
var testClIds []string
var testCredLibs []*target.CredentialLibrary
for _, cl := range cls {
testCredLibs = append(testCredLibs, &target.CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
CredentialLibraryId: cl.PublicId,
CredentialPurpose: string(credential.ApplicationPurpose),
},
})
testClIds = append(testClIds, cl.PublicId)
}
tt.newTargetOpts = append(tt.newTargetOpts, target.WithHostSources(testHostSetIds), target.WithCredentialSources(testClIds))
tt.newTargetOpts = append(
tt.newTargetOpts,
target.WithHostSources(testHostSetIds),
target.WithCredentialLibraries(testCredLibs),
)
name := tt.newName
if name == "" {
name = tcp.TestId(t)
+5 -6
View File
@@ -36,12 +36,11 @@ func TestTarget(t *testing.T, conn *db.DB, scopeId, name string, opt ...target.O
err := rw.CreateItems(context.Background(), newHostSets)
require.NoError(err)
}
if len(opts.WithCredentialSources) > 0 {
newCredLibs := make([]interface{}, 0, len(opts.WithCredentialSources))
for _, cl := range opts.WithCredentialSources {
newCl, err := target.NewCredentialLibrary(tar.PublicId, cl)
require.NoError(err)
newCredLibs = append(newCredLibs, newCl)
if len(opts.WithCredentialLibraries) > 0 {
newCredLibs := make([]interface{}, 0, len(opts.WithCredentialLibraries))
for _, cl := range opts.WithCredentialLibraries {
cl.TargetId = tar.PublicId
newCredLibs = append(newCredLibs, cl)
}
err := rw.CreateItems(context.Background(), newCredLibs)
require.NoError(err)
+18 -4
View File
@@ -4,19 +4,33 @@ import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/target/store"
"github.com/stretchr/testify/require"
)
// TestNewCredentialLibrary creates a new in memory CredentialLibrary
// representing the relationship between targetId and credentialLibraryId with
// the given purpose.
func TestNewCredentialLibrary(targetId, credentialLibraryId string, purpose credential.Purpose) *CredentialLibrary {
return &CredentialLibrary{
CredentialLibrary: &store.CredentialLibrary{
TargetId: targetId,
CredentialLibraryId: credentialLibraryId,
CredentialPurpose: string(purpose),
},
}
}
// TestCredentialLibrary creates a CredentialLibrary for targetId and
// libraryId.
// libraryId with the credential purpose of application.
func TestCredentialLibrary(t *testing.T, conn *db.DB, targetId, libraryId string) *CredentialLibrary {
t.Helper()
require := require.New(t)
rw := db.New(conn)
lib, err := NewCredentialLibrary(targetId, libraryId)
require.NoError(err)
err = rw.Create(context.Background(), lib)
lib := TestNewCredentialLibrary(targetId, libraryId, credential.ApplicationPurpose)
err := rw.Create(context.Background(), lib)
require.NoError(err)
return lib
}