forked from TrueCloudLab/lego
Route53: Make it possible to configure from the env (#603)
This commit is contained in:
parent
725b6b816a
commit
ef7cd04002
5 changed files with 134 additions and 41 deletions
12
platform/config/env/env.go
vendored
12
platform/config/env/env.go
vendored
|
@ -3,6 +3,7 @@ package env
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,3 +26,14 @@ func Get(names ...string) (map[string]string, error) {
|
||||||
|
|
||||||
return values, nil
|
return values, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(os.Getenv(envVar))
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
56
platform/config/env/env_test.go
vendored
Normal file
56
platform/config/env/env_test.go
vendored
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package env
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_GetOrDefaultInt(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
envValue string
|
||||||
|
defaultValue int
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "valid value",
|
||||||
|
envValue: "100",
|
||||||
|
defaultValue: 2,
|
||||||
|
expected: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid content, use default value",
|
||||||
|
envValue: "abc123",
|
||||||
|
defaultValue: 2,
|
||||||
|
expected: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "valid negative value",
|
||||||
|
envValue: "-111",
|
||||||
|
defaultValue: 2,
|
||||||
|
expected: -111,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "float: invalid type, use default value",
|
||||||
|
envValue: "1.11",
|
||||||
|
defaultValue: 2,
|
||||||
|
expected: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = "LEGO_ENV_TC"
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
defer os.Unsetenv(key)
|
||||||
|
err := os.Setenv(key, test.envValue)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
result := GetOrDefaultInt(key, test.defaultValue)
|
||||||
|
assert.Equal(t, test.expected, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/aws/aws-sdk-go/service/route53"
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
"github.com/xenolf/lego/acme"
|
"github.com/xenolf/lego/acme"
|
||||||
|
"github.com/xenolf/lego/platform/config/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config is used to configure the creation of the DNSProvider
|
// Config is used to configure the creation of the DNSProvider
|
||||||
|
@ -29,11 +30,13 @@ type Config struct {
|
||||||
|
|
||||||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||||
func NewDefaultConfig() *Config {
|
func NewDefaultConfig() *Config {
|
||||||
|
propagationMins := env.GetOrDefaultInt("AWS_PROPAGATION_TIMEOUT", 2)
|
||||||
|
intervalSecs := env.GetOrDefaultInt("AWS_POLLING_INTERVAL", 4)
|
||||||
return &Config{
|
return &Config{
|
||||||
MaxRetries: 5,
|
MaxRetries: env.GetOrDefaultInt("AWS_MAX_RETRIES", 5),
|
||||||
TTL: 10,
|
TTL: env.GetOrDefaultInt("AWS_TTL", 10),
|
||||||
PropagationTimeout: time.Minute * 2,
|
PropagationTimeout: time.Minute * time.Duration(propagationMins),
|
||||||
PollingInterval: time.Second * 4,
|
PollingInterval: time.Second * time.Duration(intervalSecs),
|
||||||
HostedZoneID: os.Getenv("AWS_HOSTED_ZONE_ID"),
|
HostedZoneID: os.Getenv("AWS_HOSTED_ZONE_ID"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
package route53
|
package route53
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/aws/aws-sdk-go/service/route53"
|
"github.com/aws/aws-sdk-go/service/route53"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/xenolf/lego/platform/config/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRoute53TTL(t *testing.T) {
|
func TestRoute53TTL(t *testing.T) {
|
||||||
m, err := testGetAndPreCheck()
|
config, err := env.Get("AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION", "R53_DOMAIN")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Skip(err.Error())
|
t.Skip(err.Error())
|
||||||
}
|
}
|
||||||
|
@ -20,16 +19,16 @@ func TestRoute53TTL(t *testing.T) {
|
||||||
provider, err := NewDNSProvider()
|
provider, err := NewDNSProvider()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = provider.Present(m["route53Domain"], "foo", "bar")
|
err = provider.Present(config["R53_DOMAIN"], "foo", "bar")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// we need a separate R53 client here as the one in the DNS provider is
|
// we need a separate R53 client here as the one in the DNS provider is
|
||||||
// unexported.
|
// unexported.
|
||||||
fqdn := "_acme-challenge." + m["route53Domain"] + "."
|
fqdn := "_acme-challenge." + config["R53_DOMAIN"] + "."
|
||||||
svc := route53.New(session.New())
|
svc := route53.New(session.New())
|
||||||
zoneID, err := provider.getHostedZoneID(fqdn)
|
zoneID, err := provider.getHostedZoneID(fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
provider.CleanUp(m["route53Domain"], "foo", "bar")
|
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,32 +37,17 @@ func TestRoute53TTL(t *testing.T) {
|
||||||
}
|
}
|
||||||
resp, err := svc.ListResourceRecordSets(params)
|
resp, err := svc.ListResourceRecordSets(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
provider.CleanUp(m["route53Domain"], "foo", "bar")
|
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range resp.ResourceRecordSets {
|
for _, v := range resp.ResourceRecordSets {
|
||||||
if aws.StringValue(v.Name) == fqdn && aws.StringValue(v.Type) == "TXT" && aws.Int64Value(v.TTL) == 10 {
|
if aws.StringValue(v.Name) == fqdn && aws.StringValue(v.Type) == "TXT" && aws.Int64Value(v.TTL) == 10 {
|
||||||
provider.CleanUp(m["route53Domain"], "foo", "bar")
|
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider.CleanUp(m["route53Domain"], "foo", "bar")
|
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
|
||||||
t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", m["route53Domain"])
|
t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", config["R53_DOMAIN"])
|
||||||
}
|
|
||||||
|
|
||||||
func testGetAndPreCheck() (map[string]string, error) {
|
|
||||||
m := map[string]string{
|
|
||||||
"route53Key": os.Getenv("AWS_ACCESS_KEY_ID"),
|
|
||||||
"route53Secret": os.Getenv("AWS_SECRET_ACCESS_KEY"),
|
|
||||||
"route53Region": os.Getenv("AWS_REGION"),
|
|
||||||
"route53Domain": os.Getenv("R53_DOMAIN"),
|
|
||||||
}
|
|
||||||
for _, v := range m {
|
|
||||||
if v == "" {
|
|
||||||
return nil, fmt.Errorf("AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, and R53_DOMAIN are needed to run this test")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
@ -13,24 +14,40 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
route53Secret string
|
r53AwsSecretAccessKey string
|
||||||
route53Key string
|
r53AwsAccessKeyID string
|
||||||
route53Region string
|
r53AwsRegion string
|
||||||
route53Zone string
|
r53AwsHostedZoneID string
|
||||||
|
|
||||||
|
r53AwsMaxRetries string
|
||||||
|
r53AwsTTL string
|
||||||
|
r53AwsPropagationTimeout string
|
||||||
|
r53AwsPollingInterval string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
route53Key = os.Getenv("AWS_ACCESS_KEY_ID")
|
r53AwsAccessKeyID = os.Getenv("AWS_ACCESS_KEY_ID")
|
||||||
route53Secret = os.Getenv("AWS_SECRET_ACCESS_KEY")
|
r53AwsSecretAccessKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
|
||||||
route53Region = os.Getenv("AWS_REGION")
|
r53AwsRegion = os.Getenv("AWS_REGION")
|
||||||
route53Zone = os.Getenv("AWS_HOSTED_ZONE_ID")
|
r53AwsHostedZoneID = os.Getenv("AWS_HOSTED_ZONE_ID")
|
||||||
|
|
||||||
|
r53AwsMaxRetries = os.Getenv("AWS_MAX_RETRIES")
|
||||||
|
r53AwsTTL = os.Getenv("AWS_TTL")
|
||||||
|
r53AwsPropagationTimeout = os.Getenv("AWS_PROPAGATION_TIMEOUT")
|
||||||
|
r53AwsPollingInterval = os.Getenv("AWS_POLLING_INTERVAL")
|
||||||
}
|
}
|
||||||
|
|
||||||
func restoreEnv() {
|
func restoreEnv() {
|
||||||
os.Setenv("AWS_ACCESS_KEY_ID", route53Key)
|
os.Setenv("AWS_ACCESS_KEY_ID", r53AwsAccessKeyID)
|
||||||
os.Setenv("AWS_SECRET_ACCESS_KEY", route53Secret)
|
os.Setenv("AWS_SECRET_ACCESS_KEY", r53AwsSecretAccessKey)
|
||||||
os.Setenv("AWS_REGION", route53Region)
|
os.Setenv("AWS_REGION", r53AwsRegion)
|
||||||
os.Setenv("AWS_HOSTED_ZONE_ID", route53Zone)
|
os.Setenv("AWS_HOSTED_ZONE_ID", r53AwsHostedZoneID)
|
||||||
|
|
||||||
|
os.Setenv("AWS_MAX_RETRIES", r53AwsMaxRetries)
|
||||||
|
os.Setenv("AWS_TTL", r53AwsTTL)
|
||||||
|
os.Setenv("AWS_PROPAGATION_TIMEOUT", r53AwsPropagationTimeout)
|
||||||
|
os.Setenv("AWS_POLLING_INTERVAL", r53AwsPollingInterval)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRoute53Provider(ts *httptest.Server) *DNSProvider {
|
func makeRoute53Provider(ts *httptest.Server) *DNSProvider {
|
||||||
|
@ -84,6 +101,27 @@ func TestHostedZoneIDFromEnv(t *testing.T) {
|
||||||
assert.Equal(t, testZoneID, fqdn)
|
assert.Equal(t, testZoneID, fqdn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigFromEnv(t *testing.T) {
|
||||||
|
defer restoreEnv()
|
||||||
|
|
||||||
|
config := NewDefaultConfig()
|
||||||
|
assert.Equal(t, config.TTL, 10, "Expected TTL to be use the default")
|
||||||
|
|
||||||
|
os.Setenv("AWS_MAX_RETRIES", "10")
|
||||||
|
os.Setenv("AWS_TTL", "99")
|
||||||
|
os.Setenv("AWS_PROPAGATION_TIMEOUT", "60")
|
||||||
|
os.Setenv("AWS_POLLING_INTERVAL", "60")
|
||||||
|
const zoneID = "abc123"
|
||||||
|
os.Setenv("AWS_HOSTED_ZONE_ID", zoneID)
|
||||||
|
|
||||||
|
config = NewDefaultConfig()
|
||||||
|
assert.Equal(t, config.MaxRetries, 10, "Expected PropagationTimeout to be configured from the environment")
|
||||||
|
assert.Equal(t, config.TTL, 99, "Expected TTL to be configured from the environment")
|
||||||
|
assert.Equal(t, config.PropagationTimeout, time.Minute*60, "Expected PropagationTimeout to be configured from the environment")
|
||||||
|
assert.Equal(t, config.PollingInterval, time.Second*60, "Expected PollingInterval to be configured from the environment")
|
||||||
|
assert.Equal(t, config.HostedZoneID, zoneID, "Expected HostedZoneID to be configured from the environment")
|
||||||
|
}
|
||||||
|
|
||||||
func TestRoute53Present(t *testing.T) {
|
func TestRoute53Present(t *testing.T) {
|
||||||
mockResponses := MockResponseMap{
|
mockResponses := MockResponseMap{
|
||||||
"/2013-04-01/hostedzonesbyname": MockResponse{StatusCode: 200, Body: ListHostedZonesByNameResponse},
|
"/2013-04-01/hostedzonesbyname": MockResponse{StatusCode: 200, Body: ListHostedZonesByNameResponse},
|
||||||
|
|
Loading…
Reference in a new issue