Skip to content

Commit

Permalink
hcs-1936: Prepare for adding license auto-retrieval to auto-config in…
Browse files Browse the repository at this point in the history
… enterprise
  • Loading branch information
mkeeler committed May 17, 2021
1 parent bd9824c commit a041eb2
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 51 deletions.
4 changes: 1 addition & 3 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,7 @@ func (a *Agent) Start(ctx context.Context) error {
return fmt.Errorf("Failed to load TLS configurations after applying auto-config settings: %w", err)
}

// we cannot use the context passed into this method as that context will be cancelled after the
// agent finishes starting up which would cause the license manager to stop
if err := a.startLicenseManager(&lib.StopChannelContext{StopCh: a.shutdownCh}); err != nil {
if err := a.startLicenseManager(ctx); err != nil {
return err
}

Expand Down
39 changes: 30 additions & 9 deletions agent/auto-config/auto_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ type AutoConfig struct {
// events from the token store when the Agent
// token is updated.
tokenUpdates token.Notifier

// AutoConfigEnterprise holds the enterprise specific
// AutoConfig bits
AutoConfigEnterprise
}

// New creates a new AutoConfig object for providing automatic Consul configuration.
Expand Down Expand Up @@ -92,9 +96,14 @@ func New(config Config) (*AutoConfig, error) {
}
}

if err := config.EnterpriseConfig.validateAndFinalize(); err != nil {
return nil, err
}

return &AutoConfig{
acConfig: config,
logger: logger,
acConfig: config,
logger: logger,
AutoConfigEnterprise: newAutoConfigEnterprise(config),
}, nil
}

Expand Down Expand Up @@ -126,13 +135,8 @@ func (ac *AutoConfig) ReadConfig() (*config.RuntimeConfig, error) {
// The context passed in can be used to cancel the retrieval of the initial configuration
// like when receiving a signal during startup.
func (ac *AutoConfig) InitialConfiguration(ctx context.Context) (*config.RuntimeConfig, error) {
if ac.config == nil {
config, err := ac.ReadConfig()
if err != nil {
return nil, err
}

ac.config = config
if err := ac.maybeLoadConfig(); err != nil {
return nil, err
}

switch {
Expand Down Expand Up @@ -180,6 +184,23 @@ func (ac *AutoConfig) InitialConfiguration(ctx context.Context) (*config.Runtime
}
}

// maybeLoadConfig will read the Consul configuration using the
// provided config loader if and only if the config field of
// the struct is nil. When it does this it will fill in that
// field. If the config field already is non-nil then this
// is a noop.
func (ac *AutoConfig) maybeLoadConfig() error {
if ac.config == nil {
config, err := ac.ReadConfig()
if err != nil {
return err
}

ac.config = config
}
return nil
}

// introToken is responsible for determining the correct intro token to use
// when making the initial AutoConfig.InitialConfiguration RPC request.
func (ac *AutoConfig) introToken() (string, error) {
Expand Down
11 changes: 11 additions & 0 deletions agent/auto-config/auto_config_oss.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// +build !consulent

package autoconf

// AutoConfigEnterprise has no fields in OSS
type AutoConfigEnterprise struct{}

// newAutoConfigEnterprise initializes the enterprise AutoConfig struct
func newAutoConfigEnterprise(config Config) AutoConfigEnterprise {
return AutoConfigEnterprise{}
}
11 changes: 11 additions & 0 deletions agent/auto-config/auto_config_oss_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// +build !consulent

package autoconf

import (
"testing"
)

func newEnterpriseConfig(t *testing.T) EnterpriseConfig {
return EnterpriseConfig{}
}
22 changes: 10 additions & 12 deletions agent/auto-config/auto_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,12 @@ func TestNew(t *testing.T) {
Loader: func(source config.Source) (result config.LoadResult, err error) {
return config.LoadResult{}, nil
},
DirectRPC: newMockDirectRPC(t),
Tokens: newMockTokenStore(t),
Cache: newMockCache(t),
TLSConfigurator: newMockTLSConfigurator(t),
ServerProvider: newMockServerProvider(t),
DirectRPC: newMockDirectRPC(t),
Tokens: newMockTokenStore(t),
Cache: newMockCache(t),
TLSConfigurator: newMockTLSConfigurator(t),
ServerProvider: newMockServerProvider(t),
EnterpriseConfig: newEnterpriseConfig(t),
}

if tcase.modify != nil {
Expand Down Expand Up @@ -211,26 +212,23 @@ func setupRuntimeConfig(t *testing.T) *configLoader {
}

func TestInitialConfiguration_disabled(t *testing.T) {
loader := setupRuntimeConfig(t)
loader.addConfigHCL(`
mcfg := newMockedConfig(t)
mcfg.loader.addConfigHCL(`
primary_datacenter = "primary"
auto_config = {
enabled = false
}
`)

conf := newMockedConfig(t).Config
conf.Loader = loader.Load

ac, err := New(conf)
ac, err := New(mcfg.Config)
require.NoError(t, err)
require.NotNil(t, ac)

cfg, err := ac.InitialConfiguration(context.Background())
require.NoError(t, err)
require.NotNil(t, cfg)
require.Equal(t, "primary", cfg.PrimaryDatacenter)
require.NoFileExists(t, filepath.Join(*loader.opts.FlagValues.DataDir, autoConfigFileName))
require.NoFileExists(t, filepath.Join(*mcfg.loader.opts.FlagValues.DataDir, autoConfigFileName))
}

func TestInitialConfiguration_cancelled(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions agent/auto-config/auto_encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (ac *AutoConfig) autoEncryptInitialCertsOnce(ctx context.Context, csr, key
}
var resp structs.SignedResponse

servers, err := ac.autoEncryptHosts()
servers, err := ac.joinHosts()
if err != nil {
return nil, err
}
Expand All @@ -69,7 +69,7 @@ func (ac *AutoConfig) autoEncryptInitialCertsOnce(ctx context.Context, csr, key
return nil, fmt.Errorf("No servers successfully responded to the auto-encrypt request")
}

func (ac *AutoConfig) autoEncryptHosts() ([]string, error) {
func (ac *AutoConfig) joinHosts() ([]string, error) {
// use servers known to gossip if there are any
if ac.acConfig.ServerProvider != nil {
if srv := ac.acConfig.ServerProvider.FindLANServer(); srv != nil {
Expand Down
2 changes: 1 addition & 1 deletion agent/auto-config/auto_encrypt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func TestAutoEncrypt_hosts(t *testing.T) {
},
}

hosts, err := ac.autoEncryptHosts()
hosts, err := ac.joinHosts()
if tcase.err != "" {
testutil.RequireErrorContains(t, err, tcase.err)
} else {
Expand Down
3 changes: 3 additions & 0 deletions agent/auto-config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,7 @@ type Config struct {
// agent token as well as getting notifications when that token is updated.
// This field is required.
Tokens TokenStore

// EnterpriseConfig is the embedded specific enterprise configurations
EnterpriseConfig
}
11 changes: 11 additions & 0 deletions agent/auto-config/config_oss.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// +build !consulent

package autoconf

// EnterpriseConfig stub - only populated in Consul Enterprise
type EnterpriseConfig struct{}

// finalize is a noop for OSS
func (_ *EnterpriseConfig) validateAndFinalize() error {
return nil
}
18 changes: 18 additions & 0 deletions agent/auto-config/mock_oss_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// +build !consulent

package autoconf

import (
"testing"
)

// mockedEnterpriseConfig is pretty much just a stub in OSS
// It does contain an enterprise config for compatibility
// purposes but that in and of itself is just a stub.
type mockedEnterpriseConfig struct {
EnterpriseConfig
}

func newMockedEnterpriseConfig(t *testing.T) *mockedEnterpriseConfig {
return &mockedEnterpriseConfig{}
}
32 changes: 21 additions & 11 deletions agent/auto-config/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,20 +218,25 @@ func (m *mockTokenStore) StopNotify(notifier token.Notifier) {
type mockedConfig struct {
Config

directRPC *mockDirectRPC
serverProvider *mockServerProvider
cache *mockCache
tokens *mockTokenStore
tlsCfg *mockTLSConfigurator
loader *configLoader
directRPC *mockDirectRPC
serverProvider *mockServerProvider
cache *mockCache
tokens *mockTokenStore
tlsCfg *mockTLSConfigurator
enterpriseConfig *mockedEnterpriseConfig
}

func newMockedConfig(t *testing.T) *mockedConfig {
loader := setupRuntimeConfig(t)
directRPC := newMockDirectRPC(t)
serverProvider := newMockServerProvider(t)
mcache := newMockCache(t)
tokens := newMockTokenStore(t)
tlsCfg := newMockTLSConfigurator(t)

entConfig := newMockedEnterpriseConfig(t)

// I am not sure it is well defined behavior but in testing it
// out it does appear like Cleanup functions can fail tests
// Adding in the mock expectations assertions here saves us
Expand All @@ -248,18 +253,23 @@ func newMockedConfig(t *testing.T) *mockedConfig {

return &mockedConfig{
Config: Config{
DirectRPC: directRPC,
ServerProvider: serverProvider,
Cache: mcache,
Tokens: tokens,
TLSConfigurator: tlsCfg,
Logger: testutil.Logger(t),
Loader: loader.Load,
DirectRPC: directRPC,
ServerProvider: serverProvider,
Cache: mcache,
Tokens: tokens,
TLSConfigurator: tlsCfg,
Logger: testutil.Logger(t),
EnterpriseConfig: entConfig.EnterpriseConfig,
},
loader: loader,
directRPC: directRPC,
serverProvider: serverProvider,
cache: mcache,
tokens: tokens,
tlsCfg: tlsCfg,

enterpriseConfig: entConfig,
}
}

Expand Down
5 changes: 0 additions & 5 deletions agent/consul/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,6 @@ func NewClient(config *Config, deps Deps) (*Client, error) {
go c.monitorACLMode()
}

if err := c.startEnterprise(); err != nil {
c.Shutdown()
return nil, err
}

return c, nil
}

Expand Down
23 changes: 16 additions & 7 deletions agent/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,24 @@ func NewBaseDeps(configLoader ConfigLoader, logOut io.Writer) (BaseDeps, error)

d.Router = router.NewRouter(d.Logger, cfg.Datacenter, fmt.Sprintf("%s.%s", cfg.NodeName, cfg.Datacenter), builder)

// this needs to happen prior to creating auto-config as some of the dependencies
// must also be passed to auto-config
d, err = initEnterpriseBaseDeps(d, cfg)
if err != nil {
return d, err
}

acConf := autoconf.Config{
DirectRPC: d.ConnPool,
Logger: d.Logger,
Loader: configLoader,
ServerProvider: d.Router,
TLSConfigurator: d.TLSConfigurator,
Cache: d.Cache,
Tokens: d.Tokens,
DirectRPC: d.ConnPool,
Logger: d.Logger,
Loader: configLoader,
ServerProvider: d.Router,
TLSConfigurator: d.TLSConfigurator,
Cache: d.Cache,
Tokens: d.Tokens,
EnterpriseConfig: initEnterpriseAutoConfig(d.EnterpriseDeps),
}

d.AutoConfig, err = autoconf.New(acConf)
if err != nil {
return d, err
Expand Down
7 changes: 7 additions & 0 deletions agent/setup_oss.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
package agent

import (
autoconf "github.com/hashicorp/consul/agent/auto-config"
"github.com/hashicorp/consul/agent/config"
"github.com/hashicorp/consul/agent/consul"
)

// initEnterpriseBaseDeps is responsible for initializing the enterprise dependencies that
// will be utilized throughout the whole Consul Agent.
func initEnterpriseBaseDeps(d BaseDeps, _ *config.RuntimeConfig) (BaseDeps, error) {
return d, nil
}

// initEnterpriseAutoConfig is responsible for setting up auto-config for enterprise
func initEnterpriseAutoConfig(_ consul.EnterpriseDeps) autoconf.EnterpriseConfig {
return autoconf.EnterpriseConfig{}
}
3 changes: 2 additions & 1 deletion sdk/testutil/testlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func LoggerWithOutput(t TestingTB, output io.Writer) hclog.InterceptLogger {
}

var sendTestLogsToStdout = os.Getenv("NOLOGBUFFER") == "1"
var bufferVerbose = os.Getenv("BUFFERVERBOSE") == "1"

// NewLogBuffer returns an io.Writer which buffers all writes. When the test
// ends, t.Failed is checked. If the test has failed or has been run in verbose
Expand All @@ -36,7 +37,7 @@ func NewLogBuffer(t TestingTB) io.Writer {
}
buf := &logBuffer{buf: new(bytes.Buffer)}
t.Cleanup(func() {
if t.Failed() || testing.Verbose() {
if t.Failed() || (!bufferVerbose && testing.Verbose()) {
buf.Lock()
defer buf.Unlock()
buf.buf.WriteTo(os.Stdout)
Expand Down
10 changes: 10 additions & 0 deletions test/integration/connect/envoy/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ function start_consul {
'-p=9502:8502'
)
fi

license="${CONSUL_LICENSE:-}"
# load the consul license so we can pass it into the consul
# containers as an env var in the case that this is a consul
# enterprise test
if test -z "$license" -a -n "${CONSUL_LICENSE_PATH:-}"
then
license=$(cat $CONSUL_LICENSE_PATH)
fi

# Run consul and expose some ports to the host to make debugging locally a
# bit easier.
Expand All @@ -151,6 +160,7 @@ function start_consul {
$WORKDIR_SNIPPET \
--hostname "consul-${DC}" \
--network-alias "consul-${DC}" \
-e "CONSUL_LICENSE=$license" \
${ports[@]} \
consul-dev \
agent -dev -datacenter "${DC}" \
Expand Down

0 comments on commit a041eb2

Please sign in to comment.