mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-07 01:56:57 +02:00
Add OVH API rate limiting option
This commit is contained in:
parent
ccab168a35
commit
ba5afe9518
1
go.mod
1
go.mod
@ -51,6 +51,7 @@ require (
|
|||||||
github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92
|
github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92
|
||||||
github.com/vultr/govultr v0.3.2
|
github.com/vultr/govultr v0.3.2
|
||||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875
|
go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875
|
||||||
|
go.uber.org/ratelimit v0.1.0
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||||
google.golang.org/api v0.15.0
|
google.golang.org/api v0.15.0
|
||||||
|
2
go.sum
2
go.sum
@ -550,6 +550,8 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|||||||
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/ratelimit v0.1.0 h1:U2AruXqeTb4Eh9sYQSTrMhH8Cb7M0Ian2ibBOnBcnAw=
|
||||||
|
go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||||
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||||
|
2
main.go
2
main.go
@ -200,7 +200,7 @@ func main() {
|
|||||||
case "digitalocean":
|
case "digitalocean":
|
||||||
p, err = digitalocean.NewDigitalOceanProvider(ctx, domainFilter, cfg.DryRun, cfg.DigitalOceanAPIPageSize)
|
p, err = digitalocean.NewDigitalOceanProvider(ctx, domainFilter, cfg.DryRun, cfg.DigitalOceanAPIPageSize)
|
||||||
case "ovh":
|
case "ovh":
|
||||||
p, err = ovh.NewOVHProvider(ctx, domainFilter, cfg.OVHEndpoint, cfg.DryRun)
|
p, err = ovh.NewOVHProvider(ctx, domainFilter, cfg.OVHEndpoint, cfg.OVHApiRateLimit, cfg.DryRun)
|
||||||
case "linode":
|
case "linode":
|
||||||
p, err = linode.NewLinodeProvider(domainFilter, cfg.DryRun, externaldns.Version)
|
p, err = linode.NewLinodeProvider(domainFilter, cfg.DryRun, externaldns.Version)
|
||||||
case "dnsimple":
|
case "dnsimple":
|
||||||
|
@ -99,6 +99,7 @@ type Config struct {
|
|||||||
OCIConfigFile string
|
OCIConfigFile string
|
||||||
InMemoryZones []string
|
InMemoryZones []string
|
||||||
OVHEndpoint string
|
OVHEndpoint string
|
||||||
|
OVHApiRateLimit int
|
||||||
PDNSServer string
|
PDNSServer string
|
||||||
PDNSAPIKey string `secure:"yes"`
|
PDNSAPIKey string `secure:"yes"`
|
||||||
PDNSTLSEnabled bool
|
PDNSTLSEnabled bool
|
||||||
@ -197,6 +198,7 @@ var defaultConfig = &Config{
|
|||||||
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
||||||
InMemoryZones: []string{},
|
InMemoryZones: []string{},
|
||||||
OVHEndpoint: "ovh-eu",
|
OVHEndpoint: "ovh-eu",
|
||||||
|
OVHApiRateLimit: 20,
|
||||||
PDNSServer: "http://localhost:8081",
|
PDNSServer: "http://localhost:8081",
|
||||||
PDNSAPIKey: "",
|
PDNSAPIKey: "",
|
||||||
PDNSTLSEnabled: false,
|
PDNSTLSEnabled: false,
|
||||||
@ -360,6 +362,7 @@ func (cfg *Config) ParseFlags(args []string) error {
|
|||||||
app.Flag("rcodezero-txt-encrypt", "When using the Rcodezero provider with txt registry option, set if TXT rrs are encrypted (default: false)").Default(strconv.FormatBool(defaultConfig.RcodezeroTXTEncrypt)).BoolVar(&cfg.RcodezeroTXTEncrypt)
|
app.Flag("rcodezero-txt-encrypt", "When using the Rcodezero provider with txt registry option, set if TXT rrs are encrypted (default: false)").Default(strconv.FormatBool(defaultConfig.RcodezeroTXTEncrypt)).BoolVar(&cfg.RcodezeroTXTEncrypt)
|
||||||
app.Flag("inmemory-zone", "Provide a list of pre-configured zones for the inmemory provider; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.InMemoryZones)
|
app.Flag("inmemory-zone", "Provide a list of pre-configured zones for the inmemory provider; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.InMemoryZones)
|
||||||
app.Flag("ovh-endpoint", "When using the OVH provider, specify the endpoint (default: ovh-eu)").Default(defaultConfig.OVHEndpoint).StringVar(&cfg.OVHEndpoint)
|
app.Flag("ovh-endpoint", "When using the OVH provider, specify the endpoint (default: ovh-eu)").Default(defaultConfig.OVHEndpoint).StringVar(&cfg.OVHEndpoint)
|
||||||
|
app.Flag("ovh-api-rate-limit", "When using the OVH provider, specify the API request rate limit, X operations by seconds (default: 20)").Default(strconv.Itoa(defaultConfig.OVHApiRateLimit)).IntVar(&cfg.OVHApiRateLimit)
|
||||||
app.Flag("pdns-server", "When using the PowerDNS/PDNS provider, specify the URL to the pdns server (required when --provider=pdns)").Default(defaultConfig.PDNSServer).StringVar(&cfg.PDNSServer)
|
app.Flag("pdns-server", "When using the PowerDNS/PDNS provider, specify the URL to the pdns server (required when --provider=pdns)").Default(defaultConfig.PDNSServer).StringVar(&cfg.PDNSServer)
|
||||||
app.Flag("pdns-api-key", "When using the PowerDNS/PDNS provider, specify the API key to use to authorize requests (required when --provider=pdns)").Default(defaultConfig.PDNSAPIKey).StringVar(&cfg.PDNSAPIKey)
|
app.Flag("pdns-api-key", "When using the PowerDNS/PDNS provider, specify the API key to use to authorize requests (required when --provider=pdns)").Default(defaultConfig.PDNSAPIKey).StringVar(&cfg.PDNSAPIKey)
|
||||||
app.Flag("pdns-tls-enabled", "When using the PowerDNS/PDNS provider, specify whether to use TLS (default: false, requires --tls-ca, optionally specify --tls-client-cert and --tls-client-cert-key)").Default(strconv.FormatBool(defaultConfig.PDNSTLSEnabled)).BoolVar(&cfg.PDNSTLSEnabled)
|
app.Flag("pdns-tls-enabled", "When using the PowerDNS/PDNS provider, specify whether to use TLS (default: false, requires --tls-ca, optionally specify --tls-client-cert and --tls-client-cert-key)").Default(strconv.FormatBool(defaultConfig.PDNSTLSEnabled)).BoolVar(&cfg.PDNSTLSEnabled)
|
||||||
|
@ -75,6 +75,7 @@ var (
|
|||||||
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
||||||
InMemoryZones: []string{""},
|
InMemoryZones: []string{""},
|
||||||
OVHEndpoint: "ovh-eu",
|
OVHEndpoint: "ovh-eu",
|
||||||
|
OVHApiRateLimit: 20,
|
||||||
PDNSServer: "http://localhost:8081",
|
PDNSServer: "http://localhost:8081",
|
||||||
PDNSAPIKey: "",
|
PDNSAPIKey: "",
|
||||||
Policy: "sync",
|
Policy: "sync",
|
||||||
@ -149,6 +150,7 @@ var (
|
|||||||
OCIConfigFile: "oci.yaml",
|
OCIConfigFile: "oci.yaml",
|
||||||
InMemoryZones: []string{"example.org", "company.com"},
|
InMemoryZones: []string{"example.org", "company.com"},
|
||||||
OVHEndpoint: "ovh-ca",
|
OVHEndpoint: "ovh-ca",
|
||||||
|
OVHApiRateLimit: 42,
|
||||||
PDNSServer: "http://ns.example.com:8081",
|
PDNSServer: "http://ns.example.com:8081",
|
||||||
PDNSAPIKey: "some-secret-key",
|
PDNSAPIKey: "some-secret-key",
|
||||||
PDNSTLSEnabled: true,
|
PDNSTLSEnabled: true,
|
||||||
@ -237,6 +239,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
"--inmemory-zone=example.org",
|
"--inmemory-zone=example.org",
|
||||||
"--inmemory-zone=company.com",
|
"--inmemory-zone=company.com",
|
||||||
"--ovh-endpoint=ovh-ca",
|
"--ovh-endpoint=ovh-ca",
|
||||||
|
"--ovh-api-rate-limit=42",
|
||||||
"--pdns-server=http://ns.example.com:8081",
|
"--pdns-server=http://ns.example.com:8081",
|
||||||
"--pdns-api-key=some-secret-key",
|
"--pdns-api-key=some-secret-key",
|
||||||
"--pdns-tls-enabled",
|
"--pdns-tls-enabled",
|
||||||
@ -326,6 +329,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
"EXTERNAL_DNS_OCI_CONFIG_FILE": "oci.yaml",
|
"EXTERNAL_DNS_OCI_CONFIG_FILE": "oci.yaml",
|
||||||
"EXTERNAL_DNS_INMEMORY_ZONE": "example.org\ncompany.com",
|
"EXTERNAL_DNS_INMEMORY_ZONE": "example.org\ncompany.com",
|
||||||
"EXTERNAL_DNS_OVH_ENDPOINT": "ovh-ca",
|
"EXTERNAL_DNS_OVH_ENDPOINT": "ovh-ca",
|
||||||
|
"EXTERNAL_DNS_OVH_API_RATE_LIMIT": "42",
|
||||||
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com",
|
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com",
|
||||||
"EXTERNAL_DNS_EXCLUDE_DOMAINS": "xapi.example.org\nxapi.company.com",
|
"EXTERNAL_DNS_EXCLUDE_DOMAINS": "xapi.example.org\nxapi.company.com",
|
||||||
"EXTERNAL_DNS_PDNS_SERVER": "http://ns.example.com:8081",
|
"EXTERNAL_DNS_PDNS_SERVER": "http://ns.example.com:8081",
|
||||||
|
@ -29,6 +29,8 @@ import (
|
|||||||
"sigs.k8s.io/external-dns/endpoint"
|
"sigs.k8s.io/external-dns/endpoint"
|
||||||
"sigs.k8s.io/external-dns/plan"
|
"sigs.k8s.io/external-dns/plan"
|
||||||
"sigs.k8s.io/external-dns/provider"
|
"sigs.k8s.io/external-dns/provider"
|
||||||
|
|
||||||
|
"go.uber.org/ratelimit"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -50,6 +52,8 @@ type OVHProvider struct {
|
|||||||
|
|
||||||
client ovhClient
|
client ovhClient
|
||||||
|
|
||||||
|
apiRateLimiter ratelimit.Limiter
|
||||||
|
|
||||||
domainFilter endpoint.DomainFilter
|
domainFilter endpoint.DomainFilter
|
||||||
DryRun bool
|
DryRun bool
|
||||||
}
|
}
|
||||||
@ -79,7 +83,7 @@ type ovhChange struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewOVHProvider initializes a new OVH DNS based Provider.
|
// NewOVHProvider initializes a new OVH DNS based Provider.
|
||||||
func NewOVHProvider(ctx context.Context, domainFilter endpoint.DomainFilter, endpoint string, dryRun bool) (*OVHProvider, error) {
|
func NewOVHProvider(ctx context.Context, domainFilter endpoint.DomainFilter, endpoint string, apiRateLimit int, dryRun bool) (*OVHProvider, error) {
|
||||||
client, err := ovh.NewEndpointClient(endpoint)
|
client, err := ovh.NewEndpointClient(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -91,6 +95,7 @@ func NewOVHProvider(ctx context.Context, domainFilter endpoint.DomainFilter, end
|
|||||||
return &OVHProvider{
|
return &OVHProvider{
|
||||||
client: client,
|
client: client,
|
||||||
domainFilter: domainFilter,
|
domainFilter: domainFilter,
|
||||||
|
apiRateLimiter: ratelimit.New(apiRateLimit),
|
||||||
DryRun: dryRun,
|
DryRun: dryRun,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -149,10 +154,14 @@ func (p *OVHProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) e
|
|||||||
|
|
||||||
func (p *OVHProvider) refresh(zone string) error {
|
func (p *OVHProvider) refresh(zone string) error {
|
||||||
log.Debugf("OVH: Refresh %s zone", zone)
|
log.Debugf("OVH: Refresh %s zone", zone)
|
||||||
|
|
||||||
|
p.apiRateLimiter.Take()
|
||||||
return p.client.Post(fmt.Sprintf("/domain/zone/%s/refresh", zone), nil, nil)
|
return p.client.Post(fmt.Sprintf("/domain/zone/%s/refresh", zone), nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *OVHProvider) change(change ovhChange) error {
|
func (p *OVHProvider) change(change ovhChange) error {
|
||||||
|
p.apiRateLimiter.Take()
|
||||||
|
|
||||||
switch change.Action {
|
switch change.Action {
|
||||||
case ovhCreate:
|
case ovhCreate:
|
||||||
log.Debugf("OVH: Add an entry to %s", change.String())
|
log.Debugf("OVH: Add an entry to %s", change.String())
|
||||||
@ -194,6 +203,7 @@ func (p *OVHProvider) zones() ([]string, error) {
|
|||||||
zones := []string{}
|
zones := []string{}
|
||||||
filteredZones := []string{}
|
filteredZones := []string{}
|
||||||
|
|
||||||
|
p.apiRateLimiter.Take()
|
||||||
if err := p.client.Get("/domain/zone", &zones); err != nil {
|
if err := p.client.Get("/domain/zone", &zones); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -213,6 +223,8 @@ func (p *OVHProvider) records(ctx *context.Context, zone *string, records chan<-
|
|||||||
eg, _ := errgroup.WithContext(*ctx)
|
eg, _ := errgroup.WithContext(*ctx)
|
||||||
|
|
||||||
log.Debugf("OVH: Getting records for %s", *zone)
|
log.Debugf("OVH: Getting records for %s", *zone)
|
||||||
|
|
||||||
|
p.apiRateLimiter.Take()
|
||||||
if err := p.client.Get(fmt.Sprintf("/domain/zone/%s/record", *zone), &recordsIds); err != nil {
|
if err := p.client.Get(fmt.Sprintf("/domain/zone/%s/record", *zone), &recordsIds); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -236,6 +248,8 @@ func (p *OVHProvider) record(zone *string, id uint64, records chan<- ovhRecord)
|
|||||||
record := ovhRecord{}
|
record := ovhRecord{}
|
||||||
|
|
||||||
log.Debugf("OVH: Getting record %d for %s", id, *zone)
|
log.Debugf("OVH: Getting record %d for %s", id, *zone)
|
||||||
|
|
||||||
|
p.apiRateLimiter.Take()
|
||||||
if err := p.client.Get(fmt.Sprintf("/domain/zone/%s/record/%d", *zone, id), &record); err != nil {
|
if err := p.client.Get(fmt.Sprintf("/domain/zone/%s/record/%d", *zone, id), &record); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/ovh/go-ovh/ovh"
|
"github.com/ovh/go-ovh/ovh"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
|
"go.uber.org/ratelimit"
|
||||||
"sigs.k8s.io/external-dns/endpoint"
|
"sigs.k8s.io/external-dns/endpoint"
|
||||||
"sigs.k8s.io/external-dns/plan"
|
"sigs.k8s.io/external-dns/plan"
|
||||||
)
|
)
|
||||||
@ -59,6 +60,7 @@ func TestOvhZones(t *testing.T) {
|
|||||||
client := new(mockOvhClient)
|
client := new(mockOvhClient)
|
||||||
provider := &OVHProvider{
|
provider := &OVHProvider{
|
||||||
client: client,
|
client: client,
|
||||||
|
apiRateLimiter: ratelimit.New(10),
|
||||||
domainFilter: endpoint.NewDomainFilter([]string{"com"}),
|
domainFilter: endpoint.NewDomainFilter([]string{"com"}),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +83,7 @@ func TestOvhZones(t *testing.T) {
|
|||||||
func TestOvhZoneRecords(t *testing.T) {
|
func TestOvhZoneRecords(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
client := new(mockOvhClient)
|
client := new(mockOvhClient)
|
||||||
provider := &OVHProvider{client: client}
|
provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10)}
|
||||||
|
|
||||||
// Basic zones records
|
// Basic zones records
|
||||||
client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once()
|
client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once()
|
||||||
@ -125,7 +127,7 @@ func TestOvhZoneRecords(t *testing.T) {
|
|||||||
func TestOvhRecords(t *testing.T) {
|
func TestOvhRecords(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
client := new(mockOvhClient)
|
client := new(mockOvhClient)
|
||||||
provider := &OVHProvider{client: client}
|
provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10)}
|
||||||
|
|
||||||
// Basic zones records
|
// Basic zones records
|
||||||
client.On("Get", "/domain/zone").Return([]string{"example.org", "example.net"}, nil).Once()
|
client.On("Get", "/domain/zone").Return([]string{"example.org", "example.net"}, nil).Once()
|
||||||
@ -158,7 +160,7 @@ func TestOvhRecords(t *testing.T) {
|
|||||||
|
|
||||||
func TestOvhRefresh(t *testing.T) {
|
func TestOvhRefresh(t *testing.T) {
|
||||||
client := new(mockOvhClient)
|
client := new(mockOvhClient)
|
||||||
provider := &OVHProvider{client: client}
|
provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10)}
|
||||||
|
|
||||||
// Basic zone refresh
|
// Basic zone refresh
|
||||||
client.On("Post", "/domain/zone/example.net/refresh", nil).Return(nil, nil).Once()
|
client.On("Post", "/domain/zone/example.net/refresh", nil).Return(nil, nil).Once()
|
||||||
@ -199,7 +201,7 @@ func TestOvhNewChange(t *testing.T) {
|
|||||||
func TestOvhApplyChanges(t *testing.T) {
|
func TestOvhApplyChanges(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
client := new(mockOvhClient)
|
client := new(mockOvhClient)
|
||||||
provider := &OVHProvider{client: client}
|
provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10)}
|
||||||
changes := plan.Changes{
|
changes := plan.Changes{
|
||||||
Create: []*endpoint.Endpoint{
|
Create: []*endpoint.Endpoint{
|
||||||
{DNSName: ".example.net", RecordType: "A", RecordTTL: 10, Targets: []string{"203.0.113.42"}},
|
{DNSName: ".example.net", RecordType: "A", RecordTTL: 10, Targets: []string{"203.0.113.42"}},
|
||||||
@ -252,7 +254,7 @@ func TestOvhApplyChanges(t *testing.T) {
|
|||||||
func TestOvhChange(t *testing.T) {
|
func TestOvhChange(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
client := new(mockOvhClient)
|
client := new(mockOvhClient)
|
||||||
provider := &OVHProvider{client: client}
|
provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10)}
|
||||||
|
|
||||||
// Record creation
|
// Record creation
|
||||||
client.On("Post", "/domain/zone/example.net/record", ovhRecordFields{SubDomain: "ovh"}).Return(nil, nil).Once()
|
client.On("Post", "/domain/zone/example.net/record", ovhRecordFields{SubDomain: "ovh"}).Return(nil, nil).Once()
|
||||||
|
Loading…
Reference in New Issue
Block a user