mirror of https://github.com/hashicorp/boundary
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
924 lines
28 KiB
924 lines
28 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package tcp_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/globals"
|
|
talias "github.com/hashicorp/boundary/internal/alias/target"
|
|
"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"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/host/static"
|
|
"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/store"
|
|
"github.com/hashicorp/boundary/internal/target/tcp"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func TestRepository_CreateTarget(t *testing.T) {
|
|
t.Parallel()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
testKms := kms.TestKms(t, conn, wrapper)
|
|
|
|
ctx := context.Background()
|
|
repo, err := target.NewRepository(ctx, rw, rw, testKms)
|
|
require.NoError(t, err)
|
|
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
|
|
cats := static.TestCatalogs(t, conn, proj.PublicId, 1)
|
|
static.TestSets(t, conn, cats[0].GetPublicId(), 2)
|
|
|
|
cs := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), 1)[0]
|
|
vault.TestCredentialLibraries(t, conn, wrapper, cs.GetPublicId(), 2)
|
|
|
|
type args struct {
|
|
target target.Target
|
|
opt []target.Option
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantErr bool
|
|
wantAddress string
|
|
wantIsError errors.Code
|
|
}{
|
|
{
|
|
name: "valid-org",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("valid-org"),
|
|
target.WithDescription("valid-org"),
|
|
target.WithDefaultPort(uint32(22)))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "with-dns-name",
|
|
args: args{
|
|
target: func() *tcp.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-dns-name"),
|
|
target.WithDescription("with-dns-name"),
|
|
target.WithDefaultPort(uint32(22)),
|
|
target.WithAddress("www.google.com"),
|
|
)
|
|
require.NoError(t, err)
|
|
return target.(*tcp.Target)
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
wantAddress: "www.google.com",
|
|
},
|
|
{
|
|
name: "with-ipv4-address",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-ipv4-address"),
|
|
target.WithDescription("with-ipv4-address"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("8.8.8.8"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
wantAddress: "8.8.8.8",
|
|
},
|
|
{
|
|
name: "with-invalid-ipv4-address-with-port",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-invalid-ipv4-address-with-port"),
|
|
target.WithDescription("with-invalid-ipv4-address-with-port"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("8.8.8.8:80"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidAddress,
|
|
},
|
|
{
|
|
name: "with-abbreviated-ipv6-address",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-abbreviated-ipv6-address"),
|
|
target.WithDescription("with-abbreviated-ipv6-address"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("2001:4860:4860::8888"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
wantAddress: "2001:4860:4860::8888",
|
|
},
|
|
{
|
|
name: "with-ipv6-address",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-ipv6-address"),
|
|
target.WithDescription("with-ipv6-address"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("2001:4860:4860:0:0:0:0:8888"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
wantAddress: "2001:4860:4860::8888",
|
|
},
|
|
{
|
|
name: "with-abbreviated-[ipv6]-address",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-abbreviated-[ipv6]-address"),
|
|
target.WithDescription("with-abbreviated-[ipv6]-address"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("[2001:4860:4860::8888]"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
wantAddress: "2001:4860:4860::8888",
|
|
},
|
|
{
|
|
name: "with-invalid-abbreviated-[ipv6]-address-with-port",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-invalid-abbreviated-[ipv6]-address-with-port"),
|
|
target.WithDescription("with-invalid-abbreviated-[ipv6]-address-with-port"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("[2001:4860:4860::8888]:80"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidAddress,
|
|
},
|
|
{
|
|
name: "with-[ipv6]-address",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-[ipv6]-address"),
|
|
target.WithDescription("with-[ipv6]-address"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("[2001:4860:4860:0:0:0:0:8888]"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
wantAddress: "2001:4860:4860:0:0:0:0:8888",
|
|
},
|
|
{
|
|
name: "with-invalid-[ipv6]-address-with-port",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-invalid-[ipv6]-address-with-port"),
|
|
target.WithDescription("with-invalid-[ipv6]-address-with-port"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress("[2001:4860:4860:0:0:0:0:8888]:80"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidAddress,
|
|
},
|
|
{
|
|
name: "with-address-whitespace",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("with-address-whitespace"),
|
|
target.WithDescription("with-address-whitespace"),
|
|
target.WithDefaultPort(80),
|
|
target.WithAddress(" 8.8.8.8 "))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
wantAddress: "8.8.8.8",
|
|
},
|
|
{
|
|
name: "nil-target",
|
|
args: args{
|
|
target: nil,
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "nil-target-store",
|
|
args: args{
|
|
target: func() *tcp.Target {
|
|
target := &tcp.Target{}
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "public-id-not-empty",
|
|
args: args{
|
|
target: func() target.Target {
|
|
tar, err := target.New(
|
|
ctx,
|
|
tcp.Subtype,
|
|
proj.PublicId,
|
|
target.WithName("valid-org"),
|
|
target.WithDescription("valid-org"),
|
|
target.WithDefaultPort(uint32(22)),
|
|
)
|
|
require.NoError(t, err)
|
|
id, err := db.NewPublicId(ctx, globals.TcpTargetPrefix)
|
|
require.NoError(t, err)
|
|
tar.SetPublicId(ctx, id)
|
|
return tar
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "empty-project-id",
|
|
args: args{
|
|
target: func() target.Target {
|
|
tar, err := target.New(
|
|
ctx,
|
|
tcp.Subtype,
|
|
proj.PublicId,
|
|
target.WithName("empty-project-id"),
|
|
)
|
|
require.NoError(t, err)
|
|
tar.SetProjectId("")
|
|
return tar
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidParameter,
|
|
},
|
|
{
|
|
name: "valid-with-egress-filter",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("valid-egress-filter"),
|
|
target.WithDescription("valid-org"),
|
|
target.WithDefaultPort(uint32(22)),
|
|
target.WithEgressWorkerFilter("test-filter"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "deprecated-worker-filter",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("bad-worker-filter"),
|
|
target.WithDescription("valid-org"),
|
|
target.WithDefaultPort(uint32(22)),
|
|
target.WithWorkerFilter("test-filter"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.Exception,
|
|
},
|
|
{
|
|
name: "invalid-setting-egress-and-worker-filter",
|
|
args: args{
|
|
target: func() target.Target {
|
|
target, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("bad-filters"),
|
|
target.WithDescription("valid-org"),
|
|
target.WithDefaultPort(uint32(22)),
|
|
target.WithWorkerFilter("test-filter"),
|
|
target.WithEgressWorkerFilter("test-filter"))
|
|
require.NoError(t, err)
|
|
return target
|
|
}(),
|
|
},
|
|
wantErr: true,
|
|
wantIsError: errors.Exception,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
tar, err := repo.CreateTarget(context.Background(), tt.args.target, tt.args.opt...)
|
|
if tt.wantErr {
|
|
assert.Error(err)
|
|
assert.Nil(tar)
|
|
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.NotNil(tar.GetPublicId())
|
|
|
|
hostSources := tar.GetHostSources()
|
|
credSources := tar.GetCredentialSources()
|
|
|
|
foundTarget, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
|
|
foundHostSources := foundTarget.GetHostSources()
|
|
foundCredLibs := foundTarget.GetCredentialSources()
|
|
|
|
assert.NoError(err)
|
|
if len(tt.wantAddress) != 0 {
|
|
assert.Equal(tt.wantAddress, tar.GetAddress())
|
|
} else {
|
|
assert.Equal(tt.args.target.GetAddress(), tar.GetAddress())
|
|
}
|
|
assert.True(proto.Equal(tar.(*tcp.Target), foundTarget.(*tcp.Target)))
|
|
assert.Equal(hostSources, foundHostSources)
|
|
assert.Equal(credSources, foundCredLibs)
|
|
|
|
err = db.TestVerifyOplog(t, rw, tar.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.NoError(err)
|
|
|
|
// TODO (jimlambrt 9/2020) - unfortunately, we can currently
|
|
// test to make sure that the oplog entry for a target host sets
|
|
// create exist because the db.TestVerifyOplog doesn't really
|
|
// support that level of testing and the previous call to
|
|
// CreateTarget would create an oplog entry for the
|
|
// create on the target even if no host sets were added. Once
|
|
// TestVerifyOplog supports the appropriate granularity, we should
|
|
// add an appropriate assert.
|
|
})
|
|
}
|
|
|
|
t.Run("create with aliases", func(t *testing.T) {
|
|
newAlias1, err := talias.NewAlias(context.Background(), "global", "alias1", talias.WithHostId("hst_1234567890"))
|
|
require.NoError(t, err)
|
|
newAlias2, err := talias.NewAlias(context.Background(), "global", "alias2", talias.WithHostId("hst_0987654321"))
|
|
require.NoError(t, err)
|
|
|
|
tar, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("create-with-alias"),
|
|
target.WithDescription("create-with-alias"),
|
|
target.WithDefaultPort(uint32(22)))
|
|
require.NoError(t, err)
|
|
tar, err = repo.CreateTarget(context.Background(), tar, target.WithAliases([]*talias.Alias{newAlias1, newAlias2}))
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, tar)
|
|
assert.Len(t, tar.GetAliases(), 2)
|
|
assert.NotEmpty(t, tar.GetAliases()[0].GetPublicId())
|
|
assert.NotEmpty(t, tar.GetAliases()[1].GetPublicId())
|
|
assert.NotZero(t, tar.GetAliases()[0].GetCreateTime())
|
|
assert.NotZero(t, tar.GetAliases()[1].GetCreateTime())
|
|
assert.Contains(t, []string{newAlias1.GetValue(), newAlias2.GetValue()}, tar.GetAliases()[0].GetValue())
|
|
assert.Contains(t, []string{newAlias1.GetValue(), newAlias2.GetValue()}, tar.GetAliases()[1].GetValue())
|
|
assert.Contains(t, []string{newAlias1.GetHostId(), newAlias2.GetHostId()}, tar.GetAliases()[0].GetHostId())
|
|
assert.Contains(t, []string{newAlias1.GetHostId(), newAlias2.GetHostId()}, tar.GetAliases()[1].GetHostId())
|
|
})
|
|
|
|
t.Run("create an invalid aliases", func(t *testing.T) {
|
|
invalidAlias, err := talias.NewAlias(context.Background(), "global", "invalid_alias")
|
|
require.NoError(t, err)
|
|
|
|
tar, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("create-with-invalid-alias"),
|
|
target.WithDescription("create-with-invalid-alias"),
|
|
target.WithDefaultPort(uint32(22)))
|
|
require.NoError(t, err)
|
|
tar, err = repo.CreateTarget(context.Background(), tar, target.WithAliases([]*talias.Alias{invalidAlias}))
|
|
require.Error(t, err)
|
|
require.Nil(t, tar)
|
|
})
|
|
|
|
t.Run("create with duplicate aliases", func(t *testing.T) {
|
|
dupAlias, err := talias.NewAlias(context.Background(), "global", "dup-alias")
|
|
require.NoError(t, err)
|
|
|
|
tar, err := target.New(ctx, tcp.Subtype, proj.PublicId,
|
|
target.WithName("create-with-duplicate-alias"),
|
|
target.WithDescription("create-with-duplicate-alias"),
|
|
target.WithDefaultPort(uint32(22)))
|
|
require.NoError(t, err)
|
|
tar, err = repo.CreateTarget(context.Background(), tar, target.WithAliases([]*talias.Alias{dupAlias, dupAlias}))
|
|
require.Error(t, err)
|
|
require.Nil(t, tar)
|
|
})
|
|
}
|
|
|
|
func TestRepository_UpdateTcpTarget(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(context.Background(), rw, rw, testKms)
|
|
require.NoError(t, err)
|
|
id := tcp.TestId(t)
|
|
|
|
iamRepo := iam.TestRepo(t, conn, wrapper)
|
|
_, proj := iam.TestScopes(t, iamRepo)
|
|
pubId := func(s string) *string { return &s }
|
|
|
|
type args struct {
|
|
name string
|
|
description string
|
|
address string
|
|
port uint32
|
|
fieldMaskPaths []string
|
|
opt []target.Option
|
|
ProjectId string
|
|
PublicId *string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
newProjectId string
|
|
newName string
|
|
newTargetOpts []target.Option
|
|
args args
|
|
wantRowsUpdate int
|
|
wantErr bool
|
|
wantErrMsg string
|
|
wantIsError errors.Code
|
|
wantDup bool
|
|
wantHostSources bool
|
|
wantAddress string
|
|
}{
|
|
{
|
|
name: "valid",
|
|
args: args{
|
|
name: "valid" + id,
|
|
fieldMaskPaths: []string{"Name"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "valid-ipv4-address",
|
|
args: args{
|
|
name: "valid-ipv4-address" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "8.8.8.8",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
wantAddress: "8.8.8.8",
|
|
},
|
|
{
|
|
name: "invalid-ipv4-address-with-port",
|
|
args: args{
|
|
name: "invalid-ipv4-address-with-port" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "8.8.8.8:80",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidAddress,
|
|
wantErrMsg: "invalid address",
|
|
},
|
|
{
|
|
name: "valid-abbreviated-ipv6-address",
|
|
args: args{
|
|
name: "valid-abbreviated-ipv6-address" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "2001:4860:4860::8888",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
wantAddress: "2001:4860:4860::8888",
|
|
},
|
|
{
|
|
name: "valid-ipv6-address",
|
|
args: args{
|
|
name: "valid-ipv6-address" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "2001:4860:4860:0:0:0:0:8888",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
wantAddress: "2001:4860:4860::8888",
|
|
},
|
|
{
|
|
name: "valid-abbreviated-[ipv6]-address",
|
|
args: args{
|
|
name: "valid-abbreviated-[ipv6]-address" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "[2001:4860:4860::8888]",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
wantAddress: "2001:4860:4860::8888",
|
|
},
|
|
{
|
|
name: "invalid-abbreviated-[ipv6]-address-with-port",
|
|
args: args{
|
|
name: "invalid-abbreviated-[ipv6]-address-with-port" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "[2001:4860:4860::8888]:80",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidAddress,
|
|
wantErrMsg: "invalid address",
|
|
},
|
|
{
|
|
name: "valid-[ipv6]-address",
|
|
args: args{
|
|
name: "valid-[ipv6]-address" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "[2001:4860:4860:0:0:0:0:8888]",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
wantAddress: "2001:4860:4860:0:0:0:0:8888",
|
|
},
|
|
{
|
|
name: "invalid-[ipv6]-address-with-port",
|
|
args: args{
|
|
name: "invalid-[ipv6]-address-with-port" + id,
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "[2001:4860:4860:0:0:0:0:8888]:80",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantIsError: errors.InvalidAddress,
|
|
wantErrMsg: "invalid address",
|
|
},
|
|
{
|
|
name: "null-address",
|
|
args: args{
|
|
fieldMaskPaths: []string{"Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: "null",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
newTargetOpts: []target.Option{target.WithAddress("8.8.8.8")},
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
},
|
|
{
|
|
name: "address-with-whitespace",
|
|
args: args{
|
|
fieldMaskPaths: []string{"Address"},
|
|
ProjectId: proj.PublicId,
|
|
address: " 127.0.0.1 ",
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
newTargetOpts: []target.Option{target.WithAddress("10.0.0.1")},
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
wantAddress: "127.0.0.1",
|
|
},
|
|
{
|
|
name: "delete-address",
|
|
args: args{
|
|
fieldMaskPaths: []string{"Address"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
newTargetOpts: []target.Option{target.WithAddress("8.8.8.8")},
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: false,
|
|
},
|
|
{
|
|
name: "host-source-mutually-exclusive-relationship",
|
|
args: args{
|
|
name: "invalid-address" + id,
|
|
address: "8.8.8.8",
|
|
fieldMaskPaths: []string{"Name", "Address"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantErrMsg: "unable to set address because one or more host sources is assigned to the given target",
|
|
wantRowsUpdate: 0,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "valid-no-op",
|
|
args: args{
|
|
name: "valid-no-op" + id,
|
|
fieldMaskPaths: []string{"Name"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
newName: "valid-no-op" + id,
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "not-found",
|
|
args: args{
|
|
name: "not-found" + id,
|
|
fieldMaskPaths: []string{"Name"},
|
|
ProjectId: proj.PublicId,
|
|
PublicId: func() *string { s := "1"; return &s }(),
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantRowsUpdate: 0,
|
|
wantErrMsg: "record not found, search issue: error #1100",
|
|
wantIsError: errors.RecordNotFound,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "null-name",
|
|
args: args{
|
|
name: "",
|
|
fieldMaskPaths: []string{"Name"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
newName: "null-name" + id,
|
|
wantErr: true,
|
|
wantRowsUpdate: 0,
|
|
wantErrMsg: "db.DoTx: target.(Repository).UpdateTarget: db.Update: name must not be empty: not null constraint violated: integrity violation: error #1001",
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "null-description",
|
|
args: args{
|
|
name: "null-description",
|
|
fieldMaskPaths: []string{"Description"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
newTargetOpts: []target.Option{target.WithDescription("null-description" + id)},
|
|
wantErr: false,
|
|
wantRowsUpdate: 1,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "empty-field-mask",
|
|
args: args{
|
|
name: "valid" + id,
|
|
fieldMaskPaths: []string{},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantRowsUpdate: 0,
|
|
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
|
wantIsError: errors.EmptyFieldMask,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "nil-fieldmask",
|
|
args: args{
|
|
name: "valid" + id,
|
|
fieldMaskPaths: nil,
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantRowsUpdate: 0,
|
|
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
|
wantIsError: errors.EmptyFieldMask,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "read-only-fields",
|
|
args: args{
|
|
name: "valid" + id,
|
|
fieldMaskPaths: []string{"CreateTime"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantRowsUpdate: 0,
|
|
wantErrMsg: "target.(Repository).UpdateTarget: invalid field mask: CreateTime: parameter violation: error #103",
|
|
wantIsError: errors.InvalidFieldMask,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "unknown-fields",
|
|
args: args{
|
|
name: "valid" + id,
|
|
fieldMaskPaths: []string{"Alice"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantRowsUpdate: 0,
|
|
wantErrMsg: "target.(Repository).UpdateTarget: invalid field mask: Alice: parameter violation: error #103",
|
|
wantIsError: errors.InvalidFieldMask,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "no-public-id",
|
|
args: args{
|
|
name: "valid" + id,
|
|
fieldMaskPaths: []string{"Name"},
|
|
ProjectId: proj.PublicId,
|
|
PublicId: pubId(""),
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantErrMsg: "target.(Repository).UpdateTarget: missing target public id: parameter violation: error #100",
|
|
wantIsError: errors.InvalidParameter,
|
|
wantRowsUpdate: 0,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "project-id-no-mask",
|
|
args: args{
|
|
name: "project-id" + id,
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantErrMsg: "target.(Repository).UpdateTarget: empty field mask: parameter violation: error #104",
|
|
wantIsError: errors.EmptyFieldMask,
|
|
wantHostSources: true,
|
|
},
|
|
{
|
|
name: "dup-name",
|
|
args: args{
|
|
name: "dup-name" + id,
|
|
fieldMaskPaths: []string{"Name"},
|
|
ProjectId: proj.PublicId,
|
|
},
|
|
newProjectId: proj.PublicId,
|
|
wantErr: true,
|
|
wantDup: true,
|
|
wantErrMsg: " already exists in project " + proj.PublicId,
|
|
wantIsError: errors.NotUnique,
|
|
wantHostSources: true,
|
|
},
|
|
}
|
|
css := vault.TestCredentialStores(t, conn, wrapper, proj.GetPublicId(), len(tests))
|
|
for i, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cs := css[i]
|
|
require, assert := require.New(t), assert.New(t)
|
|
ctx := context.Background()
|
|
if tt.wantDup {
|
|
_ = tcp.TestTarget(ctx, t, conn, proj.PublicId, tt.args.name)
|
|
}
|
|
|
|
testHostSetIds := []string{}
|
|
if tt.wantHostSources {
|
|
testCats := static.TestCatalogs(t, conn, proj.PublicId, 1)
|
|
hsets := static.TestSets(t, conn, testCats[0].GetPublicId(), 5)
|
|
testHostSetIds = make([]string, 0, len(hsets))
|
|
for _, hs := range hsets {
|
|
testHostSetIds = append(testHostSetIds, hs.PublicId)
|
|
}
|
|
tt.newTargetOpts = append(
|
|
tt.newTargetOpts,
|
|
target.WithHostSources(testHostSetIds),
|
|
)
|
|
}
|
|
|
|
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.BrokeredPurpose),
|
|
},
|
|
})
|
|
testClIds = append(testClIds, cl.PublicId)
|
|
}
|
|
|
|
tt.newTargetOpts = append(
|
|
tt.newTargetOpts,
|
|
target.WithCredentialLibraries(testCredLibs),
|
|
)
|
|
name := tt.newName
|
|
if name == "" {
|
|
name = tcp.TestId(t)
|
|
}
|
|
tar := tcp.TestTarget(ctx, t, conn, tt.newProjectId, name, tt.newTargetOpts...)
|
|
updateTarget := tcp.NewTestTarget(
|
|
ctx,
|
|
tt.args.ProjectId,
|
|
target.WithName(tt.args.name),
|
|
target.WithDescription(tt.args.description),
|
|
target.WithDefaultPort(tt.args.port),
|
|
target.WithAddress(tt.args.address),
|
|
)
|
|
updateTarget.SetPublicId(ctx, tar.GetPublicId())
|
|
if tt.args.PublicId != nil {
|
|
ut := updateTarget.(*tcp.Target)
|
|
ut.PublicId = *tt.args.PublicId
|
|
}
|
|
|
|
targetAfterUpdate, updatedRows, err := repo.UpdateTarget(ctx, updateTarget, tar.GetVersion(), tt.args.fieldMaskPaths, tt.args.opt...)
|
|
if tt.wantErr {
|
|
assert.Error(err)
|
|
assert.True(errors.Match(errors.T(tt.wantIsError), err))
|
|
assert.Nil(targetAfterUpdate)
|
|
assert.Equal(0, updatedRows)
|
|
assert.NotEmpty(err.Error())
|
|
assert.Contains(err.Error(), tt.wantErrMsg)
|
|
err = db.TestVerifyOplog(t, rw, tar.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.Error(err)
|
|
assert.True(errors.IsNotFoundError(err))
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
require.NotNil(targetAfterUpdate)
|
|
assert.Equal(tt.wantRowsUpdate, updatedRows)
|
|
|
|
hostSources := targetAfterUpdate.GetHostSources()
|
|
credSources := targetAfterUpdate.GetCredentialSources()
|
|
afterUpdateIds := make([]string, 0, len(hostSources))
|
|
for _, hs := range hostSources {
|
|
afterUpdateIds = append(afterUpdateIds, hs.Id())
|
|
}
|
|
assert.Equal(testHostSetIds, afterUpdateIds)
|
|
if len(tt.wantAddress) != 0 {
|
|
assert.Equal(tt.wantAddress, targetAfterUpdate.GetAddress())
|
|
} else {
|
|
assert.Equal(tt.args.address, targetAfterUpdate.GetAddress())
|
|
}
|
|
|
|
afterUpdateIds = make([]string, 0, len(credSources))
|
|
for _, cl := range credSources {
|
|
afterUpdateIds = append(afterUpdateIds, cl.Id())
|
|
}
|
|
assert.ElementsMatch(testClIds, afterUpdateIds)
|
|
|
|
switch tt.name {
|
|
case "valid-no-op":
|
|
assert.Equal(tar.GetUpdateTime().String(), targetAfterUpdate.GetUpdateTime().String())
|
|
default:
|
|
assert.NotEqual(tar.GetUpdateTime(), targetAfterUpdate.GetUpdateTime())
|
|
}
|
|
foundTarget, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
|
|
assert.NoError(err)
|
|
assert.True(proto.Equal(targetAfterUpdate.((*tcp.Target)), foundTarget.((*tcp.Target))))
|
|
assert.Equal(targetAfterUpdate.GetAddress(), foundTarget.GetAddress())
|
|
underlyingDB, err := conn.SqlDB(ctx)
|
|
require.NoError(err)
|
|
dbassert := dbassert.New(t, underlyingDB)
|
|
if tt.args.description == "" {
|
|
assert.Equal(foundTarget.GetDescription(), "")
|
|
dbassert.IsNull(foundTarget, "description")
|
|
}
|
|
err = db.TestVerifyOplog(t, rw, tar.GetPublicId(), db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
|
|
assert.NoError(err)
|
|
})
|
|
}
|
|
}
|