Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare for adding license auto-retrieval to auto-config in enterprise #10248

Merged
merged 1 commit into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelog/10248.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:breaking-change
licensing: **(Enterprise Only)** Consul Enterprise has removed support for temporary licensing. All server agents must have a valid license at startup and client agents must have a license at startup or be able to retrieve one from the servers.
```

```release-note:breaking-change
licensing: **(Enterprise Only)** Consul Enterprise client agents now require a valid non-anonymous ACL token for retrieving their license from the servers. Additionally client agents rely on the value of the `start_join` and `retry_join` configurations for determining the servers to query for the license. Therefore one must be set to use license auto-retrieval.
```
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
30 changes: 23 additions & 7 deletions agent/auto-config/auto_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ func New(config Config) (*AutoConfig, error) {
}
}

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

return &AutoConfig{
acConfig: config,
logger: logger,
Expand Down Expand Up @@ -126,13 +130,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 +179,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
3 changes: 0 additions & 3 deletions agent/consul/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,6 @@ type Config struct {
// a Consul server is now up and known about.
ServerUp func()

// Shutdown callback is used to trigger a full Consul shutdown
Shutdown func()

// UserEventHandler callback can be used to handle incoming
// user events. This function should not block.
UserEventHandler func(serf.UserEvent)
Expand Down
25 changes: 17 additions & 8 deletions agent/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,21 +110,30 @@ 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
}

return initEnterpriseBaseDeps(d, cfg)
return d, nil
}

// grpcLogInitOnce because the test suite will call NewBaseDeps in many tests and
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{}
}
8 changes: 7 additions & 1 deletion sdk/testutil/testlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,26 @@ func LoggerWithOutput(t TestingTB, output io.Writer) hclog.InterceptLogger {
}

var sendTestLogsToStdout = os.Getenv("NOLOGBUFFER") == "1"
var testLogOnlyFailed = os.Getenv("TEST_LOGGING_ONLY_FAILED") == "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
// mode all log output is printed to stdout.
//
// Set the env var NOLOGBUFFER=1 to disable buffering, resulting in all log
// output being written immediately to stdout.
//
// Typically log output is written either for failed tests or when go test
// is running with the verbose flag (-v) set. Setting TEST_LOGGING_ONLY_FAILED=1
// will prevent logs being output when the verbose flag is set if the test
// case is successful.
func NewLogBuffer(t TestingTB) io.Writer {
if sendTestLogsToStdout {
return os.Stdout
}
buf := &logBuffer{buf: new(bytes.Buffer)}
t.Cleanup(func() {
if t.Failed() || testing.Verbose() {
if t.Failed() || (!testLogOnlyFailed && testing.Verbose()) {
buf.Lock()
defer buf.Unlock()
buf.buf.WriteTo(os.Stdout)
Expand Down
Loading