Add skip daemon flag and send recently authed tokens to daemon (#3883)
* Add skip daemon flag and send recently authed tokens to daemon * Rename flag skip-daemon to skip-cache-daemon * adding option test * move common.Options to base.Option * SocketAddress returns *url.URL, fix search test
This commit is contained in:
1 parent
2f7459fa40
commit
3a7ea64a31
27 files changed
+429
-419
No files matched your search
@@ -64,8 +64,19 @@ func (c *AddTokenCommand) Run(args []string) int {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
client, err := c.Client()
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
apiErr, err := c.Add(ctx)
|
||||
keyringType, tokenName, err := c.DiscoverKeyringTokenInfo()
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
apiErr, err := c.Add(ctx, client, keyringType, tokenName)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandCliError
|
||||
@@ -78,24 +89,14 @@ func (c *AddTokenCommand) Run(args []string) int {
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
func (c *AddTokenCommand) Add(ctx context.Context) (*api.Error, error) {
|
||||
func (c *AddTokenCommand) Add(ctx context.Context, client *api.Client, keyringType, tokenName string) (*api.Error, error) {
|
||||
const op = "daemon.(AddTokenCommand).Add"
|
||||
client, err := c.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyringType, tokenName, err := c.DiscoverKeyringTokenInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pa := daemon.UpsertTokenRequest{
|
||||
BoundaryAddr: client.Addr(),
|
||||
}
|
||||
switch keyringType {
|
||||
case "", base.NoneKeyring:
|
||||
keyringType = base.NoneKeyring
|
||||
token := client.Token()
|
||||
if parts := strings.SplitN(token, "_", 4); len(parts) == 3 {
|
||||
pa.AuthTokenId = strings.Join(parts[:2], "_")
|
||||
@@ -129,12 +130,15 @@ func addToken(ctx context.Context, daemonPath string, p *daemon.UpsertTokenReque
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
addr := daemon.SocketAddress(daemonPath)
|
||||
_, err = os.Stat(strings.TrimPrefix(addr, "unix://"))
|
||||
if strings.HasPrefix(addr, "unix://") && err != nil {
|
||||
addr, err := daemon.SocketAddress(daemonPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if err := client.SetAddr(addr); err != nil {
|
||||
_, err = os.Stat(addr.Path)
|
||||
if strings.EqualFold(addr.Scheme, "unix") && err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if err := client.SetAddr(addr.String()); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
// Because this is using the real lib it can pick up from stored locations
|
||||
|
||||
@@ -10,24 +10,31 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/clientcache/internal/daemon"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// Keep this interface aligned with the interface at internal/cmd/commands.go
|
||||
type cacheEnabledCommand interface {
|
||||
cli.Command
|
||||
BaseCommand() *base.Command
|
||||
}
|
||||
|
||||
// CommandWrapper starts the boundary daemon after the command was Run and attempts
|
||||
// to send the current persona to any running daemon.
|
||||
type CommandWrapper struct {
|
||||
cli.Command
|
||||
ui cli.Ui
|
||||
cacheEnabledCommand
|
||||
}
|
||||
|
||||
// Wrap returns a cli.CommandFactory that returns a command wrapped in the CommandWrapper.
|
||||
func Wrap(ui cli.Ui, wrapped cli.Command) cli.CommandFactory {
|
||||
func Wrap(c cacheEnabledCommand) cli.CommandFactory {
|
||||
return func() (cli.Command, error) {
|
||||
return &CommandWrapper{
|
||||
Command: wrapped,
|
||||
ui: ui,
|
||||
cacheEnabledCommand: c,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@@ -35,11 +42,18 @@ func Wrap(ui cli.Ui, wrapped cli.Command) cli.CommandFactory {
|
||||
// Run runs the wrapped command and then attempts to start the boundary daemon and send
|
||||
// the current persona
|
||||
func (w *CommandWrapper) Run(args []string) int {
|
||||
r := w.Command.Run(args)
|
||||
if w.BaseCommand().FlagSkipCacheDaemon {
|
||||
return w.cacheEnabledCommand.Run(args)
|
||||
}
|
||||
|
||||
// potentially intercept the token in case it isn't stored in the keyring
|
||||
var token string
|
||||
w.cacheEnabledCommand.BaseCommand().Opts = append(w.cacheEnabledCommand.BaseCommand().Opts, base.WithInterceptedToken(&token))
|
||||
r := w.cacheEnabledCommand.Run(args)
|
||||
|
||||
ctx := context.Background()
|
||||
if w.startDaemon(ctx) {
|
||||
w.addPersonaInCache(ctx)
|
||||
w.addTokenToCache(ctx, token)
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -49,7 +63,7 @@ func (w *CommandWrapper) Run(args []string) int {
|
||||
func (w *CommandWrapper) startDaemon(ctx context.Context) bool {
|
||||
cmdName, err := os.Executable()
|
||||
if err != nil {
|
||||
w.ui.Error(fmt.Sprintf("unable to find boundary binary for daemon startup: %s", err.Error()))
|
||||
w.BaseCommand().UI.Error(fmt.Sprintf("unable to find boundary binary for daemon startup: %s", err.Error()))
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -64,10 +78,59 @@ func (w *CommandWrapper) startDaemon(ctx context.Context) bool {
|
||||
return err == nil || strings.Contains(stdErr.String(), "already running")
|
||||
}
|
||||
|
||||
// addPersonaInCache runs AddPersonaCommand
|
||||
func (w *CommandWrapper) addPersonaInCache(ctx context.Context) bool {
|
||||
c := AddTokenCommand{Command: base.NewCommand(w.ui)}
|
||||
c.Flags()
|
||||
apiErr, err := c.Add(ctx)
|
||||
// addTokenToCache runs AddTokenCommand with the token used in, or retrieved by
|
||||
// the wrapped command.
|
||||
func (w *CommandWrapper) addTokenToCache(ctx context.Context, token string) bool {
|
||||
com := AddTokenCommand{Command: base.NewCommand(w.BaseCommand().UI)}
|
||||
client, err := w.BaseCommand().Client()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
keyringType, tokName, err := w.BaseCommand().DiscoverKeyringTokenInfo()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if token != "" {
|
||||
client.SetToken(token)
|
||||
}
|
||||
|
||||
// Since the daemon might have just started, we need to wait until it can
|
||||
// respond to our requests
|
||||
waitCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
if err := waitForDaemon(waitCtx); err != nil {
|
||||
// TODO: Print the result of this out into a log in the dot directory
|
||||
return false
|
||||
}
|
||||
|
||||
apiErr, err := com.Add(ctx, client, keyringType, tokName)
|
||||
return err == nil && apiErr == nil
|
||||
}
|
||||
|
||||
// waitForDaemon continually looks for the unix socket until it is found or the
|
||||
// provided context is done. It returns an error if the unix socket is not found
|
||||
// before the context is done.
|
||||
func waitForDaemon(ctx context.Context) error {
|
||||
const op = "daemon.waitForDaemon"
|
||||
dotPath, err := DefaultDotDirectory(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
timer := time.NewTimer(0)
|
||||
|
||||
addr, err := daemon.SocketAddress(dotPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
_, err = os.Stat(addr.Path)
|
||||
for os.IsNotExist(err) {
|
||||
select {
|
||||
case <-timer.C:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
_, err = os.Stat(addr.Path)
|
||||
timer.Reset(10 * time.Millisecond)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -69,12 +69,15 @@ func (s *StopCommand) stop(ctx context.Context) error {
|
||||
func stopThroughHandler(ctx context.Context, dotPath string) (*api.Error, error) {
|
||||
const op = "daemon.stopThroughHandler"
|
||||
|
||||
sockAddr := daemon.SocketAddress(dotPath)
|
||||
sockAddr, err := daemon.SocketAddress(dotPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
client, err := api.NewClient(nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if err := client.SetAddr(sockAddr); err != nil {
|
||||
if err := client.SetAddr(sockAddr.String()); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
// Because this is using the real lib it can pick up from stored locations
|
||||
|
||||
@@ -169,14 +169,14 @@ func search(ctx context.Context, daemonPath string, fb filterBy) (*api.Response,
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
addr := daemon.SocketAddress(daemonPath)
|
||||
addr, err := daemon.SocketAddress(daemonPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if _, err := os.Stat(strings.TrimPrefix(addr, "unix://")); strings.HasPrefix(addr, "unix://") && err == os.ErrNotExist {
|
||||
if _, err := os.Stat(addr.Path); addr.Scheme == "unix" && err == os.ErrNotExist {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "daemon unix socket is not setup")
|
||||
}
|
||||
if err := client.SetAddr(addr); err != nil {
|
||||
if err := client.SetAddr(addr.String()); err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,24 +25,12 @@ type testCommander struct {
|
||||
at *authtokens.AuthToken
|
||||
}
|
||||
|
||||
func (r *testCommander) keyring() string {
|
||||
return r.at.Id
|
||||
}
|
||||
|
||||
func (r *testCommander) tokenName() string {
|
||||
return r.at.Id
|
||||
}
|
||||
|
||||
func (r *testCommander) Client(opt ...base.Option) (*api.Client, error) {
|
||||
client, err := api.NewClient(nil)
|
||||
require.NoError(r.t, err)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (r *testCommander) DiscoverKeyringTokenInfo() (string, string, error) {
|
||||
return r.keyring(), r.tokenName(), nil
|
||||
}
|
||||
|
||||
func (r *testCommander) ReadTokenFromKeyring(k, a string) *authtokens.AuthToken {
|
||||
return r.at
|
||||
}
|
||||
@@ -72,6 +60,7 @@ func TestSearch(t *testing.T) {
|
||||
}()
|
||||
// Give the store some time to get initialized
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
srv.AddKeyringToken(t, "address", "keyringtype", "tokenname", at.Id, boundaryTokenReaderFn)
|
||||
|
||||
errorCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -52,8 +53,7 @@ func listener(ctx context.Context, path string) (net.Listener, error) {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// SocketAddress returns the unix socket filename with a 'unix://' prefix.
|
||||
// The returned value can be passed directly into the api.Client
|
||||
func SocketAddress(path string) string {
|
||||
return fmt.Sprintf("unix://%s", filepath.Join(path, sockAddr))
|
||||
// SocketAddress returns the unix socket *url.URL with the scheme set to 'unix'.
|
||||
func SocketAddress(path string) (*url.URL, error) {
|
||||
return url.Parse(fmt.Sprintf("unix://%s", filepath.Join(path, sockAddr)))
|
||||
}
|
||||
@@ -45,7 +45,9 @@ func TestListenComms(t *testing.T) {
|
||||
|
||||
client, err := api.NewClient(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.SetAddr(SocketAddress(path)))
|
||||
u, err := SocketAddress(path)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.SetAddr(u.String()))
|
||||
client.SetToken("")
|
||||
req, err := client.NewRequest(ctx, "GET", "/test", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -35,7 +35,6 @@ import (
|
||||
// and retrieve the keyring and token information used by a command.
|
||||
type Commander interface {
|
||||
ClientProvider
|
||||
DiscoverKeyringTokenInfo() (string, string, error)
|
||||
ReadTokenFromKeyring(keyringType, tokenName string) *authtokens.AuthToken
|
||||
}
|
||||
|
||||
@@ -207,27 +206,6 @@ func (s *CacheServer) Serve(ctx context.Context, cmd Commander, opt ...Option) e
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
// If we have a token info already, add it to the repository immediately so
|
||||
// it can start to get updated.
|
||||
func() {
|
||||
client, err := cmd.Client()
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err)
|
||||
return
|
||||
}
|
||||
krType, tokName, err := cmd.DiscoverKeyringTokenInfo()
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err)
|
||||
return
|
||||
}
|
||||
if at := cmd.ReadTokenFromKeyring(krType, tokName); at != nil {
|
||||
if err := repo.AddKeyringToken(ctx, client.Addr(), cache.KeyringToken{KeyringType: krType, TokenName: tokName, AuthTokenId: at.Id}); err != nil {
|
||||
event.WriteError(ctx, op, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
refreshService, err := cache.NewRefreshService(ctx, repo)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
|
||||
@@ -68,6 +68,19 @@ func (s *TestServer) Serve(t *testing.T, opt ...Option) error {
|
||||
return s.CacheServer.Serve(ctx, s.cmd, opt...)
|
||||
}
|
||||
|
||||
func (s *TestServer) AddKeyringToken(t *testing.T, address, keyring, tokenName, tokenId string, atReadFn cache.BoundaryTokenReaderFn) {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
r, err := cache.NewRepository(ctx, s.CacheServer.store, &sync.Map{}, s.cmd.ReadTokenFromKeyring, atReadFn)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, r.AddKeyringToken(ctx, address, cache.KeyringToken{
|
||||
KeyringType: keyring,
|
||||
TokenName: tokenName,
|
||||
AuthTokenId: tokenId,
|
||||
}))
|
||||
}
|
||||
|
||||
// AddResources adds targets to the cache for the provided address, token name,
|
||||
// and keyring type. They token info must already be known to the server.
|
||||
func (s *TestServer) AddResources(t *testing.T, p *authtokens.AuthToken, tars []*targets.Target, sess []*sessions.Session, atReadFn cache.BoundaryTokenReaderFn) {
|
||||
|
||||
@@ -64,10 +64,11 @@ const (
|
||||
// maxLineLength is the maximum width of any line.
|
||||
maxLineLength int = 78
|
||||
|
||||
envToken = "BOUNDARY_TOKEN"
|
||||
EnvTokenName = "BOUNDARY_TOKEN_NAME"
|
||||
EnvKeyringType = "BOUNDARY_KEYRING_TYPE"
|
||||
envRecoveryConfig = "BOUNDARY_RECOVERY_CONFIG"
|
||||
envToken = "BOUNDARY_TOKEN"
|
||||
EnvTokenName = "BOUNDARY_TOKEN_NAME"
|
||||
EnvKeyringType = "BOUNDARY_KEYRING_TYPE"
|
||||
envRecoveryConfig = "BOUNDARY_RECOVERY_CONFIG"
|
||||
envSkipCacheDaemon = "BOUNDARY_SKIP_CACHE_DAEMON"
|
||||
|
||||
StoredTokenName = "HashiCorp Boundary Auth Token"
|
||||
)
|
||||
@@ -84,6 +85,8 @@ type Command struct {
|
||||
UI cli.Ui
|
||||
ShutdownCh chan struct{}
|
||||
|
||||
Opts []Option
|
||||
|
||||
flags *FlagSets
|
||||
flagsOnce sync.Once
|
||||
|
||||
@@ -103,6 +106,7 @@ type Command struct {
|
||||
FlagKeyringType string
|
||||
FlagRecoveryConfig string
|
||||
FlagOutputCurlString bool
|
||||
FlagSkipCacheDaemon bool
|
||||
|
||||
FlagScopeId string
|
||||
FlagScopeName string
|
||||
@@ -189,6 +193,10 @@ func MakeShutdownCh() chan struct{} {
|
||||
return resultCh
|
||||
}
|
||||
|
||||
func (c *Command) BaseCommand() *Command {
|
||||
return c
|
||||
}
|
||||
|
||||
// Client returns the HTTP API client. The client is cached on the command to
|
||||
// save performance on future calls.
|
||||
func (c *Command) Client(opt ...Option) (*api.Client, error) {
|
||||
@@ -197,7 +205,7 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) {
|
||||
return c.client, nil
|
||||
}
|
||||
|
||||
opts := getOpts(opt...)
|
||||
opts := GetOpts(opt...)
|
||||
|
||||
config, err := api.DefaultConfig()
|
||||
if err != nil {
|
||||
@@ -455,6 +463,14 @@ func (c *Command) FlagSet(bit FlagSetBit) *FlagSets {
|
||||
Target: &c.FlagOutputCurlString,
|
||||
Usage: "Instead of executing the request, print an equivalent cURL command string and exit.",
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "skip-cache-daemon",
|
||||
Target: &c.FlagSkipCacheDaemon,
|
||||
Default: false,
|
||||
EnvVar: envSkipCacheDaemon,
|
||||
Usage: "Skips starting the caching daemon or sending the current used/retrieved token to the caching daemon.",
|
||||
})
|
||||
}
|
||||
|
||||
if bit&FlagSetOutputFormat != 0 {
|
||||
|
||||
@@ -35,7 +35,7 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error {
|
||||
var err error
|
||||
var c func() error
|
||||
|
||||
opts := getOpts(opt...)
|
||||
opts := GetOpts(opt...)
|
||||
|
||||
// We should only get back postgres for now, but laying the foundation for non-postgres
|
||||
switch opts.withDialect {
|
||||
|
||||
@@ -182,7 +182,7 @@ func WrapMap(prefixSpaces, maxLengthOverride int, input map[string]any) string {
|
||||
// information, to the UI in the appropriate format. WithAttributeFieldPrefix is
|
||||
// used, all other options are ignored.
|
||||
func (c *Command) PrintApiError(in *api.Error, contextStr string, opt ...Option) {
|
||||
opts := getOpts(opt...)
|
||||
opts := GetOpts(opt...)
|
||||
switch Format(c.UI) {
|
||||
case "json":
|
||||
var b []byte
|
||||
@@ -310,7 +310,7 @@ func (c *Command) PrintJsonItem(resp *api.Response, opt ...Option) bool {
|
||||
|
||||
// PrintJson prints the given raw JSON in our common format
|
||||
func (c *Command) PrintJson(input json.RawMessage, opt ...Option) bool {
|
||||
opts := getOpts(opt...)
|
||||
opts := GetOpts(opt...)
|
||||
output := struct {
|
||||
StatusCode int `json:"status_code,omitempty"`
|
||||
Item json.RawMessage `json:"item,omitempty"`
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
)
|
||||
|
||||
// getOpts - iterate the inbound Options and return a struct.
|
||||
func getOpts(opt ...Option) Options {
|
||||
// GetOpts - iterate the inbound Options and return a struct.
|
||||
func GetOpts(opt ...Option) Options {
|
||||
opts := getDefaultOptions()
|
||||
for _, o := range opt {
|
||||
if o != nil {
|
||||
@@ -45,6 +45,8 @@ type Options struct {
|
||||
withHostPlugin func() (string, plugin.HostPluginServiceClient)
|
||||
withEventGating bool
|
||||
withImplicitId string
|
||||
WithSkipScopeIdFlag bool
|
||||
WithInterceptedToken *string
|
||||
}
|
||||
|
||||
func getDefaultOptions() Options {
|
||||
@@ -209,3 +211,19 @@ func WithImplicitId(with string) Option {
|
||||
o.withImplicitId = with
|
||||
}
|
||||
}
|
||||
|
||||
// WithSkipScopeIdFlag tells a command to not create a scope ID flag (usually
|
||||
// because it's already been defined)
|
||||
func WithSkipScopeIdFlag(with bool) Option {
|
||||
return func(o *Options) {
|
||||
o.WithSkipScopeIdFlag = with
|
||||
}
|
||||
}
|
||||
|
||||
// WithInterceptedToken provides a string pointer that will have the token
|
||||
// assigned to it when performing an authenticate command.
|
||||
func WithInterceptedToken(s *string) Option {
|
||||
return func(o *Options) {
|
||||
o.WithInterceptedToken = s
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ func Test_GetOpts(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("nil-options", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(nil, nil)
|
||||
opts := GetOpts(nil, nil)
|
||||
testOpts := getDefaultOptions()
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
@@ -28,7 +28,7 @@ func Test_GetOpts(t *testing.T) {
|
||||
ObservationsEnabled: &isTrue,
|
||||
SysEventsEnabled: &isTrue,
|
||||
}
|
||||
opts := getOpts(WithEventFlags(&f))
|
||||
opts := GetOpts(WithEventFlags(&f))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withEventFlags = &f
|
||||
assert.Equal(opts, testOpts)
|
||||
@@ -45,84 +45,84 @@ func Test_GetOpts(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
opts := getOpts(WithEventerConfig(&c))
|
||||
opts := GetOpts(WithEventerConfig(&c))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withEventerConfig = &c
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithNoTokenScope", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithNoTokenScope())
|
||||
opts := GetOpts(WithNoTokenScope())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withNoTokenScope = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipDatabaseDestruction", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithSkipDatabaseDestruction())
|
||||
opts := GetOpts(WithSkipDatabaseDestruction())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipDatabaseDestruction = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithNoTokenValue", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithNoTokenValue())
|
||||
opts := GetOpts(WithNoTokenValue())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withNoTokenValue = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipAuthMethodCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithSkipAuthMethodCreation())
|
||||
opts := GetOpts(WithSkipAuthMethodCreation())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipAuthMethodCreation = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipOidcAuthMethodCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithSkipOidcAuthMethodCreation())
|
||||
opts := GetOpts(WithSkipOidcAuthMethodCreation())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipOidcAuthMethodCreation = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipLdapAuthMethodCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithSkipLdapAuthMethodCreation())
|
||||
opts := GetOpts(WithSkipLdapAuthMethodCreation())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipLdapAuthMethodCreation = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipScopesCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithSkipScopesCreation())
|
||||
opts := GetOpts(WithSkipScopesCreation())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipScopesCreation = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipHostResourcesCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithSkipHostResourcesCreation())
|
||||
opts := GetOpts(WithSkipHostResourcesCreation())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipHostResourcesCreation = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithSkipTargetCreation", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithSkipTargetCreation())
|
||||
opts := GetOpts(WithSkipTargetCreation())
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withSkipTargetCreation = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithContainerImage", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(WithContainerImage("test-container"))
|
||||
opts := GetOpts(WithContainerImage("test-container"))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withContainerImage = "test-container"
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("withDialect", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := getOpts(withDialect("test-dialect"))
|
||||
opts := GetOpts(withDialect("test-dialect"))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.withDialect = "test-dialect"
|
||||
assert.Equal(opts, testOpts)
|
||||
@@ -131,7 +131,24 @@ func Test_GetOpts(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testOpts := getDefaultOptions()
|
||||
assert.False(testOpts.withEventGating)
|
||||
opts := getOpts(WithEventGating(true))
|
||||
opts := GetOpts(WithEventGating(true))
|
||||
assert.True(opts.withEventGating)
|
||||
})
|
||||
|
||||
t.Run("WithSkipScopeIdFlag", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
opts := GetOpts(WithSkipScopeIdFlag(true))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.WithSkipScopeIdFlag = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
|
||||
t.Run("WithSkipScopeIdFlag", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
var s string
|
||||
opts := GetOpts(WithInterceptedToken(&s))
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.WithInterceptedToken = &s
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
}
|
||||
@@ -175,7 +175,7 @@ func (b *Server) SetupEventing(ctx context.Context, logger hclog.Logger, seriali
|
||||
if serverName == "" {
|
||||
return berrors.New(ctx, berrors.InvalidParameter, op, "missing server name")
|
||||
}
|
||||
opts := getOpts(opt...)
|
||||
opts := GetOpts(opt...)
|
||||
if opts.withEventerConfig != nil {
|
||||
if err := opts.withEventerConfig.Validate(); err != nil {
|
||||
return berrors.Wrap(ctx, err, op, berrors.WithMsg("invalid eventer config"))
|
||||
|
||||
+187
-194
File diff suppressed because it is too large.
Load diff
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/common"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/go-wordwrap"
|
||||
@@ -104,15 +103,18 @@ func (c *Command) Run(args []string) int {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(c.FlagAuthMethodId, globals.PasswordAuthMethodPrefix):
|
||||
cmd := PasswordCommand{Command: c.Command, Opts: []common.Option{common.WithSkipScopeIdFlag(true)}}
|
||||
cmd := PasswordCommand{Command: c.Command}
|
||||
cmd.Opts = append(c.Opts, base.WithSkipScopeIdFlag(true))
|
||||
cmd.Run([]string{})
|
||||
|
||||
case strings.HasPrefix(c.FlagAuthMethodId, globals.OidcAuthMethodPrefix):
|
||||
cmd := OidcCommand{Command: c.Command, Opts: []common.Option{common.WithSkipScopeIdFlag(true)}}
|
||||
cmd := OidcCommand{Command: c.Command}
|
||||
cmd.Opts = append(c.Opts, base.WithSkipScopeIdFlag(true))
|
||||
cmd.Run([]string{})
|
||||
|
||||
case strings.HasPrefix(c.FlagAuthMethodId, globals.LdapAuthMethodPrefix):
|
||||
cmd := LdapCommand{Command: c.Command, Opts: []common.Option{common.WithSkipScopeIdFlag(true)}}
|
||||
cmd := LdapCommand{Command: c.Command}
|
||||
cmd.Opts = append(c.Opts, base.WithSkipScopeIdFlag(true))
|
||||
cmd.Run([]string{})
|
||||
|
||||
default:
|
||||
|
||||
@@ -18,12 +18,13 @@ import (
|
||||
zkeyring "github.com/zalando/go-keyring"
|
||||
)
|
||||
|
||||
func saveAndOrPrintToken(c *base.Command, result *authmethods.AuthenticateResult) int {
|
||||
func saveAndOrPrintToken(c *base.Command, result *authmethods.AuthenticateResult, opt ...base.Option) int {
|
||||
token := new(authtokens.AuthToken)
|
||||
if err := json.Unmarshal(result.GetRawAttributes(), token); err != nil {
|
||||
c.PrintCliError(fmt.Errorf("Error trying to decode response as an auth token: %w", err))
|
||||
return base.CommandCliError
|
||||
}
|
||||
opts := base.GetOpts(opt...)
|
||||
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
@@ -101,6 +102,10 @@ func saveAndOrPrintToken(c *base.Command, result *authmethods.AuthenticateResult
|
||||
c.UI.Warn("\nStoring the token in a keyring was disabled. The token is:")
|
||||
c.UI.Output(token.Token)
|
||||
c.UI.Warn("Please be sure to store it safely!")
|
||||
|
||||
if opts.WithInterceptedToken != nil {
|
||||
*opts.WithInterceptedToken = token.Token
|
||||
}
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/common"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/go-secure-stdlib/password"
|
||||
@@ -32,8 +31,7 @@ type LdapCommand struct {
|
||||
|
||||
flagLoginName string
|
||||
flagPassword string
|
||||
Opts []common.Option
|
||||
parsedOpts *common.Options
|
||||
parsedOpts base.Options
|
||||
}
|
||||
|
||||
func (c *LdapCommand) Synopsis() string {
|
||||
@@ -77,7 +75,7 @@ func (c *LdapCommand) Flags() *base.FlagSets {
|
||||
Usage: "The auth-method resource to use for the operation.",
|
||||
})
|
||||
|
||||
if c.parsedOpts == nil || !c.parsedOpts.WithSkipScopeIdFlag {
|
||||
if !c.parsedOpts.WithSkipScopeIdFlag {
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "scope-id",
|
||||
EnvVar: "BOUNDARY_SCOPE_ID",
|
||||
@@ -98,12 +96,7 @@ func (c *LdapCommand) AutocompleteFlags() complete.Flags {
|
||||
}
|
||||
|
||||
func (c *LdapCommand) Run(args []string) int {
|
||||
opts, err := common.GetOpts(c.Opts...)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandCliError
|
||||
}
|
||||
c.parsedOpts = opts
|
||||
c.parsedOpts = base.GetOpts(c.Opts...)
|
||||
|
||||
f := c.Flags()
|
||||
if err := f.Parse(args); err != nil {
|
||||
@@ -193,5 +186,5 @@ func (c *LdapCommand) Run(args []string) int {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
return saveAndOrPrintToken(c.Command, result)
|
||||
return saveAndOrPrintToken(c.Command, result, c.Opts...)
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/common"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/cap/util"
|
||||
"github.com/mitchellh/cli"
|
||||
@@ -30,8 +29,7 @@ var (
|
||||
type OidcCommand struct {
|
||||
*base.Command
|
||||
|
||||
Opts []common.Option
|
||||
parsedOpts *common.Options
|
||||
parsedOpts base.Options
|
||||
}
|
||||
|
||||
func (c *OidcCommand) Synopsis() string {
|
||||
@@ -61,7 +59,7 @@ func (c *OidcCommand) Flags() *base.FlagSets {
|
||||
Usage: "The auth-method resource to use for the operation",
|
||||
})
|
||||
|
||||
if c.parsedOpts == nil || !c.parsedOpts.WithSkipScopeIdFlag {
|
||||
if !c.parsedOpts.WithSkipScopeIdFlag {
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "scope-id",
|
||||
EnvVar: "BOUNDARY_SCOPE_ID",
|
||||
@@ -81,13 +79,7 @@ func (c *OidcCommand) AutocompleteFlags() complete.Flags {
|
||||
}
|
||||
|
||||
func (c *OidcCommand) Run(args []string) int {
|
||||
opts, err := common.GetOpts(c.Opts...)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandCliError
|
||||
}
|
||||
c.parsedOpts = opts
|
||||
|
||||
c.parsedOpts = base.GetOpts(c.Opts...)
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
@@ -196,5 +188,5 @@ func (c *OidcCommand) Run(args []string) int {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
return saveAndOrPrintToken(c.Command, result)
|
||||
return saveAndOrPrintToken(c.Command, result, c.Opts...)
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/common"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/go-secure-stdlib/password"
|
||||
"github.com/mitchellh/cli"
|
||||
@@ -37,8 +36,7 @@ type PasswordCommand struct {
|
||||
flagLoginName string
|
||||
flagPassword string
|
||||
|
||||
Opts []common.Option
|
||||
parsedOpts *common.Options
|
||||
parsedOpts base.Options
|
||||
}
|
||||
|
||||
func (c *PasswordCommand) Synopsis() string {
|
||||
@@ -82,7 +80,7 @@ func (c *PasswordCommand) Flags() *base.FlagSets {
|
||||
Usage: "The auth-method resource to use for the operation.",
|
||||
})
|
||||
|
||||
if c.parsedOpts == nil || !c.parsedOpts.WithSkipScopeIdFlag {
|
||||
if !c.parsedOpts.WithSkipScopeIdFlag {
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "scope-id",
|
||||
EnvVar: "BOUNDARY_SCOPE_ID",
|
||||
@@ -103,12 +101,7 @@ func (c *PasswordCommand) AutocompleteFlags() complete.Flags {
|
||||
}
|
||||
|
||||
func (c *PasswordCommand) Run(args []string) int {
|
||||
opts, err := common.GetOpts(c.Opts...)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandCliError
|
||||
}
|
||||
c.parsedOpts = opts
|
||||
c.parsedOpts = base.GetOpts(c.Opts...)
|
||||
|
||||
f := c.Flags()
|
||||
|
||||
@@ -199,5 +192,5 @@ func (c *PasswordCommand) Run(args []string) int {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
return saveAndOrPrintToken(c.Command, result)
|
||||
return saveAndOrPrintToken(c.Command, result, c.Opts...)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package common
|
||||
|
||||
// GetOpts - iterate the inbound Options and return a struct.
|
||||
func GetOpts(opt ...Option) (*Options, error) {
|
||||
opts := getDefaultOptions()
|
||||
for _, o := range opt {
|
||||
if o == nil {
|
||||
continue
|
||||
}
|
||||
if err := o(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// Option - how Options are passed as arguments.
|
||||
type Option func(*Options) error
|
||||
|
||||
// Options - how Options are represented.
|
||||
type Options struct {
|
||||
WithSkipScopeIdFlag bool
|
||||
}
|
||||
|
||||
func getDefaultOptions() *Options {
|
||||
return &Options{}
|
||||
}
|
||||
|
||||
// WithSkipScopeIdFlag tells a command to not create a scope ID flag (usually
|
||||
// because it's already been defined)
|
||||
func WithSkipScopeIdFlag(with bool) Option {
|
||||
return func(o *Options) error {
|
||||
o.WithSkipScopeIdFlag = with
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Test_GetOpts provides unit tests for GetOpts and all the options
|
||||
func Test_GetOpts(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("nil-options", func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
opts, err := GetOpts(nil, nil)
|
||||
require.NoError(err)
|
||||
testOpts := getDefaultOptions()
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
|
||||
t.Run("WithSkipScopeIdFlag", func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
opts, err := GetOpts(WithSkipScopeIdFlag(true))
|
||||
require.NoError(err)
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.WithSkipScopeIdFlag = true
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
commandFactoryWrapper = daemonWrap
|
||||
clientCacheWrapper = daemonWrap
|
||||
|
||||
extraCommandsFuncs = append(extraCommandsFuncs, func(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
delete(Commands, "daemon")
|
||||
@@ -38,8 +38,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// daemonWrap wraps the provided wrappableCommand with a daemon writer which
|
||||
// daemonWrap wraps the provided cacheEnabledCommand with a daemon writer which
|
||||
// conditionally starts the client side daemon after the command completes
|
||||
func daemonWrap(ui cli.Ui, c wrappableCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(ui, c)
|
||||
func daemonWrap(c cacheEnabledCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(c)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
commandFactoryWrapper = daemonWrap
|
||||
clientCacheWrapper = daemonWrap
|
||||
|
||||
extraCommandsFuncs = append(extraCommandsFuncs, func(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
delete(Commands, "daemon")
|
||||
@@ -40,8 +40,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// daemonWrap wraps the provided wrappableCommand with a daemon writer which
|
||||
// daemonWrap wraps the provided cacheEnabledCommand with a daemon writer which
|
||||
// conditionally starts the client side daemon after the command completes
|
||||
func daemonWrap(ui cli.Ui, c wrappableCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(ui, c)
|
||||
func daemonWrap(c cacheEnabledCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(c)
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
commandFactoryWrapper = daemonWrap
|
||||
clientCacheWrapper = daemonWrap
|
||||
|
||||
extraCommandsFuncs = append(extraCommandsFuncs, func(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
delete(Commands, "daemon")
|
||||
@@ -38,8 +38,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// daemonWrap wraps the provided wrappableCommand with a daemon writer which
|
||||
// daemonWrap wraps the provided cacheEnabledCommand with a daemon writer which
|
||||
// conditionally starts the client side daemon after the command completes
|
||||
func daemonWrap(ui cli.Ui, c wrappableCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(ui, c)
|
||||
func daemonWrap(c cacheEnabledCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(c)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
commandFactoryWrapper = daemonWrap
|
||||
clientCacheWrapper = daemonWrap
|
||||
|
||||
extraCommandsFuncs = append(extraCommandsFuncs, func(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
delete(Commands, "daemon")
|
||||
@@ -40,8 +40,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// daemonWrap wraps the provided wrappableCommand with a daemon writer which
|
||||
// daemonWrap wraps the provided cacheEnabledCommand with a daemon writer which
|
||||
// conditionally starts the client side daemon after the command completes
|
||||
func daemonWrap(ui cli.Ui, c wrappableCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(ui, c)
|
||||
func daemonWrap(c cacheEnabledCommand) cli.CommandFactory {
|
||||
return daemon.Wrap(c)
|
||||
}
|
||||
Reference in new issue
Block a user