-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #154 from launchdarkly/eb/ch83954/enterprise-1
(RPE - #1) add Relay Proxy Enterprise basic infrastructure and config
- Loading branch information
Showing
20 changed files
with
662 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package entconfig | ||
|
||
import ( | ||
ct "github.com/launchdarkly/go-configtypes" | ||
"github.com/launchdarkly/ld-relay/v6/core/config" | ||
) | ||
|
||
// This file contains extended configuration for Relay Proxy Enterprise. It will be moved to a | ||
// separate project later in development. | ||
|
||
const ( | ||
// AutoConfigEnvironmentIDPlaceholder is a string that can appear within | ||
// AutoConfigConfig.EnvDataStorePrefix or AutoConfigConfig.EnvDataStoreTableName to indicate that | ||
// the environment ID should be substituted at that point. | ||
// | ||
// For instance, if EnvDataStorePrefix is "LD-$CID", the value of that setting for an environment | ||
// whose ID is "12345" would be "LD-12345". | ||
AutoConfigEnvironmentIDPlaceholder = "$CID" | ||
) | ||
|
||
// EnterpriseConfig describes the configuration for a RelayEnterprise instance. | ||
// | ||
// This is mostly the same as regular Relay, with some added options. | ||
type EnterpriseConfig struct { | ||
config.Config | ||
AutoConfig AutoConfigConfig | ||
} | ||
|
||
// AutoConfigConfig contains configuration parameters for the auto-configuration feature. | ||
type AutoConfigConfig struct { | ||
Key AutoConfigKey `conf:"AUTO_CONFIG_KEY"` | ||
EnvDatastorePrefix string `conf:"ENV_DATASTORE_PREFIX"` | ||
EnvDatastoreTableName string `conf:"ENV_DATASTORE_TABLE_NAME"` | ||
EnvAllowedOrigin ct.OptStringList `conf:"ENV_ALLOWED_ORIGIN"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package entconfig | ||
|
||
// AutoConfigKey is a type tag to indicate when a string is used as an auto-config key. | ||
type AutoConfigKey string | ||
|
||
// GetAuthorizationHeaderValue for AutoConfigKey returns the same string, since these keys are passed in | ||
// the Authorization header. Note that unlike the other kinds of authorization keys, this one is never | ||
// present in an incoming request; it is only used in requests from Relay to LaunchDarkly. | ||
func (k AutoConfigKey) GetAuthorizationHeaderValue() string { | ||
return string(k) | ||
} | ||
|
||
// UnmarshalText allows the AutoConfigKey type to be set from environment variables. | ||
func (k *AutoConfigKey) UnmarshalText(data []byte) error { | ||
*k = AutoConfigKey(string(data)) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package entconfig | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestAutoConfigKey(t *testing.T) { | ||
assert.Equal(t, "123", AutoConfigKey("123").GetAuthorizationHeaderValue()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package entconfig | ||
|
||
import ( | ||
ct "github.com/launchdarkly/go-configtypes" | ||
"github.com/launchdarkly/ld-relay/v6/core/config" | ||
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog" | ||
) | ||
|
||
// LoadConfigFromEnvironment sets parameters in an EnterpriseConfig struct from environment variables. | ||
// | ||
// The Config parameter should be initialized with default values first. | ||
func LoadConfigFromEnvironment(c *EnterpriseConfig, loggers ldlog.Loggers) error { | ||
reader := ct.NewVarReaderFromEnvironment() | ||
|
||
baseResult := config.LoadConfigFromEnvironmentBase(&c.Config, loggers) | ||
for _, e := range baseResult.Errors() { | ||
reader.AddError(e.Path, e.Err) | ||
} | ||
|
||
reader.ReadStruct(&c.AutoConfig, false) | ||
|
||
if !reader.Result().OK() { | ||
return reader.Result().GetError() | ||
} | ||
|
||
return ValidateConfig(c, loggers) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package entconfig | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog" | ||
) | ||
|
||
func TestConfigFromEnvironmentWithValidProperties(t *testing.T) { | ||
for _, tdc := range makeValidConfigs() { | ||
t.Run(tdc.name, func(t *testing.T) { | ||
testValidConfigVars(t, tdc.makeConfig, tdc.envVars) | ||
}) | ||
} | ||
} | ||
|
||
func TestConfigFromEnvironmentWithInvalidProperties(t *testing.T) { | ||
for _, tdc := range makeInvalidConfigs() { | ||
if len(tdc.envVars) != 0 { | ||
t.Run(tdc.name, func(t *testing.T) { | ||
testInvalidConfigVars(t, tdc.envVars, tdc.envVarsError) | ||
}) | ||
} | ||
} | ||
} | ||
|
||
func testValidConfigVars(t *testing.T, buildConfig func(c *EnterpriseConfig), vars map[string]string) { | ||
withEnvironment(vars, func() { | ||
var expectedConfig EnterpriseConfig | ||
buildConfig(&expectedConfig) | ||
|
||
var c EnterpriseConfig | ||
err := LoadConfigFromEnvironment(&c, ldlog.NewDisabledLoggers()) | ||
require.NoError(t, err) | ||
|
||
assert.Equal(t, expectedConfig, c) | ||
}) | ||
} | ||
|
||
func testInvalidConfigVars(t *testing.T, vars map[string]string, errMessage string) { | ||
withEnvironment(vars, func() { | ||
var c EnterpriseConfig | ||
err := LoadConfigFromEnvironment(&c, ldlog.NewDisabledLoggers()) | ||
require.Error(t, err) | ||
assert.Contains(t, err.Error(), errMessage) | ||
}) | ||
} | ||
|
||
func withEnvironment(vars map[string]string, action func()) { | ||
saved := make(map[string]string) | ||
for _, kv := range os.Environ() { | ||
p := strings.Index(kv, "=") | ||
saved[kv[:p]] = kv[p+1:] | ||
} | ||
defer func() { | ||
os.Clearenv() | ||
for k, v := range saved { | ||
os.Setenv(k, v) | ||
} | ||
}() | ||
os.Clearenv() | ||
for k, v := range vars { | ||
os.Setenv(k, v) | ||
} | ||
action() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package entconfig | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/launchdarkly/gcfg" | ||
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog" | ||
) | ||
|
||
// LoadConfigFile reads a configuration file into an EnterpriseConfig struct and performs basic validation. | ||
// | ||
// The Config parameter could be initialized with default values first, but does not need to be. | ||
func LoadConfigFile(c *EnterpriseConfig, path string, loggers ldlog.Loggers) error { | ||
if err := gcfg.ReadFileInto(c, path); err != nil { | ||
return fmt.Errorf(`failed to read configuration file "%s": %w`, path, err) | ||
} | ||
|
||
return ValidateConfig(c, loggers) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package entconfig | ||
|
||
import ( | ||
"io/ioutil" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog" | ||
|
||
helpers "github.com/launchdarkly/go-test-helpers/v2" | ||
) | ||
|
||
func TestConfigFromFileWithValidProperties(t *testing.T) { | ||
for _, tdc := range makeValidConfigs() { | ||
if tdc.fileContent == "" { | ||
// some tests only apply to environment variables, not files | ||
continue | ||
} | ||
t.Run(tdc.name, func(t *testing.T) { | ||
testFileWithValidConfig(t, tdc.makeConfig, tdc.fileContent) | ||
}) | ||
} | ||
} | ||
|
||
func TestConfigFromFileWithInvalidProperties(t *testing.T) { | ||
for _, tdc := range makeInvalidConfigs() { | ||
if tdc.fileContent == "" { | ||
// some tests only apply to environment variables, not files | ||
continue | ||
} | ||
t.Run(tdc.name, func(t *testing.T) { | ||
e := tdc.fileError | ||
if e == "" { | ||
e = tdc.envVarsError | ||
} | ||
testFileWithInvalidConfig(t, tdc.fileContent, e) | ||
}) | ||
} | ||
} | ||
|
||
func testFileWithValidConfig(t *testing.T, buildConfig func(c *EnterpriseConfig), fileContent string) { | ||
var expectedConfig EnterpriseConfig | ||
buildConfig(&expectedConfig) | ||
|
||
helpers.WithTempFile(func(filename string) { | ||
require.NoError(t, ioutil.WriteFile(filename, []byte(fileContent), 0)) | ||
|
||
var c EnterpriseConfig | ||
err := LoadConfigFile(&c, filename, ldlog.NewDisabledLoggers()) | ||
require.NoError(t, err) | ||
assert.Equal(t, expectedConfig, c) | ||
}) | ||
} | ||
|
||
func testFileWithInvalidConfig(t *testing.T, fileContent string, errMessage string) { | ||
helpers.WithTempFile(func(filename string) { | ||
require.NoError(t, ioutil.WriteFile(filename, []byte(fileContent), 0)) | ||
|
||
var c EnterpriseConfig | ||
err := LoadConfigFile(&c, filename, ldlog.NewDisabledLoggers()) | ||
require.Error(t, err) | ||
assert.Contains(t, err.Error(), errMessage) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package entconfig |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package entconfig | ||
|
||
import ( | ||
"errors" | ||
|
||
ct "github.com/launchdarkly/go-configtypes" | ||
"github.com/launchdarkly/ld-relay/v6/core/config" | ||
"gopkg.in/launchdarkly/go-sdk-common.v2/ldlog" | ||
) | ||
|
||
var ( | ||
errAutoConfPropertiesWithNoKey = errors.New("must specify auto-configuration key if other auto-configuration properties are set") | ||
errAutoConfWithEnvironments = errors.New("cannot configure specific environments if auto-configuration is enabled") | ||
) | ||
|
||
// ValidateConfig ensures that the configuration does not contain contradictory properties. | ||
// | ||
// This method covers validation rules that can't be enforced on a per-field basis (for instance, if | ||
// either field A or field B can be specified but it's invalid to specify both). It is allowed to modify | ||
// the Config struct in order to canonicalize settings in a way that simplifies things for the Relay code | ||
// (for instance, converting Redis host/port settings into a Redis URL, or converting deprecated fields to | ||
// non-deprecated ones). | ||
// | ||
// LoadConfigFromEnvironment and LoadConfigFromFile both call this method as a last step. | ||
func ValidateConfig(c *EnterpriseConfig, loggers ldlog.Loggers) error { | ||
var result ct.ValidationResult | ||
|
||
baseError := config.ValidateConfig(&c.Config, loggers) | ||
if baseError != nil { | ||
if ae, ok := baseError.(ct.ValidationAggregateError); ok { | ||
for _, e := range ae { | ||
result.AddError(e.Path, e.Err) | ||
} | ||
} else if e, ok := baseError.(ct.ValidationError); ok { | ||
result.AddError(e.Path, e.Err) | ||
} else { | ||
result.AddError(nil, baseError) | ||
} | ||
} | ||
|
||
if c.AutoConfig.Key == "" { | ||
if c.AutoConfig.EnvDatastorePrefix != "" || c.AutoConfig.EnvDatastoreTableName != "" || | ||
len(c.AutoConfig.EnvAllowedOrigin.Values()) != 0 { | ||
result.AddError(nil, errAutoConfPropertiesWithNoKey) | ||
} | ||
} else if len(c.Environment) != 0 { | ||
result.AddError(nil, errAutoConfWithEnvironments) | ||
} | ||
|
||
return result.GetError() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package entconfig contains the additional configuration schema for Relay Proxy Enterprise. | ||
package entconfig |
Oops, something went wrong.