Instantiate default resources (#425)

This commit is contained in:
Jeff Mitchell authored and GitHub committed 2020-09-24 03:31:26 -04:00
1 parent 8d8a7358f8
commit 31fe9292b3
18 files changed
+904 -239

No files matched your search

+386
View File
@@ -0,0 +1,386 @@
package base
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/vault/sdk/helper/base62"
)
func (b *Server) CreateInitialAuthMethod(ctx context.Context) error {
rw := db.New(b.Database)
kmsRepo, err := kms.NewRepository(rw, rw)
if err != nil {
return fmt.Errorf("error creating kms repository: %w", err)
}
kmsCache, err := kms.NewKms(kmsRepo, kms.WithLogger(b.Logger.Named("kms")))
if err != nil {
return fmt.Errorf("error creating kms cache: %w", err)
}
if err := kmsCache.AddExternalWrappers(
kms.WithRootWrapper(b.RootKms),
); err != nil {
return fmt.Errorf("error adding config keys to kms: %w", err)
}
// Create the dev auth method
pwRepo, err := password.NewRepository(rw, rw, kmsCache)
if err != nil {
return fmt.Errorf("error creating password repo: %w", err)
}
authMethod, err := password.NewAuthMethod(scope.Global.String())
if err != nil {
return fmt.Errorf("error creating new in memory auth method: %w", err)
}
if b.DevAuthMethodId == "" {
b.DevAuthMethodId, err = db.NewPublicId(password.AuthMethodPrefix)
if err != nil {
return fmt.Errorf("error generating initial auth method id: %w", err)
}
}
cancelCtx, cancel := context.WithCancel(ctx)
go func() {
<-b.ShutdownCh
cancel()
}()
_, err = pwRepo.CreateAuthMethod(cancelCtx, authMethod,
password.WithName("Generated global scope initial auth method"),
password.WithDescription("Provides initial administrative authentication into Boundary"),
password.WithPublicId(b.DevAuthMethodId))
if err != nil {
return fmt.Errorf("error saving auth method to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated auth method id")
b.Info["generated auth method id"] = b.DevAuthMethodId
// Create the dev user
if b.DevLoginName == "" {
b.DevLoginName, err = base62.Random(10)
if err != nil {
return fmt.Errorf("unable to generate login name: %w", err)
}
b.DevLoginName = strings.ToLower(b.DevLoginName)
}
if b.DevPassword == "" {
b.DevPassword, err = base62.Random(20)
if err != nil {
return fmt.Errorf("unable to generate password: %w", err)
}
}
b.InfoKeys = append(b.InfoKeys, "generated auth method password")
b.Info["generated auth method password"] = b.DevPassword
acct, err := password.NewAccount(b.DevAuthMethodId, password.WithLoginName(b.DevLoginName))
if err != nil {
return fmt.Errorf("error creating new in memory auth account: %w", err)
}
acct, err = pwRepo.CreateAccount(cancelCtx, scope.Global.String(), acct, password.WithPassword(b.DevPassword))
if err != nil {
return fmt.Errorf("error saving auth account to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated auth method login name")
b.Info["generated auth method login name"] = acct.GetLoginName()
iamRepo, err := iam.NewRepository(rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
if err != nil {
return fmt.Errorf("unable to create repo for org id: %w", err)
}
// Create a new user and associate it with the account
if b.DevUserId == "" {
b.DevUserId, err = db.NewPublicId(iam.UserPrefix)
if err != nil {
return fmt.Errorf("error generating initial user id: %w", err)
}
}
opts := []iam.Option{
iam.WithName("admin"),
iam.WithDescription(`Initial admin user within the "global" scope`),
iam.WithPublicId(b.DevUserId),
}
u, err := iam.NewUser(scope.Global.String(), opts...)
if err != nil {
return fmt.Errorf("error creating in memory user: %w", err)
}
if u, err = iamRepo.CreateUser(cancelCtx, u, opts...); err != nil {
return fmt.Errorf("error creating initial admin user: %w", err)
}
if u, err = iamRepo.AssociateUserWithAccount(cancelCtx, u.GetPublicId(), acct.GetPublicId()); err != nil {
return fmt.Errorf("error associating initial admin user with account: %w", err)
}
// Create a role tying them together
pr, err := iam.NewRole(scope.Global.String(),
iam.WithName("Generated global scope admin role"),
iam.WithDescription(`Provides admin grants within the "global" scope to the initial user`),
)
if err != nil {
return fmt.Errorf("error creating in memory role for generated grants: %w", err)
}
defPermsRole, err := iamRepo.CreateRole(cancelCtx, pr)
if err != nil {
return fmt.Errorf("error creating role for default generated grants: %w", err)
}
if _, err := iamRepo.AddRoleGrants(cancelCtx, defPermsRole.PublicId, defPermsRole.Version, []string{"id=*;actions=*"}); err != nil {
return fmt.Errorf("error creating grant for default generated grants: %w", err)
}
if _, err := iamRepo.AddPrincipalRoles(cancelCtx, defPermsRole.PublicId, defPermsRole.Version+1, []string{u.GetPublicId()}, nil); err != nil {
return fmt.Errorf("error adding principal to role for default generated grants: %w", err)
}
return nil
}
func (b *Server) CreateInitialScopes(ctx context.Context) error {
rw := db.New(b.Database)
kmsRepo, err := kms.NewRepository(rw, rw)
if err != nil {
return fmt.Errorf("error creating kms repository: %w", err)
}
kmsCache, err := kms.NewKms(kmsRepo, kms.WithLogger(b.Logger.Named("kms")))
if err != nil {
return fmt.Errorf("error creating kms cache: %w", err)
}
if err := kmsCache.AddExternalWrappers(
kms.WithRootWrapper(b.RootKms),
); err != nil {
return fmt.Errorf("error adding config keys to kms: %w", err)
}
cancelCtx, cancel := context.WithCancel(ctx)
go func() {
<-b.ShutdownCh
cancel()
}()
iamRepo, err := iam.NewRepository(rw, rw, kmsCache)
if err != nil {
return fmt.Errorf("error creating scopes repository: %w", err)
}
// Create the scopes
if b.DevOrgId == "" {
b.DevOrgId, err = db.NewPublicId(scope.Org.Prefix())
if err != nil {
return fmt.Errorf("error generating initial org id: %w", err)
}
}
opts := []iam.Option{
iam.WithName("Generated org scope"),
iam.WithDescription("Provides an initial org scope in Boundary"),
iam.WithRandomReader(b.SecureRandomReader),
iam.WithPublicId(b.DevOrgId),
}
orgScope, err := iam.NewOrg(opts...)
if err != nil {
return fmt.Errorf("error creating new in memory org scope: %w", err)
}
_, err = iamRepo.CreateScope(cancelCtx, orgScope, b.DevUserId, opts...)
if err != nil {
return fmt.Errorf("error saving org scope to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated org scope id")
b.Info["generated org scope id"] = b.DevOrgId
if b.DevProjectId == "" {
b.DevProjectId, err = db.NewPublicId(scope.Project.Prefix())
if err != nil {
return fmt.Errorf("error generating initial project id: %w", err)
}
}
opts = []iam.Option{
iam.WithName("Generated project scope"),
iam.WithDescription("Provides an initial project scope in Boundary"),
iam.WithRandomReader(b.SecureRandomReader),
iam.WithPublicId(b.DevProjectId),
}
projScope, err := iam.NewProject(b.DevOrgId, opts...)
if err != nil {
return fmt.Errorf("error creating new in memory project scope: %w", err)
}
_, err = iamRepo.CreateScope(cancelCtx, projScope, b.DevUserId, opts...)
if err != nil {
return fmt.Errorf("error saving project scope to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated project scope id")
b.Info["generated project scope id"] = b.DevProjectId
return nil
}
func (b *Server) CreateInitialHostResources(ctx context.Context) error {
rw := db.New(b.Database)
kmsRepo, err := kms.NewRepository(rw, rw)
if err != nil {
return fmt.Errorf("error creating kms repository: %w", err)
}
kmsCache, err := kms.NewKms(kmsRepo, kms.WithLogger(b.Logger.Named("kms")))
if err != nil {
return fmt.Errorf("error creating kms cache: %w", err)
}
if err := kmsCache.AddExternalWrappers(
kms.WithRootWrapper(b.RootKms),
); err != nil {
return fmt.Errorf("error adding config keys to kms: %w", err)
}
cancelCtx, cancel := context.WithCancel(ctx)
go func() {
<-b.ShutdownCh
cancel()
}()
staticRepo, err := static.NewRepository(rw, rw, kmsCache)
if err != nil {
return fmt.Errorf("error creating static repository: %w", err)
}
// Host Catalog
if b.DevHostCatalogId == "" {
b.DevHostCatalogId, err = db.NewPublicId(static.HostCatalogPrefix)
if err != nil {
return fmt.Errorf("error generating initial host catalog id: %w", err)
}
}
opts := []static.Option{
static.WithName("Generated host catalog"),
static.WithDescription("Provides an initial host catalog in Boundary"),
static.WithPublicId(b.DevHostCatalogId),
}
hc, err := static.NewHostCatalog(b.DevProjectId, opts...)
if err != nil {
return fmt.Errorf("error creating in memory host catalog: %w", err)
}
if hc, err = staticRepo.CreateCatalog(cancelCtx, hc, opts...); err != nil {
return fmt.Errorf("error saving host catalog to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated host catalog id")
b.Info["generated host catalog id"] = b.DevHostCatalogId
// Host
if b.DevHostId == "" {
b.DevHostId, err = db.NewPublicId(static.HostPrefix)
if err != nil {
return fmt.Errorf("error generating initial host id: %w", err)
}
}
if b.DevHostAddress == "" {
b.DevHostAddress = "localhost"
}
opts = []static.Option{
static.WithName("Generated host"),
static.WithDescription("Provides an initial host in Boundary"),
static.WithAddress(b.DevHostAddress),
static.WithPublicId(b.DevHostId),
}
h, err := static.NewHost(hc.PublicId, opts...)
if err != nil {
return fmt.Errorf("error creating in memory host: %w", err)
}
if h, err = staticRepo.CreateHost(cancelCtx, b.DevProjectId, h, opts...); err != nil {
return fmt.Errorf("error saving host to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated host id")
b.Info["generated host id"] = b.DevHostId
// Host Set
if b.DevHostSetId == "" {
b.DevHostSetId, err = db.NewPublicId(static.HostSetPrefix)
if err != nil {
return fmt.Errorf("error generating initial host set id: %w", err)
}
}
opts = []static.Option{
static.WithName("Generated host set"),
static.WithDescription("Provides an initial host set in Boundary"),
static.WithPublicId(b.DevHostSetId),
}
hs, err := static.NewHostSet(hc.PublicId, opts...)
if err != nil {
return fmt.Errorf("error creating in memory host set: %w", err)
}
if hs, err = staticRepo.CreateSet(cancelCtx, b.DevProjectId, hs, opts...); err != nil {
return fmt.Errorf("error saving host set to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated host set id")
b.Info["generated host set id"] = b.DevHostSetId
// Associate members
if _, err := staticRepo.AddSetMembers(cancelCtx, b.DevProjectId, b.DevHostSetId, hs.GetVersion(), []string{h.GetPublicId()}); err != nil {
return fmt.Errorf("error associating host set to host in the db: %w", err)
}
return nil
}
func (b *Server) CreateInitialTarget(ctx context.Context) (target.Target, error) {
rw := db.New(b.Database)
kmsRepo, err := kms.NewRepository(rw, rw)
if err != nil {
return nil, fmt.Errorf("error creating kms repository: %w", err)
}
kmsCache, err := kms.NewKms(kmsRepo, kms.WithLogger(b.Logger.Named("kms")))
if err != nil {
return nil, fmt.Errorf("error creating kms cache: %w", err)
}
if err := kmsCache.AddExternalWrappers(
kms.WithRootWrapper(b.RootKms),
); err != nil {
return nil, fmt.Errorf("error adding config keys to kms: %w", err)
}
cancelCtx, cancel := context.WithCancel(ctx)
go func() {
<-b.ShutdownCh
cancel()
}()
targetRepo, err := target.NewRepository(rw, rw, kmsCache)
if err != nil {
return nil, fmt.Errorf("error creating target repository: %w", err)
}
// Host Catalog
if b.DevTargetId == "" {
b.DevTargetId, err = db.NewPublicId(target.TcpTargetPrefix)
if err != nil {
return nil, fmt.Errorf("error generating initial target id: %w", err)
}
}
if b.DevTargetDefaultPort == 0 {
b.DevTargetDefaultPort = 22
}
opts := []target.Option{
target.WithName("Generated target"),
target.WithDescription("Provides an initial target in Boundary"),
target.WithDefaultPort(uint32(b.DevTargetDefaultPort)),
target.WithHostSets([]string{b.DevHostSetId}),
target.WithPublicId(b.DevTargetId),
}
t, err := target.NewTcpTarget(b.DevProjectId, opts...)
if err != nil {
return nil, fmt.Errorf("error creating in memory target: %w", err)
}
tt, _, err := targetRepo.CreateTcpTarget(cancelCtx, t, opts...)
if err != nil {
return nil, fmt.Errorf("error saving target to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated target id")
b.Info["generated target id"] = b.DevTargetId
return tt, nil
}
+38 -3
View File
@@ -14,9 +14,13 @@ type Option func(*Options)
// Options - how Options are represented.
type Options struct {
withNoTokenScope bool
withNoTokenValue bool
withSkipAuthMethodCreation bool
withNoTokenScope bool
withNoTokenValue bool
withSkipDatabaseDestruction bool
withSkipAuthMethodCreation bool
withSkipScopesCreation bool
withSkipHostResourcesCreation bool
withSkipTargetCreation bool
}
func getDefaultOptions() Options {
@@ -32,6 +36,13 @@ func WithNoTokenScope() Option {
}
}
// WithSkipDatabaseDestruction tells the command not to destroy the database even on error.
func WithSkipDatabaseDestruction() Option {
return func(o *Options) {
o.withSkipDatabaseDestruction = true
}
}
// WithNoTokenValue tells the client not to set a token for the client from a
// saved token's value, as this can cause confusing behavior at authentication
// time.
@@ -48,3 +59,27 @@ func WithSkipAuthMethodCreation() Option {
o.withSkipAuthMethodCreation = true
}
}
// WithSkipScopesCreation tells the command not to instantiate scopes on first
// run.
func WithSkipScopesCreation() Option {
return func(o *Options) {
o.withSkipScopesCreation = true
}
}
// WithSkipHostResourcesCreation tells the command not to instantiate a host
// catalog and related resources on first run.
func WithSkipHostResourcesCreation() Option {
return func(o *Options) {
o.withSkipHostResourcesCreation = true
}
}
// WithSkipTargetCreation tells the command not to instantiate a target on first
// run.
func WithSkipTargetCreation() Option {
return func(o *Options) {
o.withSkipTargetCreation = true
}
}
+49 -113
View File
@@ -16,10 +16,8 @@ import (
"github.com/armon/go-metrics"
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/sdk/strutil"
@@ -31,7 +29,6 @@ import (
"github.com/hashicorp/shared-secure-libs/configutil"
"github.com/hashicorp/shared-secure-libs/gatedwriter"
"github.com/hashicorp/shared-secure-libs/reloadutil"
"github.com/hashicorp/vault/sdk/helper/base62"
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/helper/mlock"
"github.com/hashicorp/vault/sdk/logical"
@@ -68,15 +65,18 @@ type Server struct {
Listeners []*ServerListener
DevAuthMethodId string
DevLoginName string
DevPassword string
DevOrgId string
DevProjectId string
DevHostCatalogId string
DevHostSetId string
DevHostId string
DevTargetId string
DevAuthMethodId string
DevLoginName string
DevPassword string
DevUserId string
DevOrgId string
DevProjectId string
DevHostCatalogId string
DevHostSetId string
DevHostId string
DevTargetId string
DevHostAddress string
DevTargetDefaultPort int
DatabaseUrl string
DevDatabaseCleanupFunc func() error
@@ -443,8 +443,10 @@ func (b *Server) CreateDevDatabase(dialect string, opt ...Option) error {
// In case of an error, run the cleanup function. If we pass all errors, c should be set to a noop
// function before returning from this method
defer func() {
if err := c(); err != nil {
b.Logger.Error("error cleaning up docker container", "error", err)
if !opts.withSkipDatabaseDestruction {
if err := c(); err != nil {
b.Logger.Error("error cleaning up docker container", "error", err)
}
}
}()
@@ -483,6 +485,39 @@ func (b *Server) CreateDevDatabase(dialect string, opt ...Option) error {
return err
}
if opts.withSkipScopesCreation {
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
return nil
}
if err := b.CreateInitialScopes(context.Background()); err != nil {
return err
}
if opts.withSkipHostResourcesCreation {
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
return nil
}
if err := b.CreateInitialHostResources(context.Background()); err != nil {
return err
}
if opts.withSkipTargetCreation {
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
return nil
}
if _, err := b.CreateInitialTarget(context.Background()); err != nil {
return err
}
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
@@ -520,105 +555,6 @@ func (b *Server) CreateGlobalKmsKeys(ctx context.Context) error {
return nil
}
func (b *Server) CreateInitialAuthMethod(ctx context.Context) error {
rw := db.New(b.Database)
kmsRepo, err := kms.NewRepository(rw, rw)
if err != nil {
return fmt.Errorf("error creating kms repository: %w", err)
}
kmsCache, err := kms.NewKms(kmsRepo)
if err != nil {
return fmt.Errorf("error creating kms cache: %w", err)
}
if err := kmsCache.AddExternalWrappers(
kms.WithRootWrapper(b.RootKms),
); err != nil {
return fmt.Errorf("error adding config keys to kms: %w", err)
}
// Create the dev auth method
pwRepo, err := password.NewRepository(rw, rw, kmsCache)
if err != nil {
return fmt.Errorf("error creating password repo: %w", err)
}
authMethod, err := password.NewAuthMethod(scope.Global.String())
if err != nil {
return fmt.Errorf("error creating new in memory auth method: %w", err)
}
if b.DevAuthMethodId == "" {
b.DevAuthMethodId, err = db.NewPublicId(password.AuthMethodPrefix)
if err != nil {
return fmt.Errorf("error generating dev auth method id: %w", err)
}
}
cancelCtx, cancel := context.WithCancel(ctx)
go func() {
<-b.ShutdownCh
cancel()
}()
_, err = pwRepo.CreateAuthMethod(cancelCtx, authMethod, password.WithPublicId(b.DevAuthMethodId))
if err != nil {
return fmt.Errorf("error saving auth method to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated auth method id")
b.Info["generated auth method id"] = b.DevAuthMethodId
// Create the dev user
if b.DevLoginName == "" {
b.DevLoginName, err = base62.Random(10)
if err != nil {
return fmt.Errorf("unable to generate login name: %w", err)
}
b.DevLoginName = strings.ToLower(b.DevLoginName)
}
if b.DevPassword == "" {
b.DevPassword, err = base62.Random(20)
if err != nil {
return fmt.Errorf("unable to generate password: %w", err)
}
}
b.InfoKeys = append(b.InfoKeys, "generated password")
b.Info["generated password"] = b.DevPassword
acct, err := password.NewAccount(b.DevAuthMethodId, password.WithLoginName(b.DevLoginName))
if err != nil {
return fmt.Errorf("error creating new in memory auth account: %w", err)
}
acct, err = pwRepo.CreateAccount(cancelCtx, scope.Global.String(), acct, password.WithPassword(b.DevPassword))
if err != nil {
return fmt.Errorf("error saving auth account to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "generated login name")
b.Info["generated login name"] = acct.GetLoginName()
// Create a role tying them together
iamRepo, err := iam.NewRepository(rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
if err != nil {
return fmt.Errorf("unable to create repo for org id: %w", err)
}
pr, err := iam.NewRole(scope.Global.String())
if err != nil {
return fmt.Errorf("error creating in memory role for generated grants: %w", err)
}
pr.Name = "Generated Global Scope Admin Role"
pr.Description = `Provides admin grants to all authenticated users within the "global" scope`
defPermsRole, err := iamRepo.CreateRole(cancelCtx, pr)
if err != nil {
return fmt.Errorf("error creating role for default generated grants: %w", err)
}
if _, err := iamRepo.AddRoleGrants(cancelCtx, defPermsRole.PublicId, defPermsRole.Version, []string{"id=*;actions=*"}); err != nil {
return fmt.Errorf("error creating grant for default generated grants: %w", err)
}
if _, err := iamRepo.AddPrincipalRoles(cancelCtx, defPermsRole.PublicId, defPermsRole.Version+1, []string{"u_auth"}, nil); err != nil {
return fmt.Errorf("error adding principal to role for default generated grants: %w", err)
}
return nil
}
func (b *Server) DestroyDevDatabase() error {
if b.Database != nil {
b.Database.Close()
+103 -5
View File
@@ -1,6 +1,8 @@
package database
import (
"fmt"
"github.com/hashicorp/boundary/internal/cmd/base"
)
@@ -9,6 +11,7 @@ type AuthMethodInfo struct {
LoginName string `json:"login_name"`
Password string `json:"password"`
ScopeId string `json:"scope_id"`
UserId string `json:"user_id"`
}
func generateInitialAuthMethodTableOutput(in *AuthMethodInfo) string {
@@ -17,6 +20,7 @@ func generateInitialAuthMethodTableOutput(in *AuthMethodInfo) string {
"Auth Method ID": in.AuthMethodId,
"Login Name": in.LoginName,
"Password": in.Password,
"User ID": in.UserId,
}
maxLength := 0
@@ -26,12 +30,106 @@ func generateInitialAuthMethodTableOutput(in *AuthMethodInfo) string {
}
}
ret := []string{"", "Initial auth method information:"}
ret = append(ret,
// We do +2 because there is another +2 offset for host sets below
ret := []string{
"",
"Initial auth method information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
)
}
return base.WrapForHelpText(ret)
}
type ScopeInfo struct {
ScopeId string `json:"scope_id"`
Type string `json:"type"`
}
func generateInitialScopeTableOutput(in *ScopeInfo) string {
nonAttributeMap := map[string]interface{}{
"Scope ID": in.ScopeId,
"Type": in.Type,
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
ret := []string{
"",
fmt.Sprintf("Initial %s scope information:", in.Type),
base.WrapMap(2, maxLength+2, nonAttributeMap),
}
return base.WrapForHelpText(ret)
}
type HostInfo struct {
HostCatalogId string `json:"host_catalog_id"`
HostSetId string `json:"host_set_id"`
HostId string `json:"host_id"`
Type string `json:"type"`
ScopeId string `json:"scope_id"`
}
func generateInitialHostResourcesTableOutput(in *HostInfo) string {
nonAttributeMap := map[string]interface{}{
"Host Catalog ID": in.HostCatalogId,
"Host Set ID": in.HostSetId,
"Host ID": in.HostId,
"Type": in.Type,
"Scope ID": in.ScopeId,
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
ret := []string{
"",
"Initial host resources information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
}
return base.WrapForHelpText(ret)
}
type TargetInfo struct {
TargetId string `json:"target_id"`
DefaultPort uint32 `json:"default_port"`
SessionMaxSeconds uint32 `json:"session_max_seconds"`
SessionConnectionLimit int32 `json:"session_connection_limit"`
Type string `json:"type"`
ScopeId string `json:"scope_id"`
}
func generateInitialTargetTableOutput(in *TargetInfo) string {
nonAttributeMap := map[string]interface{}{
"Target ID": in.TargetId,
"Default Port": in.DefaultPort,
"Session Max Seconds": in.SessionMaxSeconds,
"Session Connection Limit": in.SessionConnectionLimit,
"Type": in.Type,
"Scope ID": in.ScopeId,
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
ret := []string{
"",
"Initial target information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
}
return base.WrapForHelpText(ret)
}
+148 -31
View File
@@ -8,7 +8,6 @@ import (
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/servers/controller"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/sdk/wrapper"
wrapping "github.com/hashicorp/go-kms-wrapping"
@@ -24,22 +23,23 @@ type InitCommand struct {
*base.Command
srv *base.Server
SighupCh chan struct{}
childSighupCh []chan struct{}
ReloadedCh chan struct{}
SigUSR2Ch chan struct{}
SighupCh chan struct{}
ReloadedCh chan struct{}
SigUSR2Ch chan struct{}
Config *config.Config
controller *controller.Controller
Config *config.Config
configWrapper wrapping.Wrapper
flagConfig string
flagConfigKms string
flagLogLevel string
flagLogFormat string
flagMigrationUrl string
flagSkipAuthMethodCreation bool
flagConfig string
flagConfigKms string
flagLogLevel string
flagLogFormat string
flagMigrationUrl string
flagSkipAuthMethodCreation bool
flagSkipScopesCreation bool
flagSkipHostResourcesCreation bool
flagSkipTargetCreation bool
}
func (c *InitCommand) Synopsis() string {
@@ -47,17 +47,27 @@ func (c *InitCommand) Synopsis() string {
}
func (c *InitCommand) Help() string {
helpText := `
Usage: boundary database init [options]
Initialize Boundary's database:
$ boundary database init -config=/etc/boundary/controller.hcl
For a full list of examples, please see the documentation.
` + c.Flags().Help()
return strings.TrimSpace(helpText)
return base.WrapForHelpText([]string{
"Usage: boundary database init [options]",
"",
" Initialize Boundary's database:",
"",
" $ boundary database init -config=/etc/boundary/controller.hcl",
"",
" Unless told not to via flags, some initial resources will be created, in the following order and in the indicated scopes:",
"",
" Password-Type Auth Method (global)",
" Org Scope (global)",
" Project Scope (org)",
" Static-Type Host Catalog (project)",
" Static-Type Host Set",
" Static-Type Host",
" Target (project)",
"",
" If flags are used to skip any of these resources, any resources that would be created afterwards are also skipped.",
"",
" For a full list of examples, please see the documentation.",
}) + c.Flags().Help()
}
func (c *InitCommand) Flags() *base.FlagSets {
@@ -111,6 +121,24 @@ func (c *InitCommand) Flags() *base.FlagSets {
Usage: "If not set, an auth method will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-scopes-creation",
Target: &c.flagSkipScopesCreation,
Usage: "If not set, scopes will not be created as part of initialization.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-host-resources-creation",
Target: &c.flagSkipHostResourcesCreation,
Usage: "If not set, host resources (host catalog, host set, host) will not be created as part of initialization.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-target-creation",
Target: &c.flagSkipTargetCreation,
Usage: "If not set, a target will not be created as part of initialization.",
})
f.StringVar(&base.StringVar{
Name: "migration-url",
Target: &c.flagMigrationUrl,
@@ -129,7 +157,7 @@ func (c *InitCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *InitCommand) Run(args []string) int {
func (c *InitCommand) Run(args []string) (retCode int) {
if result := c.ParseFlagsAndConfig(args); result > 0 {
return result
}
@@ -262,6 +290,20 @@ func (c *InitCommand) Run(args []string) int {
return 0
}
var jsonMap map[string]interface{}
if base.Format(c.UI) == "json" {
jsonMap = make(map[string]interface{})
defer func() {
b, err := base.JsonFormatter{}.Format(jsonMap)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
retCode = 1
return
}
c.UI.Output(string(b))
}()
}
// Use an easy name, at least
c.srv.DevLoginName = "admin"
if err := c.srv.CreateInitialAuthMethod(c.Context); err != nil {
@@ -274,17 +316,92 @@ func (c *InitCommand) Run(args []string) int {
LoginName: c.srv.DevLoginName,
Password: c.srv.DevPassword,
ScopeId: scope.Global.String(),
UserId: c.srv.DevUserId,
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateInitialAuthMethodTableOutput(authMethodInfo))
case "json":
b, err := base.JsonFormatter{}.Format(authMethodInfo)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
jsonMap["auth_method"] = authMethodInfo
}
if c.flagSkipScopesCreation {
return 0
}
if err := c.srv.CreateInitialScopes(c.Context); err != nil {
c.UI.Error(fmt.Errorf("Error creating initial scopes: %w", err).Error())
return 1
}
orgScopeInfo := &ScopeInfo{
ScopeId: c.srv.DevOrgId,
Type: scope.Org.String(),
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateInitialScopeTableOutput(orgScopeInfo))
case "json":
jsonMap["org_scope"] = orgScopeInfo
}
projScopeInfo := &ScopeInfo{
ScopeId: c.srv.DevProjectId,
Type: scope.Project.String(),
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateInitialScopeTableOutput(projScopeInfo))
case "json":
jsonMap["proj_scope"] = projScopeInfo
}
if c.flagSkipHostResourcesCreation {
return 0
}
if err := c.srv.CreateInitialHostResources(c.Context); err != nil {
c.UI.Error(fmt.Errorf("Error creating initial host resources: %w", err).Error())
return 1
}
hostInfo := &HostInfo{
HostCatalogId: c.srv.DevHostCatalogId,
HostSetId: c.srv.DevHostSetId,
HostId: c.srv.DevHostId,
Type: "static",
ScopeId: c.srv.DevProjectId,
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateInitialHostResourcesTableOutput(hostInfo))
case "json":
jsonMap["host_resources"] = hostInfo
}
if c.flagSkipTargetCreation {
return 0
}
t, err := c.srv.CreateInitialTarget(c.Context)
if err != nil {
c.UI.Error(fmt.Errorf("Error creating initial target: %w", err).Error())
return 1
}
targetInfo := &TargetInfo{
TargetId: c.srv.DevTargetId,
DefaultPort: t.GetDefaultPort(),
SessionMaxSeconds: t.GetSessionMaxSeconds(),
SessionConnectionLimit: t.GetSessionConnectionLimit(),
Type: "tcp",
ScopeId: c.srv.DevProjectId,
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateInitialTargetTableOutput(targetInfo))
case "json":
jsonMap["target"] = targetInfo
}
return 0
+45 -57
View File
@@ -2,6 +2,7 @@ package dev
import (
"fmt"
"net"
"runtime"
"strings"
@@ -9,9 +10,11 @@ import (
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/servers/controller"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/hashicorp/boundary/internal/servers/worker"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/mitchellh/cli"
"github.com/posener/complete"
@@ -38,6 +41,8 @@ type Command struct {
flagLoginName string
flagPassword string
flagIdSuffix string
flagHostAddress string
flagTargetDefaultPort int
flagControllerAPIListenAddr string
flagControllerClusterListenAddr string
flagWorkerProxyListenAddr string
@@ -89,10 +94,11 @@ func (c *Command) Flags() *base.FlagSets {
})
f.StringVar(&base.StringVar{
Name: "id-suffix",
Target: &c.flagIdSuffix,
EnvVar: "BOUNDARY_DEV_ID_SUFFIX",
Usage: `If set, auto-created resources will use this value for their identifier (along with their resource-specific prefix). Must be 10 alphanumeric characters. As an example, if this is set to "1234567890", the generated password auth method ID will be "ampw_1234567890", the generated TCP target ID will be "ttcp_1234567890", and so on.`,
Name: "id-suffix",
Target: &c.flagIdSuffix,
Default: "1234567890",
EnvVar: "BOUNDARY_DEV_ID_SUFFIX",
Usage: `If set, auto-created resources will use this value for their identifier (along with their resource-specific prefix). Must be 10 alphanumeric characters. As an example, if this is set to "1234567890", the generated password auth method ID will be "ampw_1234567890", the generated TCP target ID will be "ttcp_1234567890", and so on.`,
})
f.StringVar(&base.StringVar{
@@ -116,6 +122,22 @@ func (c *Command) Flags() *base.FlagSets {
Usage: "Address to bind to for controller \"api\" purpose.",
})
f.StringVar(&base.StringVar{
Name: "host-address",
Default: "localhost",
Target: &c.flagHostAddress,
EnvVar: "BOUNDARY_DEV_HOST_ADDRESS",
Usage: "Address to use for the default host that is created. Must be a bare host or IP address, no port.",
})
f.IntVar(&base.IntVar{
Name: "target-default-port",
Default: 22,
Target: &c.flagTargetDefaultPort,
EnvVar: "BOUNDARY_DEV_TARGET_DEFAULT_PORT",
Usage: "Default port to use for the default target that is created.",
})
f.StringVar(&base.StringVar{
Name: "cluster-listen-address",
Target: &c.flagControllerClusterListenAddr,
@@ -203,11 +225,13 @@ func (c *Command) Run(args []string) int {
return 1
}
c.DevAuthMethodId = fmt.Sprintf("%s_%s", password.AuthMethodPrefix, c.flagIdSuffix)
c.DevUserId = fmt.Sprintf("%s_%s", iam.UserPrefix, c.flagIdSuffix)
c.DevOrgId = fmt.Sprintf("%s_%s", scope.Org.Prefix(), c.flagIdSuffix)
c.DevProjectId = fmt.Sprintf("%s_%s", scope.Project.Prefix(), c.flagIdSuffix)
c.DevHostCatalogId = fmt.Sprintf("%s_%s", static.HostCatalogPrefix, c.flagIdSuffix)
c.DevHostSetId = fmt.Sprintf("%s_%s", static.HostSetPrefix, c.flagIdSuffix)
c.DevHostId = fmt.Sprintf("%s_%s", static.HostPrefix, c.flagIdSuffix)
c.DevTargetId = fmt.Sprintf("%s_%s", target.TcpTargetPrefix, c.flagIdSuffix)
}
if c.flagLoginName != "" {
c.DevLoginName = c.flagLoginName
@@ -215,6 +239,20 @@ func (c *Command) Run(args []string) int {
if c.flagPassword != "" {
c.DevPassword = c.flagPassword
}
c.DevTargetDefaultPort = c.flagTargetDefaultPort
host, port, err := net.SplitHostPort(c.flagHostAddress)
if err != nil {
if !strings.Contains(err.Error(), "missing port") {
c.UI.Error(fmt.Errorf("Invalid host address specified: %w", err).Error())
return 1
}
host = c.flagHostAddress
}
if port != "" {
c.UI.Error(`Port must not be specified as part of the dev host address`)
return 1
}
c.DevHostAddress = host
c.Config.PassthroughDirectory = c.flagPassthroughDirectory
@@ -301,6 +339,9 @@ func (c *Command) Run(args []string) int {
}()
var opts []base.Option
if c.flagDisableDatabaseDestruction {
opts = append(opts, base.WithSkipDatabaseDestruction())
}
if err := c.CreateDevDatabase("postgres", opts...); err != nil {
c.UI.Error(fmt.Errorf("Error creating dev database container: %w", err).Error())
return 1
@@ -361,45 +402,6 @@ func (c *Command) Run(args []string) int {
return 1
}
}
/*
shutdownWg := &sync.WaitGroup{}
shutdownWg.Add(2)
controllerSighupCh := make(chan struct{})
c.childSighupCh = append(c.childSighupCh, controllerSighupCh)
devController := &controllercmd.Command{
Server: c.Server,
ExtShutdownCh: childShutdownCh,
SighupCh: controllerSighupCh,
Config: c.Config,
}
if err := devController.Start(); err != nil {
c.UI.Error(err.Error())
return 1
}
workerSighupCh := make(chan struct{})
c.childSighupCh = append(c.childSighupCh, workerSighupCh)
devWorker := &workercmd.Command{
Server: c.Server,
ExtShutdownCh: childShutdownCh,
SighupCh: workerSighupCh,
Config: c.Config,
}
if err := devWorker.Start(); err != nil {
c.UI.Error(err.Error())
return 1
}
go func() {
defer shutdownWg.Done()
devController.WaitForInterrupt()
}()
go func() {
defer shutdownWg.Done()
devWorker.WaitForInterrupt()
}()
*/
// Wait for shutdown
shutdownTriggered := false
@@ -409,10 +411,6 @@ func (c *Command) Run(args []string) int {
case <-c.ShutdownCh:
c.UI.Output("==> Boundary dev environment shutdown triggered")
/*
childShutdownCh <- struct{}{}
childShutdownCh <- struct{}{}
*/
if err := c.worker.Shutdown(false); err != nil {
c.UI.Error(fmt.Errorf("Error shutting down worker: %w", err).Error())
}
@@ -423,14 +421,6 @@ func (c *Command) Run(args []string) int {
shutdownTriggered = true
/*
case <-c.SighupCh:
c.UI.Output("==> Boundary dev environment reload triggered")
for _, v := range c.childSighupCh {
v <- struct{}{}
}
*/
case <-c.SigUSR2Ch:
buf := make([]byte, 32*1024*1024)
n := runtime.Stack(buf[:], true)
@@ -438,7 +428,5 @@ func (c *Command) Run(args []string) int {
}
}
//shutdownWg.Wait()
return 0
}
+8
View File
@@ -18,6 +18,7 @@ type options struct {
withDescription string
withLimit int
withAddress string
withPublicId string
}
func getDefaultOptions() options {
@@ -57,3 +58,10 @@ func WithAddress(address string) Option {
o.withAddress = address
}
}
// WithPublicId provides an optional public id
func WithPublicId(id string) Option {
return func(o *options) {
o.withPublicId = id
}
}
+6
View File
@@ -32,4 +32,10 @@ func Test_GetOpts(t *testing.T) {
testOpts.withAddress = "test"
assert.Equal(t, opts, testOpts)
})
t.Run("WithPublicId", func(t *testing.T) {
opts := getOpts(WithPublicId("test"))
testOpts := getDefaultOptions()
testOpts.withPublicId = "test"
assert.Equal(t, opts, testOpts)
})
}
+13 -4
View File
@@ -43,11 +43,20 @@ func (r *Repository) CreateHost(ctx context.Context, scopeId string, h *Host, op
}
h = h.clone()
id, err := newHostId()
if err != nil {
return nil, fmt.Errorf("create: static host: %w", err)
opts := getOpts(opt...)
if opts.withPublicId != "" {
if !strings.HasPrefix(opts.withPublicId, HostPrefix+"_") {
return nil, fmt.Errorf("create: static host: passed-in public ID %q has wrong prefix, should be %q: %w", opts.withPublicId, HostPrefix, db.ErrInvalidPublicId)
}
h.PublicId = opts.withPublicId
} else {
id, err := newHostId()
if err != nil {
return nil, fmt.Errorf("create: static host: %w", err)
}
h.PublicId = id
}
h.PublicId = id
oplogWrapper, err := r.kms.GetWrapper(ctx, scopeId, kms.KeyPurposeOplog)
if err != nil {
@@ -35,11 +35,20 @@ func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, opt ...O
}
c = c.clone()
id, err := newHostCatalogId()
if err != nil {
return nil, fmt.Errorf("create: static host catalog: %w", err)
opts := getOpts(opt...)
if opts.withPublicId != "" {
if !strings.HasPrefix(opts.withPublicId, HostCatalogPrefix+"_") {
return nil, fmt.Errorf("create: static host catalog: passed-in public ID %q has wrong prefix, should be %q: %w", opts.withPublicId, HostCatalogPrefix, db.ErrInvalidPublicId)
}
c.PublicId = opts.withPublicId
} else {
id, err := newHostCatalogId()
if err != nil {
return nil, fmt.Errorf("create: static host catalog: %w", err)
}
c.PublicId = id
}
c.PublicId = id
oplogWrapper, err := r.kms.GetWrapper(ctx, c.ScopeId, kms.KeyPurposeOplog)
if err != nil {
+13 -4
View File
@@ -37,11 +37,20 @@ func (r *Repository) CreateSet(ctx context.Context, scopeId string, s *HostSet,
}
s = s.clone()
id, err := newHostSetId()
if err != nil {
return nil, fmt.Errorf("create: static host set: %w", err)
opts := getOpts(opt...)
if opts.withPublicId != "" {
if !strings.HasPrefix(opts.withPublicId, HostSetPrefix+"_") {
return nil, fmt.Errorf("create: static host set: passed-in public ID %q has wrong prefix, should be %q: %w", opts.withPublicId, HostSetPrefix, db.ErrInvalidPublicId)
}
s.PublicId = opts.withPublicId
} else {
id, err := newHostSetId()
if err != nil {
return nil, fmt.Errorf("create: static host set: %w", err)
}
s.PublicId = id
}
s.PublicId = id
oplogWrapper, err := r.kms.GetWrapper(ctx, scopeId, kms.KeyPurposeOplog)
if err != nil {
+1 -1
View File
@@ -110,7 +110,7 @@ func (r *Repository) CreateScope(ctx context.Context, s *Scope, userId string, o
}
role.PublicId = rolePublicId
role.Name = "on-scope-creation"
role.Description = fmt.Sprintf("Role created for administration of scope %s at its creation time", scopePublicId)
role.Description = fmt.Sprintf("Role created for administration of scope %s by user %s at its creation time", scopePublicId, userId)
roleRaw = role
roleMetadata = oplog.Metadata{
"resource-public-id": []string{rolePublicId},
+18 -7
View File
@@ -21,18 +21,29 @@ func (r *Repository) CreateUser(ctx context.Context, user *User, opt ...Option)
if user.PublicId != "" {
return nil, fmt.Errorf("create user: public id is not empty %w", db.ErrInvalidParameter)
}
id, err := newUserId()
if err != nil {
return nil, fmt.Errorf("create user: %w", err)
u := user.Clone().(*User)
opts := getOpts(opt...)
if opts.withPublicId != "" {
if !strings.HasPrefix(opts.withPublicId, UserPrefix+"_") {
return nil, fmt.Errorf("create user: passed-in public ID %q has wrong prefix, should be %q: %w", opts.withPublicId, UserPrefix, db.ErrInvalidPublicId)
}
u.PublicId = opts.withPublicId
} else {
id, err := newUserId()
if err != nil {
return nil, fmt.Errorf("create user: %w", err)
}
u.PublicId = id
}
u := user.Clone()
u.(*User).PublicId = id
resource, err := r.create(ctx, u.(*User))
resource, err := r.create(ctx, u)
if err != nil {
if db.IsUniqueError(err) {
return nil, fmt.Errorf("create user: user %s already exists in org %s: %w", user.Name, user.ScopeId, err)
}
return nil, fmt.Errorf("create user: %w for %s", err, u.(*User).PublicId)
return nil, fmt.Errorf("create user: %w for %s", err, u.PublicId)
}
return resource.(*User), err
}
@@ -612,7 +612,7 @@ func TestCreate(t *testing.T) {
require.Len(roles, 1)
role := roles[0]
assert.Equal("on-scope-creation", role.GetName())
assert.Equal(fmt.Sprintf("Role created for administration of scope %s at its creation time", got.GetItem().GetId()), role.GetDescription())
assert.Equal(fmt.Sprintf("Role created for administration of scope %s by user %s at its creation time", got.GetItem().GetId(), userId), role.GetDescription())
}
// Clear all values which are hard to compare against.
+31 -4
View File
@@ -239,6 +239,18 @@ type TestControllerOpts struct {
// method automatically.
DisableAuthMethodCreation bool
// DisableScopesCreation can be set true to disable creating scopes
// automatically.
DisableScopesCreation bool
// DisableHostResourcesCreation can be set true to disable creating a host
// catalog and related resources automatically.
DisableHostResourcesCreation bool
// DisableTargetCreation can be set true to disable creating a target
// automatically.
DisableTargetCreation bool
// DisableDatabaseCreation can be set true to disable creating a dev
// database
DisableDatabaseCreation bool
@@ -382,10 +394,25 @@ func NewTestController(t *testing.T, opts *TestControllerOpts) *TestController {
if err := tc.b.CreateGlobalKmsKeys(ctx); err != nil {
t.Fatal(err)
}
}
if !opts.DisableAuthMethodCreation {
if err := tc.b.CreateInitialAuthMethod(ctx); err != nil {
t.Fatal(err)
if !opts.DisableAuthMethodCreation {
if err := tc.b.CreateInitialAuthMethod(ctx); err != nil {
t.Fatal(err)
}
if !opts.DisableScopesCreation {
if err := tc.b.CreateInitialScopes(ctx); err != nil {
t.Fatal(err)
}
if !opts.DisableHostResourcesCreation {
if err := tc.b.CreateInitialHostResources(ctx); err != nil {
t.Fatal(err)
}
if !opts.DisableTargetCreation {
if _, err := tc.b.CreateInitialTarget(ctx); err != nil {
t.Fatal(err)
}
}
}
}
}
}
} else if !opts.DisableDatabaseCreation {
+9
View File
@@ -26,6 +26,7 @@ type options struct {
withHostSets []string
withSessionMaxSeconds uint32
withSessionConnectionLimit int32
withPublicId string
}
func getDefaultOptions() options {
@@ -40,6 +41,7 @@ func getDefaultOptions() options {
withHostSets: nil,
withSessionMaxSeconds: uint32((8 * time.Hour).Seconds()),
withSessionConnectionLimit: 1,
withPublicId: "",
}
}
@@ -112,3 +114,10 @@ func WithSessionConnectionLimit(limit int32) Option {
o.withSessionConnectionLimit = limit
}
}
// WithPublicId provides an optional public id
func WithPublicId(id string) Option {
return func(o *options) {
o.withPublicId = id
}
}
+7
View File
@@ -68,6 +68,13 @@ func Test_GetOpts(t *testing.T) {
testOpts.withScopeId = "testId"
assert.Equal(opts, testOpts)
})
t.Run("WithPublicId", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithPublicId("testId"))
testOpts := getDefaultOptions()
testOpts.withPublicId = "testId"
assert.Equal(opts, testOpts)
})
t.Run("WithTargetType", func(t *testing.T) {
assert := assert.New(t)
opts := getOpts(WithTargetType(TcpTargetType))
+15 -5
View File
@@ -31,17 +31,27 @@ func (r *Repository) CreateTcpTarget(ctx context.Context, target *TcpTarget, opt
if target.PublicId != "" {
return nil, nil, fmt.Errorf("create tcp target: public id not empty: %w", db.ErrInvalidParameter)
}
id, err := newTcpTargetId()
if err != nil {
return nil, nil, fmt.Errorf("create tcp target: %w", err)
t := target.Clone().(*TcpTarget)
if opts.withPublicId != "" {
if !strings.HasPrefix(opts.withPublicId, TcpTargetPrefix+"_") {
return nil, nil, fmt.Errorf("create tcp target: passed-in public ID %q has wrong prefix, should be %q: %w", opts.withPublicId, TcpTargetPrefix, db.ErrInvalidPublicId)
}
t.PublicId = opts.withPublicId
} else {
id, err := newTcpTargetId()
if err != nil {
return nil, nil, fmt.Errorf("create tcp target: %w", err)
}
t.PublicId = id
}
oplogWrapper, err := r.kms.GetWrapper(ctx, target.ScopeId, kms.KeyPurposeOplog)
if err != nil {
return nil, nil, fmt.Errorf("create tcp target: unable to get oplog wrapper: %w", err)
}
t := target.Clone().(*TcpTarget)
t.PublicId = id
newHostSets := make([]interface{}, 0, len(opts.withHostSets))
for _, hsId := range opts.withHostSets {