Instantiate default resources (#425)
This commit is contained in:
1 parent
8d8a7358f8
commit
31fe9292b3
18 files changed
+904
-239
No files matched your search
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user