mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
cli: add -dev-consul and -dev-vault agent mode (#19327)
The `-dev-consul` and `-dev-vault` flags add default identities and configuration to the Nomad agent to connect and use the workload identity integration with Consul and Vault.
This commit is contained in:
@@ -61,7 +61,6 @@ type Command struct {
|
||||
}
|
||||
|
||||
func (c *Command) readConfig() *Config {
|
||||
var dev *devModeConfig
|
||||
var configPath []string
|
||||
var servers string
|
||||
var meta []string
|
||||
@@ -86,8 +85,12 @@ func (c *Command) readConfig() *Config {
|
||||
// Role options
|
||||
var devMode bool
|
||||
var devConnectMode bool
|
||||
var devConsulMode bool
|
||||
var devVaultMode bool
|
||||
flags.BoolVar(&devMode, "dev", false, "")
|
||||
flags.BoolVar(&devConnectMode, "dev-connect", false, "")
|
||||
flags.BoolVar(&devConsulMode, "dev-consul", false, "")
|
||||
flags.BoolVar(&devVaultMode, "dev-vault", false, "")
|
||||
flags.BoolVar(&cmdConfig.Server.Enabled, "server", false, "")
|
||||
flags.BoolVar(&cmdConfig.Client.Enabled, "client", false, "")
|
||||
|
||||
@@ -221,14 +224,26 @@ func (c *Command) readConfig() *Config {
|
||||
}
|
||||
|
||||
// Load the configuration
|
||||
dev, err := newDevModeConfig(devMode, devConnectMode)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return nil
|
||||
}
|
||||
var config *Config
|
||||
if dev != nil {
|
||||
config = DevConfig(dev)
|
||||
|
||||
devConfig := &devModeConfig{
|
||||
defaultMode: devMode,
|
||||
connectMode: devConnectMode,
|
||||
consulMode: devConsulMode,
|
||||
vaultMode: devVaultMode,
|
||||
}
|
||||
if devConfig.enabled() {
|
||||
err := devConfig.validate()
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return nil
|
||||
}
|
||||
err = devConfig.networkConfig()
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return nil
|
||||
}
|
||||
config = DevConfig(devConfig)
|
||||
} else {
|
||||
config = DefaultConfig()
|
||||
}
|
||||
@@ -1402,9 +1417,19 @@ General Options (clients and servers):
|
||||
|
||||
-dev-connect
|
||||
Start the agent in development mode, but bind to a public network
|
||||
interface rather than localhost for using Consul Connect. This
|
||||
interface rather than localhost for using Consul Connect. It may be used
|
||||
with -dev-consul to configure default workload identities for Consul. This
|
||||
mode is supported only on Linux as root.
|
||||
|
||||
-dev-consul
|
||||
Starts the agent in development mode with a default Consul configuration
|
||||
for Nomad workload identity. It may be used with -dev-connect to configure
|
||||
the agent for Consul Service Mesh.
|
||||
|
||||
-dev-vault
|
||||
Starts the agent in development mode with a default Vault configuration
|
||||
for Nomad workload identity.
|
||||
|
||||
Server Options:
|
||||
|
||||
-server
|
||||
|
||||
@@ -1177,47 +1177,43 @@ type devModeConfig struct {
|
||||
// mode flags are set at the command line via -dev and -dev-connect
|
||||
defaultMode bool
|
||||
connectMode bool
|
||||
consulMode bool
|
||||
vaultMode bool
|
||||
|
||||
bindAddr string
|
||||
iface string
|
||||
}
|
||||
|
||||
// newDevModeConfig parses the optional string value of the -dev flag
|
||||
func newDevModeConfig(devMode, connectMode bool) (*devModeConfig, error) {
|
||||
if !devMode && !connectMode {
|
||||
return nil, nil
|
||||
}
|
||||
mode := &devModeConfig{}
|
||||
mode.defaultMode = devMode
|
||||
if connectMode {
|
||||
func (mode *devModeConfig) enabled() bool {
|
||||
return mode.defaultMode || mode.connectMode ||
|
||||
mode.consulMode || mode.vaultMode
|
||||
}
|
||||
|
||||
func (mode *devModeConfig) validate() error {
|
||||
if mode.connectMode {
|
||||
if runtime.GOOS != "linux" {
|
||||
// strictly speaking -dev-connect only binds to the
|
||||
// non-localhost interface, but given its purpose
|
||||
// is to support a feature with network namespaces
|
||||
// we'll return an error here rather than let the agent
|
||||
// come up and fail unexpectedly to run jobs
|
||||
return nil, fmt.Errorf("-dev-connect is only supported on linux.")
|
||||
return fmt.Errorf("-dev-connect is only supported on linux.")
|
||||
}
|
||||
u, err := users.Current()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"-dev-connect uses network namespaces and is only supported for root: %v", err)
|
||||
}
|
||||
if u.Uid != "0" {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"-dev-connect uses network namespaces and is only supported for root.")
|
||||
}
|
||||
// Ensure Consul is on PATH
|
||||
if _, err := exec.LookPath("consul"); err != nil {
|
||||
return nil, fmt.Errorf("-dev-connect requires a 'consul' binary in Nomad's $PATH")
|
||||
return fmt.Errorf("-dev-connect requires a 'consul' binary in Nomad's $PATH")
|
||||
}
|
||||
mode.connectMode = true
|
||||
}
|
||||
err := mode.networkConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mode, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mode *devModeConfig) networkConfig() error {
|
||||
@@ -1289,6 +1285,26 @@ func DevConfig(mode *devModeConfig) *Config {
|
||||
conf.Telemetry.PrometheusMetrics = true
|
||||
conf.Telemetry.PublishAllocationMetrics = true
|
||||
conf.Telemetry.PublishNodeMetrics = true
|
||||
|
||||
if mode.consulMode {
|
||||
conf.Consuls[0].ServiceIdentity = &config.WorkloadIdentityConfig{
|
||||
Audience: []string{"consul.io"},
|
||||
TTL: pointer.Of(time.Hour),
|
||||
}
|
||||
conf.Consuls[0].TaskIdentity = &config.WorkloadIdentityConfig{
|
||||
Audience: []string{"consul.io"},
|
||||
TTL: pointer.Of(time.Hour),
|
||||
}
|
||||
}
|
||||
|
||||
if mode.vaultMode {
|
||||
conf.Vaults[0].Enabled = pointer.Of(true)
|
||||
conf.Vaults[0].Addr = "http://localhost:8200"
|
||||
conf.Vaults[0].DefaultIdentity = &config.WorkloadIdentityConfig{
|
||||
Audience: []string{"vault.io"},
|
||||
TTL: pointer.Of(time.Hour),
|
||||
}
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -725,59 +724,61 @@ func TestConfig_Listener(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig_DevModeFlag(t *testing.T) {
|
||||
func TestConfig_DevMode_validate(t *testing.T) {
|
||||
ci.Parallel(t)
|
||||
|
||||
cases := []struct {
|
||||
dev bool
|
||||
connect bool
|
||||
expected *devModeConfig
|
||||
devConfig *devModeConfig
|
||||
expectedErr string
|
||||
}{}
|
||||
if runtime.GOOS != "linux" {
|
||||
cases = []struct {
|
||||
dev bool
|
||||
connect bool
|
||||
expected *devModeConfig
|
||||
devConfig *devModeConfig
|
||||
expectedErr string
|
||||
}{
|
||||
{false, false, nil, ""},
|
||||
{true, false, &devModeConfig{defaultMode: true, connectMode: false}, ""},
|
||||
{true, true, nil, "-dev-connect is only supported on linux"},
|
||||
{false, true, nil, "-dev-connect is only supported on linux"},
|
||||
{
|
||||
devConfig: &devModeConfig{
|
||||
connectMode: true,
|
||||
},
|
||||
expectedErr: "-dev-connect is only supported on linux",
|
||||
},
|
||||
{
|
||||
devConfig: &devModeConfig{
|
||||
defaultMode: true,
|
||||
connectMode: true,
|
||||
},
|
||||
expectedErr: "-dev-connect is only supported on linux",
|
||||
},
|
||||
}
|
||||
}
|
||||
if runtime.GOOS == "linux" {
|
||||
testutil.RequireRoot(t)
|
||||
cases = []struct {
|
||||
dev bool
|
||||
connect bool
|
||||
expected *devModeConfig
|
||||
devConfig *devModeConfig
|
||||
expectedErr string
|
||||
}{
|
||||
{false, false, nil, ""},
|
||||
{true, false, &devModeConfig{defaultMode: true, connectMode: false}, ""},
|
||||
{true, true, &devModeConfig{defaultMode: true, connectMode: true}, ""},
|
||||
{false, true, &devModeConfig{defaultMode: false, connectMode: true}, ""},
|
||||
{
|
||||
devConfig: &devModeConfig{
|
||||
connectMode: true,
|
||||
},
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
devConfig: &devModeConfig{
|
||||
defaultMode: true,
|
||||
connectMode: true,
|
||||
},
|
||||
expectedErr: "",
|
||||
},
|
||||
}
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run("", func(t *testing.T) {
|
||||
mode, err := newDevModeConfig(c.dev, c.connect)
|
||||
if err != nil && c.expectedErr == "" {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err != nil && !strings.Contains(err.Error(), c.expectedErr) {
|
||||
t.Fatalf("expected %s; got %v", c.expectedErr, err)
|
||||
}
|
||||
if mode == nil && c.expected != nil {
|
||||
t.Fatalf("expected %+v but got nil", c.expected)
|
||||
}
|
||||
if mode != nil {
|
||||
if c.expected.defaultMode != mode.defaultMode ||
|
||||
c.expected.connectMode != mode.connectMode {
|
||||
t.Fatalf("expected %+v, got %+v", c.expected, mode)
|
||||
}
|
||||
err := c.devConfig.validate()
|
||||
if c.expectedErr != "" {
|
||||
must.Error(t, err)
|
||||
} else {
|
||||
must.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -98,8 +98,16 @@ via CLI arguments. The `agent` command accepts the following arguments:
|
||||
but you may pass an optional comma-separated list of mode configurations:
|
||||
|
||||
- `-dev-connect`: Start the agent in development mode, but bind to a public
|
||||
network interface rather than localhost for using Consul Connect. This mode
|
||||
is supported only on Linux as root.
|
||||
network interface rather than localhost for using Consul Connect. It may be
|
||||
used with `-dev-consul` to configure default workload identities for Consul.
|
||||
This mode is supported only on Linux as root.
|
||||
|
||||
- `-dev-consul`: Starts the agent in development mode with a default Consul
|
||||
configuration for Nomad workload identity. It may be used with `-dev-connect`
|
||||
to configure the agent for Consul Service Mesh.
|
||||
|
||||
- `-dev-vault`: Starts the agent in development mode with a default Vault
|
||||
configuration for Nomad workload identity.
|
||||
|
||||
- `-encrypt`: Set the Serf encryption key. See the [Encryption Overview] for
|
||||
more details.
|
||||
|
||||
Reference in New Issue
Block a user