forked from TrueCloudLab/lego
liquidweb: detect zone automatically (#2031)
Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
parent
2140e6befe
commit
8afdc9d01c
8 changed files with 471 additions and 133 deletions
|
@ -1635,9 +1635,8 @@ func displayDNSHelp(w io.Writer, name string) error {
|
||||||
ew.writeln()
|
ew.writeln()
|
||||||
|
|
||||||
ew.writeln(`Credentials:`)
|
ew.writeln(`Credentials:`)
|
||||||
ew.writeln(` - "LIQUID_WEB_PASSWORD": Storm API Password`)
|
ew.writeln(` - "LIQUID_WEB_PASSWORD": Liquid Web API Password`)
|
||||||
ew.writeln(` - "LIQUID_WEB_USERNAME": Storm API Username`)
|
ew.writeln(` - "LIQUID_WEB_USERNAME": Liquid Web API Username`)
|
||||||
ew.writeln(` - "LIQUID_WEB_ZONE": DNS Zone`)
|
|
||||||
ew.writeln()
|
ew.writeln()
|
||||||
|
|
||||||
ew.writeln(`Additional Configuration:`)
|
ew.writeln(`Additional Configuration:`)
|
||||||
|
@ -1645,7 +1644,8 @@ func displayDNSHelp(w io.Writer, name string) error {
|
||||||
ew.writeln(` - "LIQUID_WEB_POLLING_INTERVAL": Time between DNS propagation check`)
|
ew.writeln(` - "LIQUID_WEB_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||||
ew.writeln(` - "LIQUID_WEB_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
ew.writeln(` - "LIQUID_WEB_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||||
ew.writeln(` - "LIQUID_WEB_TTL": The TTL of the TXT record used for the DNS challenge`)
|
ew.writeln(` - "LIQUID_WEB_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||||
ew.writeln(` - "LIQUID_WEB_URL": Storm API endpoint`)
|
ew.writeln(` - "LIQUID_WEB_URL": Liquid Web API endpoint`)
|
||||||
|
ew.writeln(` - "LIQUID_WEB_ZONE": DNS Zone`)
|
||||||
|
|
||||||
ew.writeln()
|
ew.writeln()
|
||||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/liquidweb`)
|
ew.writeln(`More information: https://go-acme.github.io/lego/dns/liquidweb`)
|
||||||
|
|
|
@ -28,7 +28,6 @@ Here is an example bash command using the Liquid Web provider:
|
||||||
```bash
|
```bash
|
||||||
LIQUID_WEB_USERNAME=someuser \
|
LIQUID_WEB_USERNAME=someuser \
|
||||||
LIQUID_WEB_PASSWORD=somepass \
|
LIQUID_WEB_PASSWORD=somepass \
|
||||||
LIQUID_WEB_ZONE=tacoman.com.net \
|
|
||||||
lego --email you@example.com --dns liquidweb --domains my.example.org run
|
lego --email you@example.com --dns liquidweb --domains my.example.org run
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -39,9 +38,8 @@ lego --email you@example.com --dns liquidweb --domains my.example.org run
|
||||||
|
|
||||||
| Environment Variable Name | Description |
|
| Environment Variable Name | Description |
|
||||||
|-----------------------|-------------|
|
|-----------------------|-------------|
|
||||||
| `LIQUID_WEB_PASSWORD` | Storm API Password |
|
| `LIQUID_WEB_PASSWORD` | Liquid Web API Password |
|
||||||
| `LIQUID_WEB_USERNAME` | Storm API Username |
|
| `LIQUID_WEB_USERNAME` | Liquid Web API Username |
|
||||||
| `LIQUID_WEB_ZONE` | DNS Zone |
|
|
||||||
|
|
||||||
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
||||||
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
||||||
|
@ -55,7 +53,8 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
||||||
| `LIQUID_WEB_POLLING_INTERVAL` | Time between DNS propagation check |
|
| `LIQUID_WEB_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||||
| `LIQUID_WEB_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
| `LIQUID_WEB_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||||
| `LIQUID_WEB_TTL` | The TTL of the TXT record used for the DNS challenge |
|
| `LIQUID_WEB_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||||
| `LIQUID_WEB_URL` | Storm API endpoint |
|
| `LIQUID_WEB_URL` | Liquid Web API endpoint |
|
||||||
|
| `LIQUID_WEB_ZONE` | DNS Zone |
|
||||||
|
|
||||||
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
||||||
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
||||||
|
@ -65,7 +64,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
||||||
|
|
||||||
## More information
|
## More information
|
||||||
|
|
||||||
- [API documentation](https://cart.liquidweb.com/storm/api/docs/v1/)
|
- [API documentation](https://api.liquidweb.com/docs/)
|
||||||
- [Go client](https://github.com/liquidweb/liquidweb-go)
|
- [Go client](https://github.com/liquidweb/liquidweb-go)
|
||||||
|
|
||||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -40,7 +40,7 @@ require (
|
||||||
github.com/infobloxopen/infoblox-go-client v1.1.1
|
github.com/infobloxopen/infoblox-go-client v1.1.1
|
||||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2
|
github.com/labbsr0x/bindman-dns-webhook v1.0.2
|
||||||
github.com/linode/linodego v1.17.2
|
github.com/linode/linodego v1.17.2
|
||||||
github.com/liquidweb/liquidweb-go v1.6.3
|
github.com/liquidweb/liquidweb-go v1.6.4
|
||||||
github.com/mattn/go-isatty v0.0.19
|
github.com/mattn/go-isatty v0.0.19
|
||||||
github.com/miekg/dns v1.1.55
|
github.com/miekg/dns v1.1.55
|
||||||
github.com/mimuret/golang-iij-dpf v0.9.1
|
github.com/mimuret/golang-iij-dpf v0.9.1
|
||||||
|
@ -134,7 +134,6 @@ require (
|
||||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
|
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/labbsr0x/goh v1.0.1 // indirect
|
github.com/labbsr0x/goh v1.0.1 // indirect
|
||||||
github.com/liquidweb/go-lwApi v0.0.5 // indirect
|
|
||||||
github.com/liquidweb/liquidweb-cli v0.6.9 // indirect
|
github.com/liquidweb/liquidweb-cli v0.6.9 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -386,12 +386,10 @@ github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmt
|
||||||
github.com/linode/linodego v1.17.2 h1:b32dj4662PGG5P9qVa6nBezccWdqgukndlMIuPGq1CQ=
|
github.com/linode/linodego v1.17.2 h1:b32dj4662PGG5P9qVa6nBezccWdqgukndlMIuPGq1CQ=
|
||||||
github.com/linode/linodego v1.17.2/go.mod h1:C2iyT3Vg2O2sPxkWka4XAQ5WSUtm5LmTZ3Adw43Ra7Q=
|
github.com/linode/linodego v1.17.2/go.mod h1:C2iyT3Vg2O2sPxkWka4XAQ5WSUtm5LmTZ3Adw43Ra7Q=
|
||||||
github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||||
github.com/liquidweb/go-lwApi v0.0.5 h1:CT4cdXzJXmo0bon298kS7NeSk+Gt8/UHpWBBol1NGCA=
|
|
||||||
github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
|
||||||
github.com/liquidweb/liquidweb-cli v0.6.9 h1:acbIvdRauiwbxIsOCEMXGwF75aSJDbDiyAWPjVnwoYM=
|
github.com/liquidweb/liquidweb-cli v0.6.9 h1:acbIvdRauiwbxIsOCEMXGwF75aSJDbDiyAWPjVnwoYM=
|
||||||
github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
|
github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
|
||||||
github.com/liquidweb/liquidweb-go v1.6.3 h1:NVHvcnX3eb3BltiIoA+gLYn15nOpkYkdizOEYGSKrk4=
|
github.com/liquidweb/liquidweb-go v1.6.4 h1:6S0m3hHSpiLqGD7AFSb7lH/W/qr1wx+tKil9fgIbjMc=
|
||||||
github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc=
|
github.com/liquidweb/liquidweb-go v1.6.4/go.mod h1:B934JPIIcdA+uTq2Nz5PgOtG6CuCaEvQKe/Ge/5GgZ4=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
|
|
@ -4,7 +4,9 @@ package liquidweb
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -14,7 +16,7 @@ import (
|
||||||
"github.com/liquidweb/liquidweb-go/network"
|
"github.com/liquidweb/liquidweb-go/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultBaseURL = "https://api.stormondemand.com"
|
const defaultBaseURL = "https://api.liquidweb.com"
|
||||||
|
|
||||||
// Environment variables names.
|
// Environment variables names.
|
||||||
const (
|
const (
|
||||||
|
@ -45,15 +47,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 {
|
||||||
config := &Config{
|
return &Config{
|
||||||
BaseURL: defaultBaseURL,
|
BaseURL: defaultBaseURL,
|
||||||
TTL: env.GetOrDefaultInt(EnvTTL, 300),
|
TTL: env.GetOrDefaultInt(EnvTTL, 300),
|
||||||
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
|
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
|
||||||
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second),
|
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 2*time.Second),
|
||||||
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 1*time.Minute),
|
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 1*time.Minute),
|
||||||
}
|
}
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNSProvider implements the challenge.Provider interface.
|
// DNSProvider implements the challenge.Provider interface.
|
||||||
|
@ -66,7 +66,7 @@ type DNSProvider struct {
|
||||||
|
|
||||||
// NewDNSProvider returns a DNSProvider instance configured for Liquid Web.
|
// NewDNSProvider returns a DNSProvider instance configured for Liquid Web.
|
||||||
func NewDNSProvider() (*DNSProvider, error) {
|
func NewDNSProvider() (*DNSProvider, error) {
|
||||||
values, err := env.Get(EnvUsername, EnvPassword, EnvZone)
|
values, err := env.Get(EnvUsername, EnvPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("liquidweb: %w", err)
|
return nil, fmt.Errorf("liquidweb: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ func NewDNSProvider() (*DNSProvider, error) {
|
||||||
config.BaseURL = env.GetOrFile(EnvURL)
|
config.BaseURL = env.GetOrFile(EnvURL)
|
||||||
config.Username = values[EnvUsername]
|
config.Username = values[EnvUsername]
|
||||||
config.Password = values[EnvPassword]
|
config.Password = values[EnvPassword]
|
||||||
config.Zone = values[EnvZone]
|
config.Zone = env.GetOrDefaultString(EnvZone, "")
|
||||||
|
|
||||||
return NewDNSProviderConfig(config)
|
return NewDNSProviderConfig(config)
|
||||||
}
|
}
|
||||||
|
@ -90,19 +90,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
config.BaseURL = defaultBaseURL
|
config.BaseURL = defaultBaseURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Zone == "" {
|
|
||||||
return nil, errors.New("liquidweb: zone is missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Username == "" {
|
|
||||||
return nil, errors.New("liquidweb: username is missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Password == "" {
|
|
||||||
return nil, errors.New("liquidweb: password is missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize LW client.
|
|
||||||
client, err := lw.NewAPI(config.Username, config.Password, config.BaseURL, int(config.HTTPTimeout.Seconds()))
|
client, err := lw.NewAPI(config.Username, config.Password, config.BaseURL, int(config.HTTPTimeout.Seconds()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("liquidweb: could not create Liquid Web API client: %w", err)
|
return nil, fmt.Errorf("liquidweb: could not create Liquid Web API client: %w", err)
|
||||||
|
@ -133,6 +120,15 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||||
TTL: d.config.TTL,
|
TTL: d.config.TTL,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.Zone == "" {
|
||||||
|
bestZone, err := d.findZone(params.Name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("liquidweb: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
params.Zone = bestZone
|
||||||
|
}
|
||||||
|
|
||||||
dnsEntry, err := d.client.NetworkDNS.Create(params)
|
dnsEntry, err := d.client.NetworkDNS.Create(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("liquidweb: could not create TXT record: %w", err)
|
return fmt.Errorf("liquidweb: could not create TXT record: %w", err)
|
||||||
|
@ -167,3 +163,31 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DNSProvider) findZone(domain string) (string, error) {
|
||||||
|
zones, err := d.client.NetworkDNSZone.ListAll()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to retrieve zones for account: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter the zones on the account to only ones that match
|
||||||
|
var zs []network.DNSZone
|
||||||
|
for _, item := range zones.Items {
|
||||||
|
if strings.HasSuffix(domain, item.Name) {
|
||||||
|
zs = append(zs, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(zs) < 1 {
|
||||||
|
return "", fmt.Errorf("no valid zone in account for certificate '%s'", domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// powerdns _only_ looks for records on the longest matching subdomain zone aka,
|
||||||
|
// for test.sub.example.com if sub.example.com exists,
|
||||||
|
// it will look there it will not look atexample.com even if it also exists
|
||||||
|
sort.Slice(zs, func(i, j int) bool {
|
||||||
|
return len(zs[i].Name) > len(zs[j].Name)
|
||||||
|
})
|
||||||
|
|
||||||
|
return zs[0].Name, nil
|
||||||
|
}
|
||||||
|
|
|
@ -7,22 +7,21 @@ Since = "v3.1.0"
|
||||||
Example = '''
|
Example = '''
|
||||||
LIQUID_WEB_USERNAME=someuser \
|
LIQUID_WEB_USERNAME=someuser \
|
||||||
LIQUID_WEB_PASSWORD=somepass \
|
LIQUID_WEB_PASSWORD=somepass \
|
||||||
LIQUID_WEB_ZONE=tacoman.com.net \
|
|
||||||
lego --email you@example.com --dns liquidweb --domains my.example.org run
|
lego --email you@example.com --dns liquidweb --domains my.example.org run
|
||||||
'''
|
'''
|
||||||
|
|
||||||
[Configuration]
|
[Configuration]
|
||||||
[Configuration.Credentials]
|
[Configuration.Credentials]
|
||||||
LIQUID_WEB_USERNAME = "Storm API Username"
|
LIQUID_WEB_USERNAME = "Liquid Web API Username"
|
||||||
LIQUID_WEB_PASSWORD = "Storm API Password"
|
LIQUID_WEB_PASSWORD = "Liquid Web API Password"
|
||||||
LIQUID_WEB_ZONE = "DNS Zone"
|
|
||||||
[Configuration.Additional]
|
[Configuration.Additional]
|
||||||
LIQUID_WEB_URL = "Storm API endpoint"
|
LIQUID_WEB_ZONE = "DNS Zone"
|
||||||
|
LIQUID_WEB_URL = "Liquid Web API endpoint"
|
||||||
LIQUID_WEB_TTL = "The TTL of the TXT record used for the DNS challenge"
|
LIQUID_WEB_TTL = "The TTL of the TXT record used for the DNS challenge"
|
||||||
LIQUID_WEB_POLLING_INTERVAL = "Time between DNS propagation check"
|
LIQUID_WEB_POLLING_INTERVAL = "Time between DNS propagation check"
|
||||||
LIQUID_WEB_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
LIQUID_WEB_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
||||||
LIQUID_WEB_HTTP_TIMEOUT = "Maximum waiting time for the DNS records to be created (not verified)"
|
LIQUID_WEB_HTTP_TIMEOUT = "Maximum waiting time for the DNS records to be created (not verified)"
|
||||||
|
|
||||||
[Links]
|
[Links]
|
||||||
API = "https://cart.liquidweb.com/storm/api/docs/v1/"
|
API = "https://api.liquidweb.com/docs/"
|
||||||
GoClient = "https://github.com/liquidweb/liquidweb-go"
|
GoClient = "https://github.com/liquidweb/liquidweb-go"
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package liquidweb
|
package liquidweb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/platform/tester"
|
"github.com/go-acme/lego/v4/platform/tester"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/liquidweb/liquidweb-go/network"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,23 +18,20 @@ var envTest = tester.NewEnvTest(
|
||||||
EnvZone).
|
EnvZone).
|
||||||
WithDomain(envDomain)
|
WithDomain(envDomain)
|
||||||
|
|
||||||
func setupTest(t *testing.T) (*DNSProvider, *http.ServeMux) {
|
func setupTest(t *testing.T, initRecs ...network.DNSRecord) *DNSProvider {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
serverURL := mockAPIServer(t, initRecs)
|
||||||
server := httptest.NewServer(mux)
|
|
||||||
t.Cleanup(server.Close)
|
|
||||||
|
|
||||||
config := NewDefaultConfig()
|
config := NewDefaultConfig()
|
||||||
config.Username = "blars"
|
config.Username = "blars"
|
||||||
config.Password = "tacoman"
|
config.Password = "tacoman"
|
||||||
config.BaseURL = server.URL
|
config.BaseURL = serverURL
|
||||||
config.Zone = "tacoman.com"
|
|
||||||
|
|
||||||
provider, err := NewDNSProviderConfig(config)
|
provider, err := NewDNSProviderConfig(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return provider, mux
|
return provider
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDNSProvider(t *testing.T) {
|
func TestNewDNSProvider(t *testing.T) {
|
||||||
|
@ -48,7 +41,14 @@ func TestNewDNSProvider(t *testing.T) {
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "success",
|
desc: "minimum-success",
|
||||||
|
envVars: map[string]string{
|
||||||
|
EnvUsername: "blars",
|
||||||
|
EnvPassword: "tacoman",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "set-everything",
|
||||||
envVars: map[string]string{
|
envVars: map[string]string{
|
||||||
EnvURL: "https://storm.com",
|
EnvURL: "https://storm.com",
|
||||||
EnvUsername: "blars",
|
EnvUsername: "blars",
|
||||||
|
@ -59,7 +59,7 @@ func TestNewDNSProvider(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "missing credentials",
|
desc: "missing credentials",
|
||||||
envVars: map[string]string{},
|
envVars: map[string]string{},
|
||||||
expected: "liquidweb: some credentials information are missing: LIQUID_WEB_USERNAME,LIQUID_WEB_PASSWORD,LIQUID_WEB_ZONE",
|
expected: "liquidweb: some credentials information are missing: LIQUID_WEB_USERNAME,LIQUID_WEB_PASSWORD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "missing username",
|
desc: "missing username",
|
||||||
|
@ -74,14 +74,8 @@ func TestNewDNSProvider(t *testing.T) {
|
||||||
envVars: map[string]string{
|
envVars: map[string]string{
|
||||||
EnvUsername: "blars",
|
EnvUsername: "blars",
|
||||||
EnvZone: "blars.com",
|
EnvZone: "blars.com",
|
||||||
}, expected: "liquidweb: some credentials information are missing: LIQUID_WEB_PASSWORD",
|
},
|
||||||
},
|
expected: "liquidweb: some credentials information are missing: LIQUID_WEB_PASSWORD",
|
||||||
{
|
|
||||||
desc: "missing zone",
|
|
||||||
envVars: map[string]string{
|
|
||||||
EnvUsername: "blars",
|
|
||||||
EnvPassword: "tacoman",
|
|
||||||
}, expected: "liquidweb: some credentials information are missing: LIQUID_WEB_ZONE",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,28 +120,21 @@ func TestNewDNSProviderConfig(t *testing.T) {
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
zone: "",
|
zone: "",
|
||||||
expected: "liquidweb: zone is missing",
|
expected: "liquidweb: could not create Liquid Web API client: provided username is empty",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "missing username",
|
desc: "missing username",
|
||||||
username: "",
|
username: "",
|
||||||
password: "secret",
|
password: "secret",
|
||||||
zone: "example.com",
|
zone: "example.com",
|
||||||
expected: "liquidweb: username is missing",
|
expected: "liquidweb: could not create Liquid Web API client: provided username is empty",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "missing password",
|
desc: "missing password",
|
||||||
username: "acme",
|
username: "acme",
|
||||||
password: "",
|
password: "",
|
||||||
zone: "example.com",
|
zone: "example.com",
|
||||||
expected: "liquidweb: password is missing",
|
expected: "liquidweb: could not create Liquid Web API client: provided password is empty",
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "missing zone",
|
|
||||||
username: "acme",
|
|
||||||
password: "secret",
|
|
||||||
zone: "",
|
|
||||||
expected: "liquidweb: zone is missing",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,75 +161,102 @@ func TestNewDNSProviderConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDNSProvider_Present(t *testing.T) {
|
func TestDNSProvider_Present(t *testing.T) {
|
||||||
provider, mux := setupTest(t)
|
provider := setupTest(t)
|
||||||
|
|
||||||
mux.HandleFunc("/v1/Network/DNS/Record/create", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
assert.Equal(t, http.MethodPost, r.Method)
|
|
||||||
|
|
||||||
username, password, ok := r.BasicAuth()
|
|
||||||
assert.Equal(t, "blars", username)
|
|
||||||
assert.Equal(t, "tacoman", password)
|
|
||||||
assert.True(t, ok)
|
|
||||||
|
|
||||||
reqBody, err := io.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedReqBody := `
|
|
||||||
{
|
|
||||||
"params": {
|
|
||||||
"name": "_acme-challenge.tacoman.com",
|
|
||||||
"rdata": "\"47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU\"",
|
|
||||||
"ttl": 300,
|
|
||||||
"type": "TXT",
|
|
||||||
"zone": "tacoman.com"
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
assert.JSONEq(t, expectedReqBody, string(reqBody))
|
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
_, err = fmt.Fprintf(w, `{
|
|
||||||
"type": "TXT",
|
|
||||||
"name": "_acme-challenge.tacoman.com",
|
|
||||||
"rdata": "\"47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU\"",
|
|
||||||
"ttl": 300,
|
|
||||||
"id": 1234567,
|
|
||||||
"prio": null
|
|
||||||
}`)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
err := provider.Present("tacoman.com", "", "")
|
err := provider.Present("tacoman.com", "", "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDNSProvider_CleanUp(t *testing.T) {
|
func TestDNSProvider_CleanUp(t *testing.T) {
|
||||||
provider, mux := setupTest(t)
|
provider := setupTest(t, network.DNSRecord{
|
||||||
|
Name: "_acme-challenge.tacoman.com",
|
||||||
mux.HandleFunc("/v1/Network/DNS/Record/delete", func(w http.ResponseWriter, r *http.Request) {
|
RData: "123d==",
|
||||||
assert.Equal(t, http.MethodPost, r.Method)
|
Type: "TXT",
|
||||||
|
TTL: 300,
|
||||||
username, password, ok := r.BasicAuth()
|
ID: 1234567,
|
||||||
assert.Equal(t, "blars", username)
|
ZoneID: 42,
|
||||||
assert.Equal(t, "tacoman", password)
|
|
||||||
assert.True(t, ok)
|
|
||||||
|
|
||||||
_, err := fmt.Fprintf(w, `{"deleted": "123"}`)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
provider.recordIDs["123"] = 1234567
|
provider.recordIDs["123d=="] = 1234567
|
||||||
|
|
||||||
err := provider.CleanUp("tacoman.com.", "123", "")
|
err := provider.CleanUp("tacoman.com.", "123d==", "")
|
||||||
require.NoError(t, err, "fail to remove TXT record")
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDNSProvider(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
initRecs []network.DNSRecord
|
||||||
|
domain string
|
||||||
|
token string
|
||||||
|
keyAuth string
|
||||||
|
present bool
|
||||||
|
expPresentErr string
|
||||||
|
cleanup bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "expected successful",
|
||||||
|
domain: "tacoman.com",
|
||||||
|
token: "123",
|
||||||
|
keyAuth: "456",
|
||||||
|
present: true,
|
||||||
|
cleanup: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "other successful",
|
||||||
|
domain: "banana.com",
|
||||||
|
token: "123",
|
||||||
|
keyAuth: "456",
|
||||||
|
present: true,
|
||||||
|
cleanup: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "zone not on account",
|
||||||
|
domain: "huckleberry.com",
|
||||||
|
token: "123",
|
||||||
|
keyAuth: "456",
|
||||||
|
present: true,
|
||||||
|
expPresentErr: "no valid zone in account for certificate '_acme-challenge.huckleberry.com'",
|
||||||
|
cleanup: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "ssl for domain",
|
||||||
|
domain: "sundae.cherry.com",
|
||||||
|
token: "5847953",
|
||||||
|
keyAuth: "34872934",
|
||||||
|
present: true,
|
||||||
|
cleanup: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "complicated domain",
|
||||||
|
domain: "always.money.stand.banana.com",
|
||||||
|
token: "5847953",
|
||||||
|
keyAuth: "there is always money in the banana stand",
|
||||||
|
present: true,
|
||||||
|
cleanup: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
provider := setupTest(t, test.initRecs...)
|
||||||
|
|
||||||
|
if test.present {
|
||||||
|
err := provider.Present(test.domain, test.token, test.keyAuth)
|
||||||
|
if test.expPresentErr == "" {
|
||||||
|
require.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
require.ErrorContains(t, err, test.expPresentErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if test.cleanup {
|
||||||
|
err := provider.CleanUp(test.domain, test.token, test.keyAuth)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLivePresent(t *testing.T) {
|
func TestLivePresent(t *testing.T) {
|
||||||
|
|
305
providers/dns/liquidweb/servermock_test.go
Normal file
305
providers/dns/liquidweb/servermock_test.go
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
package liquidweb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/liquidweb/liquidweb-go/network"
|
||||||
|
"github.com/liquidweb/liquidweb-go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mockAPIServer(t *testing.T, initRecs []network.DNSRecord) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
recs := make(map[int]network.DNSRecord)
|
||||||
|
|
||||||
|
for _, rec := range initRecs {
|
||||||
|
recs[int(rec.ID)] = rec
|
||||||
|
}
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.Handle("/v1/Network/DNS/Record/delete", mockAPIDelete(recs))
|
||||||
|
mux.Handle("/v1/Network/DNS/Record/create", mockAPICreate(recs))
|
||||||
|
mux.Handle("/v1/Network/DNS/Zone/list", mockAPIListZones())
|
||||||
|
mux.Handle("/bleed/Network/DNS/Record/delete", mockAPIDelete(recs))
|
||||||
|
mux.Handle("/bleed/Network/DNS/Record/create", mockAPICreate(recs))
|
||||||
|
mux.Handle("/bleed/Network/DNS/Zone/list", mockAPIListZones())
|
||||||
|
|
||||||
|
server := httptest.NewServer(requireBasicAuth(requireJSON(mux)))
|
||||||
|
t.Cleanup(server.Close)
|
||||||
|
|
||||||
|
return server.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireBasicAuth(next http.Handler) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
username, password, ok := r.BasicAuth()
|
||||||
|
if ok && username == "blars" && password == "tacoman" {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Error(w, "invalid auth", http.StatusForbidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireJSON(next http.Handler) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
_, err := buf.ReadFrom(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "malformed request - json required", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Body = io.NopCloser(buf)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockAPICreate(recs map[int]network.DNSRecord) http.HandlerFunc {
|
||||||
|
_, mockAPIServerZones := makeMockZones()
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "invalid request", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := struct {
|
||||||
|
Params network.DNSRecord `json:"params"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(body, &req); err != nil {
|
||||||
|
http.Error(w, makeEncodingError(body), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Params.ID = types.FlexInt(rand.Intn(10000000))
|
||||||
|
req.Params.ZoneID = types.FlexInt(mockAPIServerZones[req.Params.Name])
|
||||||
|
|
||||||
|
if _, exists := recs[int(req.Params.ID)]; exists {
|
||||||
|
http.Error(w, "dns record already exists", http.StatusTeapot)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
recs[int(req.Params.ID)] = req.Params
|
||||||
|
|
||||||
|
resp, err := json.Marshal(req.Params)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Error(w, string(resp), http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockAPIDelete(recs map[int]network.DNSRecord) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "invalid request", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := struct {
|
||||||
|
Params struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ID int `json:"id"`
|
||||||
|
} `json:"params"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
|
http.Error(w, makeEncodingError(body), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Params.ID == 0 {
|
||||||
|
http.Error(w, `{"error":"","error_class":"LW::Exception::Input::Multiple","errors":[{"error":"","error_class":"LW::Exception::Input::Required","field":"id","full_message":"The required field 'id' was missing a value.","position":null}],"field":["id"],"full_message":"The following input errors occurred:\nThe required field 'id' was missing a value.","type":null}`, http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := recs[req.Params.ID]; !ok {
|
||||||
|
http.Error(w, fmt.Sprintf(`{"error":"","error_class":"LW::Exception::RecordNotFound","field":"network_dns_rr","full_message":"Record 'network_dns_rr: %d' not found","input":"%d","public_message":null}`, req.Params.ID, req.Params.ID), http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(recs, req.Params.ID)
|
||||||
|
http.Error(w, fmt.Sprintf("{\"deleted\":%d}", req.Params.ID), http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockAPIListZones() http.HandlerFunc {
|
||||||
|
mockZones, mockAPIServerZones := makeMockZones()
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "invalid request", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := struct {
|
||||||
|
Params struct {
|
||||||
|
PageNum int `json:"page_num"`
|
||||||
|
} `json:"params"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(body, &req); err != nil {
|
||||||
|
http.Error(w, makeEncodingError(body), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case req.Params.PageNum < 1:
|
||||||
|
req.Params.PageNum = 1
|
||||||
|
case req.Params.PageNum > len(mockZones):
|
||||||
|
req.Params.PageNum = len(mockZones)
|
||||||
|
}
|
||||||
|
resp := mockZones[req.Params.PageNum]
|
||||||
|
resp.ItemTotal = types.FlexInt(len(mockAPIServerZones))
|
||||||
|
resp.PageNum = types.FlexInt(req.Params.PageNum)
|
||||||
|
resp.PageSize = 5
|
||||||
|
resp.PageTotal = types.FlexInt(len(mockZones))
|
||||||
|
|
||||||
|
var respBody []byte
|
||||||
|
if respBody, err = json.Marshal(resp); err == nil {
|
||||||
|
http.Error(w, string(respBody), http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Error(w, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeEncodingError(buf []byte) string {
|
||||||
|
return fmt.Sprintf(`{"data":"%q","encoding":"JSON","error":"unexpected end of string while parsing JSON string, at character offset 32 (before \"(end of string)\") at /usr/local/lp/libs/perl/LW/Base/Role/Serializer.pm line 16.\n","error_class":"LW::Exception::Deserialize","full_message":"Could not deserialize \"%q\" from JSON: unexpected end of string while parsing JSON string, at character offset 32 (before \"(end of string)\") at /usr/local/lp/libs/perl/LW/Base/Role/Serializer.pm line 16.\n"}⏎`, string(buf), string(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeMockZones() (map[int]network.DNSZoneList, map[string]int) {
|
||||||
|
mockZones := map[int]network.DNSZoneList{
|
||||||
|
1: {
|
||||||
|
Items: []network.DNSZone{
|
||||||
|
{
|
||||||
|
ID: 1,
|
||||||
|
Name: "blars.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "CORRECT",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 2,
|
||||||
|
Name: "tacoman.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "CORRECT",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 3,
|
||||||
|
Name: "storm.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "CORRECT",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 4,
|
||||||
|
Name: "not-apple.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "BAD_NAMESERVERS",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 5,
|
||||||
|
Name: "example.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "BAD_NAMESERVERS",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
Items: []network.DNSZone{
|
||||||
|
{
|
||||||
|
ID: 6,
|
||||||
|
Name: "banana.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "NXDOMAIN",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 7,
|
||||||
|
Name: "cherry.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "SERVFAIL",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 8,
|
||||||
|
Name: "dates.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "SERVFAIL",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 9,
|
||||||
|
Name: "eggplant.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "SERVFAIL",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 10,
|
||||||
|
Name: "fig.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "UNKNOWN",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
Items: []network.DNSZone{
|
||||||
|
{
|
||||||
|
ID: 11,
|
||||||
|
Name: "grapes.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "UNKNOWN",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 12,
|
||||||
|
Name: "money.banana.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "UNKNOWN",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 13,
|
||||||
|
Name: "money.stand.banana.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "UNKNOWN",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 14,
|
||||||
|
Name: "stand.banana.com",
|
||||||
|
Active: 1,
|
||||||
|
DelegationStatus: "UNKNOWN",
|
||||||
|
PrimaryNameserver: "ns.liquidweb.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockAPIServerZones := make(map[string]int)
|
||||||
|
for _, page := range mockZones {
|
||||||
|
for _, zone := range page.Items {
|
||||||
|
mockAPIServerZones[zone.Name] = int(zone.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mockZones, mockAPIServerZones
|
||||||
|
}
|
Loading…
Reference in a new issue