This moves all of the tcp target functionality into a tcp package. It also establishes a Register function in the target package to allow specific target types to be registered at initilazation time. When registering, a target type needs to provide its Subtype, as well as some RepositoryHooks that are used by the target Repository.
540 lines
16 KiB
Go
540 lines
16 KiB
Go
package tcp_test
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
|
|
"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/oplog"
|
|
"github.com/hashicorp/boundary/internal/target"
|
|
"github.com/hashicorp/boundary/internal/target/tcp"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func TestRepository_AddTargetCredentialSources(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
testKms := kms.TestKms(t, conn, wrapper)
|
|
iamRepo := iam.TestRepo(t, conn, wrapper)
|
|
_, staticProj := iam.TestScopes(t, iamRepo)
|
|
repo, err := target.NewRepository(rw, rw, testKms)
|
|
require.NoError(t, err)
|
|
|
|
cs := vault.TestCredentialStores(t, conn, wrapper, staticProj.GetPublicId(), 1)[0]
|
|
libs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 3)
|
|
require.Len(t, libs, 3)
|
|
lib1 := libs[0]
|
|
lib2 := libs[1]
|
|
lib3 := libs[2]
|
|
|
|
type args struct {
|
|
targetVersion uint32
|
|
credLibIds []string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantCredLibIds []string
|
|
wantErr bool
|
|
wantErrCode errors.Code
|
|
}{
|
|
{
|
|
name: "zero-version",
|
|
args: args{
|
|
targetVersion: 0,
|
|
},
|
|
wantErr: true,
|
|
wantErrCode: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "no-cred-sources",
|
|
args: args{
|
|
targetVersion: 1,
|
|
},
|
|
wantErr: true,
|
|
wantErrCode: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "valid-single-source",
|
|
args: args{
|
|
targetVersion: 1,
|
|
credLibIds: []string{lib1.PublicId},
|
|
},
|
|
wantCredLibIds: []string{lib1.PublicId},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "valid-multiple-sources",
|
|
args: args{
|
|
targetVersion: 1,
|
|
credLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId},
|
|
},
|
|
wantCredLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "invalid-source-id",
|
|
args: args{
|
|
targetVersion: 1,
|
|
credLibIds: []string{lib1.PublicId, lib2.PublicId, lib3.PublicId, "invalid-source-id"},
|
|
},
|
|
wantErr: true,
|
|
wantErrCode: errors.NotSpecificIntegrity,
|
|
},
|
|
{
|
|
name: "bad-version",
|
|
args: args{
|
|
targetVersion: 1000,
|
|
credLibIds: []string{lib1.PublicId},
|
|
},
|
|
wantErr: true,
|
|
wantErrCode: errors.VersionMismatch,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(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)
|
|
if tt.wantErr {
|
|
require.Error(err)
|
|
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Len(gotCredSources, len(tt.wantCredLibIds))
|
|
gotCredSourcesMap := map[string]target.CredentialSource{}
|
|
for _, s := range gotCredSources {
|
|
gotCredSourcesMap[s.Id()] = s
|
|
}
|
|
for _, id := range tt.wantCredLibIds {
|
|
assert.NotEmpty(gotCredSourcesMap[id])
|
|
}
|
|
|
|
// test to see of the target version update oplog was created
|
|
err = db.TestVerifyOplog(t, rw, projTarget.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.NoError(err)
|
|
|
|
tar, _, lookupCredSources, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
|
|
require.NoError(err)
|
|
assert.Equal(tt.args.targetVersion+1, tar.GetVersion())
|
|
assert.Equal(projTarget.GetVersion(), tar.GetVersion()-1)
|
|
assert.True(proto.Equal(gotTarget.(*tcp.Target), tar.(*tcp.Target)))
|
|
assert.Equal(gotCredSources, lookupCredSources)
|
|
for _, s := range lookupCredSources {
|
|
assert.NotEmpty(gotCredSourcesMap[s.Id()])
|
|
assert.Equal(projTarget.PublicId, s.TargetId())
|
|
}
|
|
})
|
|
}
|
|
t.Run("add-existing", func(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})
|
|
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})
|
|
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})
|
|
require.Error(err)
|
|
assert.True(errors.Match(errors.T(errors.NotUnique), err))
|
|
|
|
// Previous transactions should have been rolled back and only lib1 should be associated
|
|
_, _, lookupCredSources, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
|
|
require.NoError(err)
|
|
assert.Len(lookupCredSources, 1)
|
|
assert.Equal(lib1.PublicId, lookupCredSources[0].Id())
|
|
})
|
|
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})
|
|
|
|
require.Error(err)
|
|
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
|
|
})
|
|
}
|
|
|
|
func TestRepository_DeleteTargetCredentialSources(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
testKms := kms.TestKms(t, conn, wrapper)
|
|
iamRepo := iam.TestRepo(t, conn, wrapper)
|
|
_, proj := iam.TestScopes(t, iamRepo)
|
|
repo, err := target.NewRepository(rw, rw, testKms)
|
|
require.NoError(t, err)
|
|
|
|
type args struct {
|
|
targetIdOverride *string
|
|
targetVersionOverride *uint32
|
|
createCnt int
|
|
deleteCnt int
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantRowsDeleted int
|
|
wantErr bool
|
|
wantErrCode errors.Code
|
|
}{
|
|
{
|
|
name: "valid",
|
|
args: args{
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 5,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "valid-keeping-some",
|
|
args: args{
|
|
createCnt: 5,
|
|
deleteCnt: 2,
|
|
},
|
|
wantRowsDeleted: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "no-deletes",
|
|
args: args{
|
|
createCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
wantErrCode: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "not-found",
|
|
args: args{
|
|
targetIdOverride: func() *string { id := tcp.TestId(t); return &id }(),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
wantErrCode: errors.RecordNotFound,
|
|
},
|
|
{
|
|
name: "missing-target-id",
|
|
args: args{
|
|
targetIdOverride: func() *string { id := ""; return &id }(),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
wantErrCode: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "zero-version",
|
|
args: args{
|
|
targetVersionOverride: func() *uint32 { v := uint32(0); return &v }(),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
wantErrCode: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "bad-version",
|
|
args: args{
|
|
targetVersionOverride: func() *uint32 { v := uint32(1000); return &v }(),
|
|
createCnt: 5,
|
|
deleteCnt: 5,
|
|
},
|
|
wantRowsDeleted: 0,
|
|
wantErr: true,
|
|
wantErrCode: errors.VersionMismatch,
|
|
},
|
|
}
|
|
css := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), len(tests))
|
|
for i, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
cs := css[i]
|
|
|
|
target := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
|
|
|
|
clIds := make([]string, 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)
|
|
}
|
|
}
|
|
_, _, addedCredSources, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds)
|
|
require.NoError(err)
|
|
assert.Equal(tt.args.createCnt, len(addedCredSources))
|
|
|
|
deleteCredSources := make([]string, 0, tt.args.deleteCnt)
|
|
for i := 0; i < tt.args.deleteCnt; i++ {
|
|
deleteCredSources = append(deleteCredSources, clIds[i])
|
|
}
|
|
var targetId string
|
|
switch {
|
|
case tt.args.targetIdOverride != nil:
|
|
targetId = *tt.args.targetIdOverride
|
|
default:
|
|
targetId = target.GetPublicId()
|
|
}
|
|
var targetVersion uint32
|
|
switch {
|
|
case tt.args.targetVersionOverride != nil:
|
|
targetVersion = *tt.args.targetVersionOverride
|
|
default:
|
|
targetVersion = 2
|
|
}
|
|
deletedRows, err := repo.DeleteTargetCredentialSources(context.Background(), targetId, targetVersion, deleteCredSources)
|
|
if tt.wantErr {
|
|
require.Error(err)
|
|
assert.Equal(0, deletedRows)
|
|
assert.Truef(errors.Match(errors.T(tt.wantErrCode), err), "unexpected error %s", err.Error())
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
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))
|
|
assert.NoError(err)
|
|
})
|
|
}
|
|
t.Run("delete-unassociated", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
_, proj := iam.TestScopes(t, iamRepo)
|
|
cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
|
libs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 3)
|
|
require.Len(libs, 3)
|
|
lib1 := libs[0]
|
|
lib2 := libs[1]
|
|
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})
|
|
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})
|
|
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})
|
|
require.Error(err)
|
|
assert.True(errors.Match(errors.T(errors.MultipleRecords), err))
|
|
assert.Equal(0, delCount)
|
|
|
|
// Previous transactions should have been rolled back and only lib1 should be associated
|
|
_, _, lookupCredSources, err := repo.LookupTarget(context.Background(), projTarget.PublicId)
|
|
require.NoError(err)
|
|
assert.Len(lookupCredSources, 2)
|
|
})
|
|
}
|
|
|
|
func TestRepository_SetTargetCredentialSources(t *testing.T) {
|
|
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(target target.Target) []target.CredentialSource {
|
|
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 10)
|
|
clIds := make([]string, 0, len(credLibs))
|
|
for _, cl := range credLibs {
|
|
clIds = append(clIds, cl.PublicId)
|
|
}
|
|
|
|
_, _, created, err := repo.AddTargetCredentialSources(context.Background(), target.GetPublicId(), 1, clIds)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 10, len(created))
|
|
return created
|
|
}
|
|
type args struct {
|
|
targetVersion uint32
|
|
clIds []string
|
|
addToOrigLibs bool
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
setup func(target.Target) []target.CredentialSource
|
|
args args
|
|
wantAffectedRows int
|
|
wantErr bool
|
|
wantErrCode errors.Code
|
|
}{
|
|
{
|
|
name: "clear",
|
|
setup: setupFn,
|
|
args: args{
|
|
targetVersion: 2,
|
|
clIds: []string{},
|
|
},
|
|
wantErr: false,
|
|
wantAffectedRows: 10,
|
|
},
|
|
{
|
|
name: "no-change",
|
|
setup: setupFn,
|
|
args: args{
|
|
targetVersion: 2,
|
|
clIds: []string{},
|
|
addToOrigLibs: true,
|
|
},
|
|
wantErr: false,
|
|
wantAffectedRows: 0,
|
|
},
|
|
{
|
|
name: "add-cred-sources",
|
|
setup: setupFn,
|
|
args: args{
|
|
targetVersion: 2,
|
|
clIds: []string{lib1.PublicId, lib2.PublicId},
|
|
addToOrigLibs: true,
|
|
},
|
|
wantErr: false,
|
|
wantAffectedRows: 2,
|
|
},
|
|
{
|
|
name: "zero version",
|
|
setup: setupFn,
|
|
args: args{
|
|
targetVersion: 0,
|
|
clIds: []string{lib1.PublicId, lib2.PublicId},
|
|
addToOrigLibs: true,
|
|
},
|
|
wantErr: true,
|
|
wantErrCode: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "bad version",
|
|
setup: setupFn,
|
|
args: args{
|
|
targetVersion: 1000,
|
|
clIds: []string{lib1.PublicId, lib2.PublicId},
|
|
addToOrigLibs: true,
|
|
},
|
|
wantErr: true,
|
|
wantErrCode: errors.VersionMismatch,
|
|
},
|
|
{
|
|
name: "remove existing and add cred libs",
|
|
setup: setupFn,
|
|
args: args{
|
|
targetVersion: 2,
|
|
clIds: []string{lib1.PublicId, lib2.PublicId},
|
|
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 := tcp.TestTarget(t, conn, proj.PublicId, tt.name)
|
|
|
|
var origCredSources []target.CredentialSource
|
|
if tt.setup != nil {
|
|
origCredSources = tt.setup(tar)
|
|
}
|
|
if tt.args.addToOrigLibs {
|
|
origIds := make([]string, 0, len(origCredSources))
|
|
for _, cl := range origCredSources {
|
|
origIds = append(origIds, cl.Id())
|
|
}
|
|
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)
|
|
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(tt.args.clIds), len(got))
|
|
|
|
var wantIds []string
|
|
wantIds = append(wantIds, tt.args.clIds...)
|
|
sort.Strings(wantIds)
|
|
|
|
var gotIds []string
|
|
if len(got) > 0 {
|
|
gotIds = make([]string, 0, len(got))
|
|
for _, s := range got {
|
|
gotIds = append(gotIds, s.Id())
|
|
}
|
|
}
|
|
sort.Strings(gotIds)
|
|
assert.Equal(wantIds, gotIds)
|
|
|
|
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)
|
|
|
|
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "", 1, []string{lib1.PublicId})
|
|
|
|
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)
|
|
|
|
_, _, _, err := repo.SetTargetCredentialSources(context.Background(), "fake-target-id", 1, []string{lib1.PublicId})
|
|
|
|
require.Error(err)
|
|
assert.Truef(errors.Match(errors.T(errors.RecordNotFound), err), "unexpected error %s", err.Error())
|
|
})
|
|
}
|