Support reading multiple configuration files(#2504)
feat(config): Support multiple files This updates the three subcommands that take a `-config` flag to to support multiple config files via a repeated `-config` flag. It updates the following subcommands: - `server` - `database init` - `database migrate` Note that the multiple file support only works if all config files are HCL, not JSON. Also note that the config files are concatenated together. There is no attempt to merge config files, so having the same stanza in multiple files can yield unexpected results, with only one of the stanzas being used. When used with these limitations understood, this provides a way to take different actions for different kinds of dynamic configuration changes. An example would be when using consul-template to render the configuration files for boundary. With the multi file support consul-template can render one config file for the controller stanza, and provide boundary with a dynamic database credential via vault. Then when the credential is rotated, consul-template can send boundary a SIGHUP to switch to the new credential without a restart. A separate template could be used to render a config for a stanza that does not support SIGHUP, such as the events stanza that gets its values via consul's KV. If these values change, consul-template can restart boundary so the new configuration is used. Co-authored-by: Timothy Messier <tim.messier@gmail.com> Co-authored-by: Jeff Mitchell <jeffrey.mitchell@gmail.com>
This commit is contained in:
1 parent
441ca59ea3
commit
d896f37493
22 files changed
+2279
-178
No files matched your search
@@ -5,19 +5,12 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
kms_plugin_assets "github.com/hashicorp/boundary/plugins/kms"
|
||||
"github.com/hashicorp/boundary/sdk/wrapper"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/configutil/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/mlock"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
@@ -41,7 +34,7 @@ type InitCommand struct {
|
||||
// deferred function on the Run method.
|
||||
configWrapperCleanupFunc func() error
|
||||
|
||||
flagConfig string
|
||||
flagConfig []string
|
||||
flagConfigKms string
|
||||
flagLogLevel string
|
||||
flagLogFormat string
|
||||
@@ -87,7 +80,7 @@ func (c *InitCommand) Flags() *base.FlagSets {
|
||||
|
||||
f := set.NewFlagSet("Command Options")
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
f.StringSliceVar(&base.StringSliceVar{
|
||||
Name: "config",
|
||||
Target: &c.flagConfig,
|
||||
Completion: complete.PredictOr(
|
||||
@@ -475,49 +468,7 @@ func (c *InitCommand) ParseFlagsAndConfig(args []string) int {
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
wrapperPath := c.flagConfig
|
||||
if c.flagConfigKms != "" {
|
||||
wrapperPath = c.flagConfigKms
|
||||
}
|
||||
wrapper, cleanupFunc, err := wrapper.GetWrapperFromPath(
|
||||
c.Context,
|
||||
wrapperPath,
|
||||
globals.KmsPurposeConfig,
|
||||
configutil.WithPluginOptions(
|
||||
pluginutil.WithPluginsMap(kms_plugin_assets.BuiltinKmsPlugins()),
|
||||
pluginutil.WithPluginsFilesystem(kms_plugin_assets.KmsPluginPrefix, kms_plugin_assets.FileSystem()),
|
||||
),
|
||||
// TODO: How would we want to expose this kind of log to users when
|
||||
// using recovery configs? Generally with normal CLI commands we
|
||||
// don't print out all of these logs. We may want a logger with a
|
||||
// custom writer behind our existing gate where we print nothing
|
||||
// unless there is an error, then dump all of it.
|
||||
configutil.WithLogger(hclog.NewNullLogger()),
|
||||
)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return base.CommandUserError
|
||||
}
|
||||
if wrapper != nil {
|
||||
c.configWrapperCleanupFunc = cleanupFunc
|
||||
if ifWrapper, ok := wrapper.(wrapping.InitFinalizer); ok {
|
||||
if err := ifWrapper.Init(c.Context); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
|
||||
c.UI.Error(fmt.Errorf("Could not initialize kms: %w", err).Error())
|
||||
return base.CommandUserError
|
||||
}
|
||||
c.configWrapperCleanupFunc = func() error {
|
||||
if err := ifWrapper.Finalize(context.Background()); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
|
||||
c.UI.Warn(fmt.Errorf("Could not finalize kms: %w", err).Error())
|
||||
}
|
||||
if cleanupFunc != nil {
|
||||
return cleanupFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Config, err = config.LoadFile(c.flagConfig, wrapper)
|
||||
c.Config, err = config.Load(c.Context, c.flagConfig, c.flagConfigKms)
|
||||
if err != nil {
|
||||
c.UI.Error("Error parsing config: " + err.Error())
|
||||
return base.CommandUserError
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/config"
|
||||
"github.com/hashicorp/boundary/internal/db/schema"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
host_plugin_assets "github.com/hashicorp/boundary/plugins/host"
|
||||
kms_plugin_assets "github.com/hashicorp/boundary/plugins/kms"
|
||||
external_host_plugins "github.com/hashicorp/boundary/sdk/plugins/host"
|
||||
"github.com/hashicorp/boundary/sdk/wrapper"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/configutil/v2"
|
||||
"github.com/hashicorp/go-secure-stdlib/mlock"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/go-secure-stdlib/pluginutil/v2"
|
||||
@@ -49,7 +42,7 @@ type MigrateCommand struct {
|
||||
|
||||
selectedRepairs schema.RepairMigrations
|
||||
|
||||
flagConfig string
|
||||
flagConfig []string
|
||||
flagConfigKms string
|
||||
flagLogLevel string
|
||||
flagLogFormat string
|
||||
@@ -79,7 +72,7 @@ func (c *MigrateCommand) Flags() *base.FlagSets {
|
||||
|
||||
f := set.NewFlagSet("Command options")
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
f.StringSliceVar(&base.StringSliceVar{
|
||||
Name: "config",
|
||||
Target: &c.flagConfig,
|
||||
Completion: complete.PredictOr(
|
||||
@@ -320,49 +313,7 @@ func (c *MigrateCommand) ParseFlagsAndConfig(args []string) int {
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
wrapperPath := c.flagConfig
|
||||
if c.flagConfigKms != "" {
|
||||
wrapperPath = c.flagConfigKms
|
||||
}
|
||||
wrapper, cleanupFunc, err := wrapper.GetWrapperFromPath(
|
||||
c.Context,
|
||||
wrapperPath,
|
||||
globals.KmsPurposeConfig,
|
||||
configutil.WithPluginOptions(
|
||||
pluginutil.WithPluginsMap(kms_plugin_assets.BuiltinKmsPlugins()),
|
||||
pluginutil.WithPluginsFilesystem(kms_plugin_assets.KmsPluginPrefix, kms_plugin_assets.FileSystem()),
|
||||
),
|
||||
// TODO: How would we want to expose this kind of log to users when
|
||||
// using recovery configs? Generally with normal CLI commands we
|
||||
// don't print out all of these logs. We may want a logger with a
|
||||
// custom writer behind our existing gate where we print nothing
|
||||
// unless there is an error, then dump all of it.
|
||||
configutil.WithLogger(hclog.NewNullLogger()),
|
||||
)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return base.CommandUserError
|
||||
}
|
||||
if wrapper != nil {
|
||||
c.configWrapperCleanupFunc = cleanupFunc
|
||||
if ifWrapper, ok := wrapper.(wrapping.InitFinalizer); ok {
|
||||
if err := ifWrapper.Init(c.Context); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
|
||||
c.UI.Error(fmt.Errorf("Could not initialize kms: %w", err).Error())
|
||||
return base.CommandUserError
|
||||
}
|
||||
c.configWrapperCleanupFunc = func() error {
|
||||
if err := ifWrapper.Finalize(context.Background()); err != nil && !errors.Is(err, wrapping.ErrFunctionNotImplemented) {
|
||||
c.UI.Warn(fmt.Errorf("Could not finalize kms: %w", err).Error())
|
||||
}
|
||||
if cleanupFunc != nil {
|
||||
return cleanupFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Config, err = config.LoadFile(c.flagConfig, wrapper)
|
||||
c.Config, err = config.Load(c.Context, c.flagConfig, c.flagConfigKms)
|
||||
if err != nil {
|
||||
c.UI.Error("Error parsing config: " + err.Error())
|
||||
return base.CommandUserError
|
||||
|
||||
Reference in new issue
Block a user