Refresh specific resources before searching when they are stale (#4046)

validate versions for all handlers. Refresh specific user before searching

Pass flags on to the background process

Allow the search refresh timeout to be configured
This commit is contained in:
Todd authored and Johan Brandhorst-Satzkorn committed 2024-01-05 07:43:20 -08:00
1 parent b3d268eae5
commit cdc6fb0973
19 files changed
+543 -100

No files matched your search

@@ -51,6 +51,12 @@ func (w *CommandWrapper) Run(args []string) int {
w.cacheEnabledCommand.BaseCommand().Opts = append(w.cacheEnabledCommand.BaseCommand().Opts, base.WithInterceptedToken(&token))
r := w.cacheEnabledCommand.Run(args)
if r != base.CommandSuccess {
// if we were not successful in running our command, do not continue to
// start the daemon and add the token.
return r
}
ctx := context.Background()
if w.startDaemon(ctx) {
w.addTokenToCache(ctx, token)
+69 -29
View File
@@ -49,13 +49,15 @@ type server interface {
type StartCommand struct {
*base.Command
flagRefreshInterval time.Duration
flagFullFetchInterval time.Duration
flagDatabaseUrl string
flagLogLevel string
flagLogFormat string
flagStoreDebug bool
flagBackground bool
flagRefreshInterval time.Duration
flagFullFetchInterval time.Duration
flagMaxSearchStaleness time.Duration
flagMaxSearchRefreshTimeout time.Duration
flagDatabaseUrl string
flagLogLevel string
flagLogFormat string
flagStoreDebug bool
flagBackground bool
}
func (c *StartCommand) Synopsis() string {
@@ -100,29 +102,41 @@ func (c *StartCommand) Flags() *base.FlagSets {
Usage: `If set, specifies the URL used to connect to the sqlite database (store) for caching. This can refer to a file on disk (file://) from which a URL will be read; an env var (env://) from which the URL will be read; or a direct database URL.`,
})
f.DurationVar(&base.DurationVar{
Name: "refresh-interval-seconds",
Name: "refresh-interval",
Target: &c.flagRefreshInterval,
Usage: `If set, specifies the number of seconds between refresh token supported cache refreshes. Default: 1 minute`,
Default: daemon.DefaultRefreshIntervalSeconds * time.Second,
Usage: `Specifies the interval between refresh token supported cache refreshes. Default: 1 minute`,
Default: daemon.DefaultRefreshInterval,
})
f.DurationVar(&base.DurationVar{
Name: "full-fetch-interval-seconds",
Name: "full-fetch-interval",
Target: &c.flagFullFetchInterval,
Usage: `If set, specifies the number of seconds between full cache refresh for boundary instances which do not support refresh tokens. Default: 5 minutes`,
Default: daemon.DefaultFullFetchIntervalSeconds * time.Second,
Usage: `Specifies the interval between full cache refresh for boundary instances which do not support refresh tokens. Default: 5 minutes`,
Default: daemon.DefaultFullFetchInterval,
})
f.DurationVar(&base.DurationVar{
Name: "max-search-staleness",
Target: &c.flagMaxSearchStaleness,
Usage: `Specifies the duration of time that can pass since the resource was last updated before performing a search waits for the resources being refreshed first. Default: 1 minute`,
Default: daemon.DefaultSearchStaleness,
})
f.DurationVar(&base.DurationVar{
Name: "max-search-refresh-timeout",
Target: &c.flagMaxSearchRefreshTimeout,
Usage: `If a search request triggers a best effort refresh, this specifies how long the refresh should run before timing out. Default: 1 second`,
Default: daemon.DefaultSearchRefreshTimeout,
})
f.BoolVar(&base.BoolVar{
Name: "store-debug",
Target: &c.flagStoreDebug,
Default: false,
Usage: `Turn on store debugging`,
Usage: `Turn on sqlite query debugging`,
Aliases: []string{"d"},
})
f.BoolVar(&base.BoolVar{
Name: "background",
Target: &c.flagBackground,
Default: false,
Usage: `Turn on store debugging`,
Usage: `Run the client cache daemon in the background`,
})
return set
@@ -156,7 +170,7 @@ func (c *StartCommand) Run(args []string) int {
return base.CommandCliError
}
continueRun, writers, cleanup, err := makeBackground(ctx, dotDir, c.flagBackground)
continueRun, writers, cleanup, err := c.makeBackground(ctx, dotDir)
defer func() {
if cleanup != nil {
cleanup()
@@ -182,15 +196,16 @@ func (c *StartCommand) Run(args []string) int {
writers = append(writers, lf)
cfg := &daemon.Config{
ContextCancel: cancel,
RefreshInterval: c.flagRefreshInterval,
FullFetchInterval: c.flagFullFetchInterval,
DatabaseUrl: c.flagDatabaseUrl,
StoreDebug: c.flagStoreDebug,
LogLevel: c.flagLogLevel,
LogFormat: c.flagLogFormat,
LogWriter: io.MultiWriter(writers...),
DotDirectory: dotDir,
ContextCancel: cancel,
RefreshInterval: c.flagRefreshInterval,
FullFetchInterval: c.flagFullFetchInterval,
MaxSearchStaleness: c.flagMaxSearchStaleness,
DatabaseUrl: c.flagDatabaseUrl,
StoreDebug: c.flagStoreDebug,
LogLevel: c.flagLogLevel,
LogFormat: c.flagLogFormat,
LogWriter: io.MultiWriter(writers...),
DotDirectory: dotDir,
}
srv, err := daemon.New(ctx, cfg)
@@ -259,7 +274,7 @@ func logFile(ctx context.Context, dotDir string, maxSizeMb int) (io.WriteCloser,
return logFile, nil
}
func makeBackground(ctx context.Context, dotDir string, runBackgroundFlag bool) (bool, []io.Writer, pidCleanup, error) {
func (c *StartCommand) makeBackground(ctx context.Context, dotDir string) (bool, []io.Writer, pidCleanup, error) {
const op = "daemon.makeBackground"
writers := []io.Writer{}
@@ -270,11 +285,11 @@ func makeBackground(ctx context.Context, dotDir string, runBackgroundFlag bool)
return false, writers, noopPidCleanup, fmt.Errorf("Error when checking if the daemon pid is in use: %w.", err)
}
if !runBackgroundFlag && os.Getenv(backgroundEnvName) != backgroundEnvVal {
if !c.flagBackground && os.Getenv(backgroundEnvName) != backgroundEnvVal {
writers = append(writers, os.Stderr)
}
if !runBackgroundFlag || os.Getenv(backgroundEnvName) == backgroundEnvVal {
if !c.flagBackground || os.Getenv(backgroundEnvName) == backgroundEnvVal {
// We are either already running in the background or background was
// not requested. Write the pid file and continue.
cleanup, err := writePidFile(ctx, pidPath)
@@ -291,7 +306,32 @@ func makeBackground(ctx context.Context, dotDir string, runBackgroundFlag bool)
env := os.Environ()
env = append(env, fmt.Sprintf("%s=%s", backgroundEnvName, backgroundEnvVal))
cmd := exec.Command(absPath, "daemon", "start")
args := []string{"daemon", "start"}
if c.flagLogLevel != "" {
args = append(args, "-log-level", c.flagLogLevel)
}
if c.flagLogFormat != "" {
args = append(args, "-log-format", c.flagLogFormat)
}
if c.flagDatabaseUrl != "" {
args = append(args, "-database-url", c.flagDatabaseUrl)
}
if c.flagRefreshInterval > 0 && c.flagRefreshInterval != daemon.DefaultRefreshInterval {
args = append(args, "-refresh-interval", c.flagRefreshInterval.String())
}
if c.flagFullFetchInterval > 0 && c.flagFullFetchInterval != daemon.DefaultFullFetchInterval {
args = append(args, "-full-fetch-interval", c.flagFullFetchInterval.String())
}
if c.flagMaxSearchStaleness > 0 && c.flagMaxSearchStaleness != daemon.DefaultSearchStaleness {
args = append(args, "-max-search-staleness", c.flagMaxSearchStaleness.String())
}
if c.flagMaxSearchRefreshTimeout > 0 && c.flagMaxSearchRefreshTimeout != daemon.DefaultSearchRefreshTimeout {
args = append(args, "-max-search-refresh-timeout", c.flagMaxSearchRefreshTimeout.String())
}
if c.flagStoreDebug {
args = append(args, "-store-debug")
}
cmd := exec.Command(absPath, args...)
cmd.Env = env
if err = cmd.Start(); err != nil {
return false, writers, noopPidCleanup, errors.Wrap(ctx, err, op)
+1 -1
View File
@@ -20,7 +20,7 @@ import (
"github.com/posener/complete"
)
var errDaemonNotRunning = stderr.New("daemon is not running")
var errDaemonNotRunning = stderr.New("The daemon process is not running.")
var (
_ cli.Command = (*AddTokenCommand)(nil)
+1 -2
View File
@@ -5,7 +5,6 @@ package daemon
import (
"context"
stderr "errors"
"strings"
"github.com/hashicorp/boundary/internal/cmd/base"
@@ -60,7 +59,7 @@ func (c *StopCommand) Run(args []string) int {
}
if err := c.stop(c.Context); err != nil {
if errors.Match(errors.T(errors.NotFound), err) {
c.PrintCliError(stderr.New("The deamon process is not running."))
c.PrintCliError(errDaemonNotRunning)
} else {
c.PrintCliError(err)
}
+6 -3
View File
@@ -32,6 +32,8 @@ var (
"targets",
"sessions",
}
errDaemonNotRunning = stderrors.New("The deamon process is not running.")
)
type SearchCommand struct {
@@ -165,10 +167,11 @@ func (c *SearchCommand) Search(ctx context.Context) (*api.Response, *daemon.Sear
func search(ctx context.Context, daemonPath string, fb filterBy, opt ...client.Option) (*api.Response, *daemon.SearchResult, *api.Error, error) {
addr, err := daemon.SocketAddress(daemonPath)
if err != nil {
return nil, nil, nil, fmt.Errorf("Error when retrieving the socket address: %w", err)
return nil, nil, nil, fmt.Errorf("Error getting socket address: %w", err)
}
if _, err := os.Stat(addr.Path); addr.Scheme == "unix" && err == os.ErrNotExist {
return nil, nil, nil, fmt.Errorf("Error when detecting if the domain socket is present: %w.", err)
_, err = os.Stat(addr.Path)
if addr.Scheme == "unix" && err != nil {
return nil, nil, nil, errDaemonNotRunning
}
c, err := client.New(ctx, addr)
if err != nil {