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

Add optional programmatic configuration of the DNS provider #1232

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 1 addition & 1 deletion challenge/dns01/dns_challenge_manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const (
type DNSProviderManual struct{}

// NewDNSProviderManual returns a DNSProviderManual instance.
func NewDNSProviderManual() (*DNSProviderManual, error) {
func NewDNSProviderManual(conf map[string]string) (*DNSProviderManual, error) {
return &DNSProviderManual{}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion challenge/dns01/dns_challenge_manual_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func TestDNSProviderManual(t *testing.T) {

os.Stdin = file

manualProvider, err := NewDNSProviderManual()
manualProvider, err := NewDNSProviderManual(nil)
require.NoError(t, err)

err = manualProvider.Present("example.com", "", "")
Expand Down
2 changes: 1 addition & 1 deletion cmd/setup_challenges.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func setupTLSProvider(ctx *cli.Context) challenge.Provider {
}

func setupDNS(ctx *cli.Context, client *lego.Client) {
provider, err := dns.NewDNSChallengeProviderByName(ctx.GlobalString("dns"))
provider, err := dns.NewDNSChallengeProviderByName(ctx.GlobalString("dns"), nil)
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion e2e/dnschallenge/dns_challenges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestChallengeDNS_Client_Obtain(t *testing.T) {
client, err := lego.NewClient(config)
require.NoError(t, err)

provider, err := dns.NewDNSChallengeProviderByName("exec")
provider, err := dns.NewDNSChallengeProviderByName("exec", nil)
require.NoError(t, err)

err = client.Challenge.SetDNS01Provider(provider,
Expand Down
36 changes: 20 additions & 16 deletions platform/config/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import (
)

// Get environment variables.
func Get(names ...string) (map[string]string, error) {
func Get(config map[string]string, names ...string) (map[string]string, error) {
values := map[string]string{}

var missingEnvVars []string
for _, envVar := range names {
value := GetOrFile(envVar)
value := GetOrFile(config, envVar)
if value == "" {
missingEnvVars = append(missingEnvVars, envVar)
}
Expand Down Expand Up @@ -54,7 +54,7 @@ func Get(names ...string) (map[string]string, error) {
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
// // => error
//
func GetWithFallback(groups ...[]string) (map[string]string, error) {
func GetWithFallback(config map[string]string, groups ...[]string) (map[string]string, error) {
values := map[string]string{}

var missingEnvVars []string
Expand All @@ -63,7 +63,7 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
return nil, errors.New("undefined environment variable names")
}

value, envVar := getOneWithFallback(names[0], names[1:]...)
value, envVar := getOneWithFallback(config, names[0], names[1:]...)
if len(value) == 0 {
missingEnvVars = append(missingEnvVars, envVar)
continue
Expand All @@ -78,14 +78,14 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
return values, nil
}

func getOneWithFallback(main string, names ...string) (string, string) {
value := GetOrFile(main)
func getOneWithFallback(config map[string]string, main string, names ...string) (string, string) {
value := GetOrFile(config, main)
if len(value) > 0 {
return value, main
}

for _, name := range names {
value := GetOrFile(name)
value := GetOrFile(config, name)
if len(value) > 0 {
return value, main
}
Expand All @@ -96,8 +96,8 @@ func getOneWithFallback(main string, names ...string) (string, string) {

// GetOrDefaultInt returns the given environment variable value as an integer.
// Returns the default if the envvar cannot be coopered to an int, or is not found.
func GetOrDefaultInt(envVar string, defaultValue int) int {
v, err := strconv.Atoi(GetOrFile(envVar))
func GetOrDefaultInt(config map[string]string, envVar string, defaultValue int) int {
v, err := strconv.Atoi(GetOrFile(config, envVar))
if err != nil {
return defaultValue
}
Expand All @@ -107,8 +107,8 @@ func GetOrDefaultInt(envVar string, defaultValue int) int {

// GetOrDefaultSecond returns the given environment variable value as an time.Duration (second).
// Returns the default if the envvar cannot be coopered to an int, or is not found.
func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration {
v := GetOrDefaultInt(envVar, -1)
func GetOrDefaultSecond(config map[string]string, envVar string, defaultValue time.Duration) time.Duration {
v := GetOrDefaultInt(config, envVar, -1)
if v < 0 {
return defaultValue
}
Expand All @@ -118,8 +118,8 @@ func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration

// GetOrDefaultString returns the given environment variable value as a string.
// Returns the default if the envvar cannot be find.
func GetOrDefaultString(envVar, defaultValue string) string {
v := GetOrFile(envVar)
func GetOrDefaultString(config map[string]string, envVar, defaultValue string) string {
v := GetOrFile(config, envVar)
if len(v) == 0 {
return defaultValue
}
Expand All @@ -129,8 +129,8 @@ func GetOrDefaultString(envVar, defaultValue string) string {

// GetOrDefaultBool returns the given environment variable value as a boolean.
// Returns the default if the envvar cannot be coopered to a boolean, or is not found.
func GetOrDefaultBool(envVar string, defaultValue bool) bool {
v, err := strconv.ParseBool(GetOrFile(envVar))
func GetOrDefaultBool(config map[string]string, envVar string, defaultValue bool) bool {
v, err := strconv.ParseBool(GetOrFile(config, envVar))
if err != nil {
return defaultValue
}
Expand All @@ -141,7 +141,11 @@ func GetOrDefaultBool(envVar string, defaultValue bool) bool {
// GetOrFile Attempts to resolve 'key' as an environment variable.
// Failing that, it will check to see if '<key>_FILE' exists.
// If so, it will attempt to read from the referenced file to populate a value.
func GetOrFile(envVar string) string {
func GetOrFile(config map[string]string, envVar string) string {
if v, present := config[envVar]; present {
return v
}

envVarValue := os.Getenv(envVar)
if envVarValue != "" {
return envVarValue
Expand Down
47 changes: 39 additions & 8 deletions platform/config/env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestGetWithFallback(t *testing.T) {

for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
value, err := GetWithFallback(test.groups...)
value, err := GetWithFallback(nil, test.groups...)
if len(test.expected.error) > 0 {
assert.EqualError(t, err, test.expected.error)
} else {
Expand Down Expand Up @@ -147,7 +147,7 @@ func TestGetOrDefaultInt(t *testing.T) {
err := os.Setenv(key, test.envValue)
require.NoError(t, err)

result := GetOrDefaultInt(key, test.defaultValue)
result := GetOrDefaultInt(nil, key, test.defaultValue)
assert.Equal(t, test.expected, result)
})
}
Expand Down Expand Up @@ -194,7 +194,7 @@ func TestGetOrDefaultSecond(t *testing.T) {
err := os.Setenv(key, test.envValue)
require.NoError(t, err)

result := GetOrDefaultSecond(key, test.defaultValue)
result := GetOrDefaultSecond(nil, key, test.defaultValue)
assert.Equal(t, test.expected, result)
})
}
Expand Down Expand Up @@ -228,7 +228,7 @@ func TestGetOrDefaultString(t *testing.T) {
err := os.Setenv(key, test.envValue)
require.NoError(t, err)

actual := GetOrDefaultString(key, test.defaultValue)
actual := GetOrDefaultString(nil, key, test.defaultValue)
assert.Equal(t, test.expected, actual)
})
}
Expand Down Expand Up @@ -268,7 +268,7 @@ func TestGetOrDefaultBool(t *testing.T) {
err := os.Setenv(key, test.envValue)
require.NoError(t, err)

actual := GetOrDefaultBool(key, test.defaultValue)
actual := GetOrDefaultBool(nil, key, test.defaultValue)
assert.Equal(t, test.expected, actual)
})
}
Expand All @@ -279,7 +279,7 @@ func TestGetOrFile_ReadsEnvVars(t *testing.T) {
require.NoError(t, err)
defer os.Unsetenv("TEST_LEGO_ENV_VAR")

value := GetOrFile("TEST_LEGO_ENV_VAR")
value := GetOrFile(nil, "TEST_LEGO_ENV_VAR")

assert.Equal(t, "lego_env", value)
}
Expand Down Expand Up @@ -320,7 +320,7 @@ func TestGetOrFile_ReadsFiles(t *testing.T) {
require.NoError(t, err)
defer os.Unsetenv(varEnvFileName)

value := GetOrFile(varEnvName)
value := GetOrFile(nil, varEnvName)

assert.Equal(t, "lego_file", value)
})
Expand Down Expand Up @@ -351,7 +351,38 @@ func TestGetOrFile_PrefersEnvVars(t *testing.T) {
require.NoError(t, err)
defer os.Unsetenv(varEnvName)

value := GetOrFile(varEnvName)
value := GetOrFile(nil, varEnvName)

assert.Equal(t, "lego_env", value)
}

func TestExtraConfig(t *testing.T) {
config := map[string]string{
"STRING": "test_extra_config",
"INT": "42",
"BOOL": "true",
}

res, err := Get(config, "STRING")
require.NoError(t, err)
require.Equal(t, res, map[string]string{"STRING": "test_extra_config"})

res, err = GetWithFallback(config, []string{"STRING"})
require.NoError(t, err)
require.Equal(t, res, map[string]string{"STRING": "test_extra_config"})

i := GetOrDefaultInt(config, "INT", -1)
require.Equal(t, i, 42)

time := GetOrDefaultSecond(config, "INT", 3)
require.Equal(t, time.Seconds(), 42.0)

s := GetOrDefaultString(config, "STRING", "DEFAULT")
require.Equal(t, s, "test_extra_config")

b := GetOrDefaultBool(config, "BOOL", false)
require.Equal(t, b, true)

s = GetOrFile(config, "STRING")
require.Equal(t, s, "test_extra_config")
}
4 changes: 2 additions & 2 deletions providers/dns/acmedns/acmedns.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ type DNSProvider struct {

// NewDNSProvider creates an ACME-DNS provider using file based account storage.
// Its configuration is loaded from the environment by reading EnvAPIBase and EnvStoragePath.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvAPIBase, EnvStoragePath)
func NewDNSProvider(conf map[string]string) (*DNSProvider, error) {
values, err := env.Get(conf, EnvAPIBase, EnvStoragePath)
if err != nil {
return nil, fmt.Errorf("acme-dns: %w", err)
}
Expand Down
18 changes: 9 additions & 9 deletions providers/dns/alidns/alidns.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ type Config struct {
}

// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
func NewDefaultConfig(conf map[string]string) *Config {
return &Config{
TTL: env.GetOrDefaultInt(EnvTTL, 600),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 10*time.Second),
TTL: env.GetOrDefaultInt(conf, EnvTTL, 600),
PropagationTimeout: env.GetOrDefaultSecond(conf, EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(conf, EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPTimeout: env.GetOrDefaultSecond(conf, EnvHTTPTimeout, 10*time.Second),
}
}

Expand All @@ -62,16 +62,16 @@ type DNSProvider struct {
// NewDNSProvider returns a DNSProvider instance configured for Alibaba Cloud DNS.
// Credentials must be passed in the environment variables:
// ALICLOUD_ACCESS_KEY and ALICLOUD_SECRET_KEY.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvAccessKey, EnvSecretKey)
func NewDNSProvider(conf map[string]string) (*DNSProvider, error) {
values, err := env.Get(conf, EnvAccessKey, EnvSecretKey)
if err != nil {
return nil, fmt.Errorf("alicloud: %w", err)
}

config := NewDefaultConfig()
config := NewDefaultConfig(conf)
config.APIKey = values[EnvAccessKey]
config.SecretKey = values[EnvSecretKey]
config.RegionID = env.GetOrFile(EnvRegionID)
config.RegionID = env.GetOrFile(conf, EnvRegionID)

return NewDNSProviderConfig(config)
}
Expand Down
8 changes: 4 additions & 4 deletions providers/dns/alidns/alidns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func TestNewDNSProvider(t *testing.T) {

envTest.Apply(test.envVars)

p, err := NewDNSProvider()
p, err := NewDNSProvider(nil)

if len(test.expected) == 0 {
require.NoError(t, err)
Expand Down Expand Up @@ -105,7 +105,7 @@ func TestNewDNSProviderConfig(t *testing.T) {

for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
config := NewDefaultConfig()
config := NewDefaultConfig(nil)
config.APIKey = test.apiKey
config.SecretKey = test.secretKey

Expand All @@ -129,7 +129,7 @@ func TestLivePresent(t *testing.T) {
}

envTest.RestoreEnv()
provider, err := NewDNSProvider()
provider, err := NewDNSProvider(nil)
require.NoError(t, err)

err = provider.Present(envTest.GetDomain(), "", "123d==")
Expand All @@ -142,7 +142,7 @@ func TestLiveCleanUp(t *testing.T) {
}

envTest.RestoreEnv()
provider, err := NewDNSProvider()
provider, err := NewDNSProvider(nil)
require.NoError(t, err)

time.Sleep(1 * time.Second)
Expand Down
16 changes: 8 additions & 8 deletions providers/dns/arvancloud/arvancloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ type Config struct {
}

// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
func NewDefaultConfig(conf map[string]string) *Config {
return &Config{
TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second),
TTL: env.GetOrDefaultInt(conf, EnvTTL, minTTL),
PropagationTimeout: env.GetOrDefaultSecond(conf, EnvPropagationTimeout, 120*time.Second),
PollingInterval: env.GetOrDefaultSecond(conf, EnvPollingInterval, 2*time.Second),
HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
Timeout: env.GetOrDefaultSecond(conf, EnvHTTPTimeout, 30*time.Second),
},
}
}
Expand All @@ -60,13 +60,13 @@ type DNSProvider struct {

// NewDNSProvider returns a DNSProvider instance configured for ArvanCloud.
// Credentials must be passed in the environment variable: ARVANCLOUD_API_KEY.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvAPIKey)
func NewDNSProvider(conf map[string]string) (*DNSProvider, error) {
values, err := env.Get(conf, EnvAPIKey)
if err != nil {
return nil, fmt.Errorf("arvancloud: %w", err)
}

config := NewDefaultConfig()
config := NewDefaultConfig(conf)
config.APIKey = values[EnvAPIKey]

return NewDNSProviderConfig(config)
Expand Down
Loading