Skip to content

Commit 52990b3

Browse files
authored
liquidweb: add LWAPI_ prefix for env vars (go-acme#2034)
1 parent 8afdc9d commit 52990b3

File tree

4 files changed

+151
-49
lines changed

4 files changed

+151
-49
lines changed

platform/config/env/env.go

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -78,59 +78,59 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
7878
return values, nil
7979
}
8080

81+
func GetOneWithFallback[T any](main string, defaultValue T, fn func(string) (T, error), names ...string) T {
82+
v, _ := getOneWithFallback(main, names...)
83+
84+
value, err := fn(v)
85+
if err != nil {
86+
return defaultValue
87+
}
88+
89+
return value
90+
}
91+
8192
func getOneWithFallback(main string, names ...string) (string, string) {
8293
value := GetOrFile(main)
83-
if len(value) > 0 {
94+
if value != "" {
8495
return value, main
8596
}
8697

8798
for _, name := range names {
8899
value := GetOrFile(name)
89-
if len(value) > 0 {
100+
if value != "" {
90101
return value, main
91102
}
92103
}
93104

94105
return "", main
95106
}
96107

108+
// GetOrDefaultString returns the given environment variable value as a string.
109+
// Returns the default if the env var cannot be found.
110+
func GetOrDefaultString(envVar string, defaultValue string) string {
111+
return getOrDefault(envVar, defaultValue, ParseString)
112+
}
113+
114+
// GetOrDefaultBool returns the given environment variable value as a boolean.
115+
// Returns the default if the env var cannot be coopered to a boolean, or is not found.
116+
func GetOrDefaultBool(envVar string, defaultValue bool) bool {
117+
return getOrDefault(envVar, defaultValue, strconv.ParseBool)
118+
}
119+
97120
// GetOrDefaultInt returns the given environment variable value as an integer.
98121
// Returns the default if the env var cannot be coopered to an int, or is not found.
99122
func GetOrDefaultInt(envVar string, defaultValue int) int {
100-
v, err := strconv.Atoi(GetOrFile(envVar))
101-
if err != nil {
102-
return defaultValue
103-
}
104-
105-
return v
123+
return getOrDefault(envVar, defaultValue, strconv.Atoi)
106124
}
107125

108126
// GetOrDefaultSecond returns the given environment variable value as a time.Duration (second).
109127
// Returns the default if the env var cannot be coopered to an int, or is not found.
110128
func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration {
111-
v := GetOrDefaultInt(envVar, -1)
112-
if v < 0 {
113-
return defaultValue
114-
}
115-
116-
return time.Duration(v) * time.Second
117-
}
118-
119-
// GetOrDefaultString returns the given environment variable value as a string.
120-
// Returns the default if the env var cannot be found.
121-
func GetOrDefaultString(envVar, defaultValue string) string {
122-
v := GetOrFile(envVar)
123-
if v == "" {
124-
return defaultValue
125-
}
126-
127-
return v
129+
return getOrDefault(envVar, defaultValue, ParseSecond)
128130
}
129131

130-
// GetOrDefaultBool returns the given environment variable value as a boolean.
131-
// Returns the default if the env var cannot be coopered to a boolean, or is not found.
132-
func GetOrDefaultBool(envVar string, defaultValue bool) bool {
133-
v, err := strconv.ParseBool(GetOrFile(envVar))
132+
func getOrDefault[T any](envVar string, defaultValue T, fn func(string) (T, error)) T {
133+
v, err := fn(GetOrFile(envVar))
134134
if err != nil {
135135
return defaultValue
136136
}
@@ -161,3 +161,26 @@ func GetOrFile(envVar string) string {
161161

162162
return strings.TrimSuffix(string(fileContents), "\n")
163163
}
164+
165+
// ParseSecond parses env var value (string) to a second (time.Duration).
166+
func ParseSecond(s string) (time.Duration, error) {
167+
v, err := strconv.Atoi(s)
168+
if err != nil {
169+
return 0, err
170+
}
171+
172+
if v < 0 {
173+
return 0, fmt.Errorf("unsupported value: %d", v)
174+
}
175+
176+
return time.Duration(v) * time.Second, nil
177+
}
178+
179+
// ParseString parses env var value (string) to a string but throws an error when the string is empty.
180+
func ParseString(s string) (string, error) {
181+
if s == "" {
182+
return "", errors.New("empty string")
183+
}
184+
185+
return s, nil
186+
}

platform/config/env/env_test.go

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ func TestGetWithFallback(t *testing.T) {
1515
var1Missing := os.Getenv("TEST_LEGO_VAR_MISSING_1")
1616
var2Missing := os.Getenv("TEST_LEGO_VAR_MISSING_2")
1717

18-
defer func() {
18+
t.Cleanup(func() {
1919
_ = os.Setenv("TEST_LEGO_VAR_EXIST_1", var1Exist)
2020
_ = os.Setenv("TEST_LEGO_VAR_EXIST_2", var2Exist)
2121
_ = os.Setenv("TEST_LEGO_VAR_MISSING_1", var1Missing)
2222
_ = os.Setenv("TEST_LEGO_VAR_MISSING_2", var2Missing)
23-
}()
23+
})
2424

2525
err := os.Setenv("TEST_LEGO_VAR_EXIST_1", "VAR1")
2626
require.NoError(t, err)
@@ -93,7 +93,10 @@ func TestGetWithFallback(t *testing.T) {
9393
}
9494

9595
for _, test := range testCases {
96+
test := test
9697
t.Run(test.desc, func(t *testing.T) {
98+
t.Parallel()
99+
97100
value, err := GetWithFallback(test.groups...)
98101
if len(test.expected.error) > 0 {
99102
assert.EqualError(t, err, test.expected.error)
@@ -105,6 +108,74 @@ func TestGetWithFallback(t *testing.T) {
105108
}
106109
}
107110

111+
func TestGetOneWithFallback(t *testing.T) {
112+
var1Exist := os.Getenv("TEST_LEGO_VAR_EXIST_1")
113+
var2Exist := os.Getenv("TEST_LEGO_VAR_EXIST_2")
114+
var1Missing := os.Getenv("TEST_LEGO_VAR_MISSING_1")
115+
var2Missing := os.Getenv("TEST_LEGO_VAR_MISSING_2")
116+
117+
t.Cleanup(func() {
118+
_ = os.Setenv("TEST_LEGO_VAR_EXIST_1", var1Exist)
119+
_ = os.Setenv("TEST_LEGO_VAR_EXIST_2", var2Exist)
120+
_ = os.Setenv("TEST_LEGO_VAR_MISSING_1", var1Missing)
121+
_ = os.Setenv("TEST_LEGO_VAR_MISSING_2", var2Missing)
122+
})
123+
124+
err := os.Setenv("TEST_LEGO_VAR_EXIST_1", "VAR1")
125+
require.NoError(t, err)
126+
err = os.Setenv("TEST_LEGO_VAR_EXIST_2", "VAR2")
127+
require.NoError(t, err)
128+
err = os.Unsetenv("TEST_LEGO_VAR_MISSING_1")
129+
require.NoError(t, err)
130+
err = os.Unsetenv("TEST_LEGO_VAR_MISSING_2")
131+
require.NoError(t, err)
132+
133+
testCases := []struct {
134+
desc string
135+
main string
136+
defaultValue string
137+
alts []string
138+
expected string
139+
}{
140+
{
141+
desc: "with value and no alternative",
142+
main: "TEST_LEGO_VAR_EXIST_1",
143+
defaultValue: "oops",
144+
expected: "VAR1",
145+
},
146+
{
147+
desc: "with value and alternatives",
148+
main: "TEST_LEGO_VAR_EXIST_1",
149+
defaultValue: "oops",
150+
alts: []string{"TEST_LEGO_VAR_MISSING_1"},
151+
expected: "VAR1",
152+
},
153+
{
154+
desc: "without value and no alternatives",
155+
main: "TEST_LEGO_VAR_MISSING_1",
156+
defaultValue: "oops",
157+
expected: "oops",
158+
},
159+
{
160+
desc: "without value and alternatives",
161+
main: "TEST_LEGO_VAR_MISSING_1",
162+
defaultValue: "oops",
163+
alts: []string{"TEST_LEGO_VAR_EXIST_1"},
164+
expected: "VAR1",
165+
},
166+
}
167+
168+
for _, test := range testCases {
169+
test := test
170+
t.Run(test.desc, func(t *testing.T) {
171+
t.Parallel()
172+
173+
value := GetOneWithFallback(test.main, test.defaultValue, ParseString, test.alts...)
174+
assert.Equal(t, test.expected, value)
175+
})
176+
}
177+
}
178+
108179
func TestGetOrDefaultInt(t *testing.T) {
109180
testCases := []struct {
110181
desc string

providers/dns/liquidweb/liquidweb.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const defaultBaseURL = "https://api.liquidweb.com"
2020

2121
// Environment variables names.
2222
const (
23-
envNamespace = "LIQUID_WEB_"
23+
envNamespace = "LIQUID_WEB_"
24+
altEnvNamespace = "LWAPI_"
2425

2526
EnvURL = envNamespace + "URL"
2627
EnvUsername = envNamespace + "USERNAME"
@@ -49,10 +50,10 @@ type Config struct {
4950
func NewDefaultConfig() *Config {
5051
return &Config{
5152
BaseURL: defaultBaseURL,
52-
TTL: env.GetOrDefaultInt(EnvTTL, 300),
53-
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
54-
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second),
55-
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 1*time.Minute),
53+
TTL: env.GetOneWithFallback(EnvTTL, 300, strconv.Atoi, altEnvName(EnvTTL)),
54+
PropagationTimeout: env.GetOneWithFallback(EnvPropagationTimeout, 2*time.Minute, env.ParseSecond, altEnvName(EnvPropagationTimeout)),
55+
PollingInterval: env.GetOneWithFallback(EnvPollingInterval, 2*time.Second, env.ParseSecond, altEnvName(EnvPollingInterval)),
56+
HTTPTimeout: env.GetOneWithFallback(EnvHTTPTimeout, 1*time.Minute, env.ParseSecond, altEnvName(EnvHTTPTimeout)),
5657
}
5758
}
5859

@@ -66,16 +67,19 @@ type DNSProvider struct {
6667

6768
// NewDNSProvider returns a DNSProvider instance configured for Liquid Web.
6869
func NewDNSProvider() (*DNSProvider, error) {
69-
values, err := env.Get(EnvUsername, EnvPassword)
70+
values, err := env.GetWithFallback(
71+
[]string{EnvUsername, altEnvName(EnvUsername)},
72+
[]string{EnvPassword, altEnvName(EnvPassword)},
73+
)
7074
if err != nil {
7175
return nil, fmt.Errorf("liquidweb: %w", err)
7276
}
7377

7478
config := NewDefaultConfig()
75-
config.BaseURL = env.GetOrFile(EnvURL)
79+
config.BaseURL = env.GetOneWithFallback(EnvURL, defaultBaseURL, env.ParseString, altEnvName(EnvURL))
7680
config.Username = values[EnvUsername]
7781
config.Password = values[EnvPassword]
78-
config.Zone = env.GetOrDefaultString(EnvZone, "")
82+
config.Zone = env.GetOneWithFallback(EnvZone, "", env.ParseString, altEnvName(EnvZone))
7983

8084
return NewDNSProviderConfig(config)
8185
}
@@ -191,3 +195,7 @@ func (d *DNSProvider) findZone(domain string) (string, error) {
191195

192196
return zs[0].Name, nil
193197
}
198+
199+
func altEnvName(v string) string {
200+
return strings.ReplaceAll(v, envNamespace, altEnvNamespace)
201+
}

providers/dns/liquidweb/liquidweb.toml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@ Code = "liquidweb"
55
Since = "v3.1.0"
66

77
Example = '''
8-
LIQUID_WEB_USERNAME=someuser \
9-
LIQUID_WEB_PASSWORD=somepass \
8+
LWAPI_USERNAME=someuser \
9+
LWAPI_PASSWORD=somepass \
1010
lego --email [email protected] --dns liquidweb --domains my.example.org run
1111
'''
1212

1313
[Configuration]
1414
[Configuration.Credentials]
15-
LIQUID_WEB_USERNAME = "Liquid Web API Username"
16-
LIQUID_WEB_PASSWORD = "Liquid Web API Password"
15+
LWAPI_USERNAME = "Liquid Web API Username"
16+
LWAPI_PASSWORD = "Liquid Web API Password"
1717
[Configuration.Additional]
18-
LIQUID_WEB_ZONE = "DNS Zone"
19-
LIQUID_WEB_URL = "Liquid Web API endpoint"
20-
LIQUID_WEB_TTL = "The TTL of the TXT record used for the DNS challenge"
21-
LIQUID_WEB_POLLING_INTERVAL = "Time between DNS propagation check"
22-
LIQUID_WEB_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
23-
LIQUID_WEB_HTTP_TIMEOUT = "Maximum waiting time for the DNS records to be created (not verified)"
18+
LWAPI_ZONE = "DNS Zone"
19+
LWAPI_URL = "Liquid Web API endpoint"
20+
LWAPI_TTL = "The TTL of the TXT record used for the DNS challenge"
21+
LWAPI_POLLING_INTERVAL = "Time between DNS propagation check"
22+
LWAPI_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
23+
LWAPI_HTTP_TIMEOUT = "Maximum waiting time for the DNS records to be created (not verified)"
2424

2525
[Links]
2626
API = "https://api.liquidweb.com/docs/"

0 commit comments

Comments
 (0)