From 6bd3eae58f418523cf0f0f26db249f3d752c1ec0 Mon Sep 17 00:00:00 2001 From: Van Hau TRAN Date: Wed, 28 Apr 2021 16:49:05 +0200 Subject: [PATCH] scaleway: use official SDK (#1393) --- cmd/zz_gen_cmd_dnshelp.go | 4 +- docs/content/dns/zz_gen_scaleway.md | 6 +- go.mod | 1 + go.sum | 3 + providers/dns/scaleway/internal/client.go | 228 ------------------ .../dns/scaleway/internal/client_test.go | 176 -------------- providers/dns/scaleway/scaleway.go | 88 ++++--- providers/dns/scaleway/scaleway.toml | 6 +- providers/dns/scaleway/scaleway_test.go | 21 +- 9 files changed, 72 insertions(+), 461 deletions(-) delete mode 100644 providers/dns/scaleway/internal/client.go delete mode 100644 providers/dns/scaleway/internal/client_test.go diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go index 56646d214a..22199b0a3b 100644 --- a/cmd/zz_gen_cmd_dnshelp.go +++ b/cmd/zz_gen_cmd_dnshelp.go @@ -1627,12 +1627,10 @@ func displayDNSHelp(name string) error { ew.writeln(`Credentials:`) ew.writeln(` - "SCALEWAY_API_TOKEN": API token`) + ew.writeln(` - "SCALEWAY_PROJECT_ID": Project to use (optional)`) ew.writeln() ew.writeln(`Additional Configuration:`) - ew.writeln(` - "SCALEWAY_API_VERSION": API version`) - ew.writeln(` - "SCALEWAY_BASE_URL": API endpoint URL`) - ew.writeln(` - "SCALEWAY_HTTP_TIMEOUT": API request timeout`) ew.writeln(` - "SCALEWAY_POLLING_INTERVAL": Time between DNS propagation check`) ew.writeln(` - "SCALEWAY_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`) ew.writeln(` - "SCALEWAY_TTL": The TTL of the TXT record used for the DNS challenge`) diff --git a/docs/content/dns/zz_gen_scaleway.md b/docs/content/dns/zz_gen_scaleway.md index 737bd54809..f4b8d7bba3 100644 --- a/docs/content/dns/zz_gen_scaleway.md +++ b/docs/content/dns/zz_gen_scaleway.md @@ -33,6 +33,7 @@ lego --email myemail@example.com --dns scaleway --domains my.example.org run | Environment Variable Name | Description | |-----------------------|-------------| | `SCALEWAY_API_TOKEN` | API token | +| `SCALEWAY_PROJECT_ID` | Project to use (optional) | The environment variable names can be suffixed by `_FILE` to reference a file instead of a value. More information [here](/lego/dns/#configuration-and-credentials). @@ -42,9 +43,6 @@ More information [here](/lego/dns/#configuration-and-credentials). | Environment Variable Name | Description | |--------------------------------|-------------| -| `SCALEWAY_API_VERSION` | API version | -| `SCALEWAY_BASE_URL` | API endpoint URL | -| `SCALEWAY_HTTP_TIMEOUT` | API request timeout | | `SCALEWAY_POLLING_INTERVAL` | Time between DNS propagation check | | `SCALEWAY_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation | | `SCALEWAY_TTL` | The TTL of the TXT record used for the DNS challenge | @@ -57,7 +55,7 @@ More information [here](/lego/dns/#configuration-and-credentials). ## More information -- [API documentation](https://developers.scaleway.com/en/products/domain/api/) +- [API documentation](https://developers.scaleway.com/en/products/domain/dns/api/) diff --git a/go.mod b/go.mod index e777d97619..83b8d52f5f 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/pquerna/otp v1.3.0 github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2 github.com/sacloud/libsacloud v1.36.2 + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f github.com/stretchr/testify v1.7.0 github.com/transip/gotransip/v6 v6.2.0 github.com/urfave/cli v1.22.4 diff --git a/go.sum b/go.sum index 37d6f9486b..dbd3b14665 100644 --- a/go.sum +++ b/go.sum @@ -110,6 +110,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnsimple/dnsimple-go v0.63.0 h1:0doY8VW/ckRIMTmOw4E1vwqo+bhtjDzvh1pU2ZteFGA= github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -399,6 +400,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sacloud/libsacloud v1.36.2 h1:aosI7clbQ9IU0Hj+3rpk3SKJop5nLPpLThnWCivPqjI= github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f h1:WSnaD0/cvbKJgSTYbjAPf4RJXVvNNDAwVm+W8wEmnGE= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= diff --git a/providers/dns/scaleway/internal/client.go b/providers/dns/scaleway/internal/client.go deleted file mode 100644 index 643f82dbb2..0000000000 --- a/providers/dns/scaleway/internal/client.go +++ /dev/null @@ -1,228 +0,0 @@ -package internal - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" -) - -const ( - defaultEndpoint = "https://api.scaleway.com/domain/v2alpha2" - uriUpdateRecords = "/dns-zones/%s/records" - operationSet = "set" - operationDelete = "delete" - operationAdd = "add" -) - -// APIError represents an error response from the API. -type APIError struct { - Message string `json:"message"` -} - -func (a APIError) Error() string { - return a.Message -} - -// Record represents a DNS record. -type Record struct { - Data string `json:"data,omitempty"` - Name string `json:"name,omitempty"` - Priority uint32 `json:"priority,omitempty"` - TTL uint32 `json:"ttl,omitempty"` - Type string `json:"type,omitempty"` - Comment string `json:"comment,omitempty"` -} - -// RecordChangeAdd represents a list of add operations. -type RecordChangeAdd struct { - Records []*Record `json:"records,omitempty"` -} - -// RecordChangeSet represents a list of set operations. -type RecordChangeSet struct { - Data string `json:"data,omitempty"` - Name string `json:"name,omitempty"` - TTL uint32 `json:"ttl,omitempty"` - Type string `json:"type,omitempty"` - Records []*Record `json:"records,omitempty"` -} - -// RecordChangeDelete represents a list of delete operations. -type RecordChangeDelete struct { - Data string `json:"data,omitempty"` - Name string `json:"name,omitempty"` - Type string `json:"type,omitempty"` -} - -// UpdateDNSZoneRecordsRequest represents a request to update DNS records on the API. -type UpdateDNSZoneRecordsRequest struct { - DNSZone string `json:"dns_zone,omitempty"` - Changes []interface{} `json:"changes,omitempty"` - ReturnAllRecords bool `json:"return_all_records,omitempty"` -} - -// ClientOpts represents options to init client. -type ClientOpts struct { - BaseURL string - Token string -} - -// Client represents DNS client. -type Client struct { - baseURL string - token string - httpClient *http.Client -} - -// NewClient returns a client instance. -func NewClient(opts ClientOpts, httpClient *http.Client) *Client { - baseURL := defaultEndpoint - if opts.BaseURL != "" { - baseURL = opts.BaseURL - } - - if httpClient == nil { - httpClient = &http.Client{} - } - - return &Client{ - token: opts.Token, - baseURL: baseURL, - httpClient: httpClient, - } -} - -// AddRecord adds Record for given zone. -func (c *Client) AddRecord(zone string, record Record) error { - changes := map[string]RecordChangeAdd{ - operationAdd: { - Records: []*Record{&record}, - }, - } - - request := UpdateDNSZoneRecordsRequest{ - DNSZone: zone, - Changes: []interface{}{changes}, - ReturnAllRecords: false, - } - - uri := fmt.Sprintf(uriUpdateRecords, zone) - req, err := c.newRequest(http.MethodPatch, uri, request) - if err != nil { - return err - } - - return c.do(req) -} - -// SetRecord sets a unique Record for given zone. -func (c *Client) SetRecord(zone string, record Record) error { - changes := map[string]RecordChangeSet{ - operationSet: { - Name: record.Name, - Type: record.Type, - Records: []*Record{&record}, - }, - } - - request := UpdateDNSZoneRecordsRequest{ - DNSZone: zone, - Changes: []interface{}{changes}, - ReturnAllRecords: false, - } - - uri := fmt.Sprintf(uriUpdateRecords, zone) - req, err := c.newRequest(http.MethodPatch, uri, request) - if err != nil { - return err - } - - return c.do(req) -} - -// DeleteRecord deletes a Record for given zone. -func (c *Client) DeleteRecord(zone string, record Record) error { - delRecord := map[string]RecordChangeDelete{ - operationDelete: { - Name: record.Name, - Type: record.Type, - Data: record.Data, - }, - } - - request := UpdateDNSZoneRecordsRequest{ - DNSZone: zone, - Changes: []interface{}{delRecord}, - ReturnAllRecords: false, - } - - uri := fmt.Sprintf(uriUpdateRecords, zone) - req, err := c.newRequest(http.MethodPatch, uri, request) - if err != nil { - return err - } - - return c.do(req) -} - -func (c *Client) newRequest(method, uri string, body interface{}) (*http.Request, error) { - buf := new(bytes.Buffer) - - if body != nil { - err := json.NewEncoder(buf).Encode(body) - if err != nil { - return nil, fmt.Errorf("failed to encode request body with error: %w", err) - } - } - - req, err := http.NewRequest(method, c.baseURL+uri, buf) - if err != nil { - return nil, fmt.Errorf("failed to create new http request with error: %w", err) - } - - req.Header.Set("X-auth-token", c.token) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - - return req, nil -} - -func (c *Client) do(req *http.Request) error { - resp, err := c.httpClient.Do(req) - if err != nil { - return fmt.Errorf("request failed with error: %w", err) - } - - err = checkResponse(resp) - if err != nil { - return err - } - - return checkResponse(resp) -} - -func checkResponse(resp *http.Response) error { - if resp.StatusCode >= http.StatusBadRequest || resp.StatusCode < http.StatusOK { - if resp.Body == nil { - return fmt.Errorf("request failed with status code %d and empty body", resp.StatusCode) - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - defer resp.Body.Close() - - apiError := APIError{} - err = json.Unmarshal(body, &apiError) - if err != nil { - return fmt.Errorf("request failed with status code %d, response body: %s", resp.StatusCode, string(body)) - } - - return fmt.Errorf("request failed with status code %d: %w", resp.StatusCode, apiError) - } - - return nil -} diff --git a/providers/dns/scaleway/internal/client_test.go b/providers/dns/scaleway/internal/client_test.go deleted file mode 100644 index 4d7df48757..0000000000 --- a/providers/dns/scaleway/internal/client_test.go +++ /dev/null @@ -1,176 +0,0 @@ -package internal - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -const fakeToken = "test" - -func setupTest() (*Client, *http.ServeMux, func()) { - mux := http.NewServeMux() - svr := httptest.NewServer(mux) - - opts := ClientOpts{ - BaseURL: svr.URL, - Token: fakeToken, - } - client := NewClient(opts, nil) - - return client, mux, func() { - svr.Close() - } -} - -func TestClient_AddRecord(t *testing.T) { - client, mux, tearDown := setupTest() - defer tearDown() - - mux.HandleFunc("/dns-zones/zone/records", func(rw http.ResponseWriter, req *http.Request) { - if req.Method != http.MethodPatch { - http.Error(rw, fmt.Sprintf("unsupported method: %s", req.Method), http.StatusBadRequest) - return - } - - auth := req.Header.Get("X-Auth-Token") - if auth != fakeToken { - http.Error(rw, fmt.Sprintf("invalid token: %s", auth), http.StatusUnauthorized) - return - } - - raw, err := ioutil.ReadAll(req.Body) - if err != nil { - http.Error(rw, err.Error(), http.StatusBadRequest) - return - } - - expected := `{"dns_zone":"zone","changes":[{"add":{"records":[{"data":"\"value\"","name":"fqdn","ttl":30,"type":"TXT"}]}}]}` - assert.Equal(t, expected+"\n", string(raw)) - }) - - record := Record{ - Type: "TXT", - TTL: 30, - Name: "fqdn", - Data: fmt.Sprintf(`"%s"`, "value"), - } - - err := client.AddRecord("zone", record) - require.NoError(t, err) -} - -func TestClient_AddRecord_error(t *testing.T) { - client, mux, tearDown := setupTest() - defer tearDown() - - mux.HandleFunc("/dns-zones/zone/records", func(rw http.ResponseWriter, req *http.Request) { - if req.Method != http.MethodPatch { - http.Error(rw, fmt.Sprintf("unsupported method: %s", req.Method), http.StatusBadRequest) - return - } - - auth := req.Header.Get("X-Auth-Token") - if auth != fakeToken { - http.Error(rw, fmt.Sprintf("invalid token: %s", auth), http.StatusUnauthorized) - return - } - - rw.WriteHeader(http.StatusNotFound) - err := json.NewEncoder(rw).Encode(APIError{"oops"}) - if err != nil { - http.Error(rw, err.Error(), http.StatusInternalServerError) - return - } - }) - - record := Record{ - Type: "TXT", - TTL: 30, - Name: "fqdn", - Data: fmt.Sprintf(`"%s"`, "value"), - } - - err := client.AddRecord("zone", record) - require.EqualError(t, err, "request failed with status code 404: oops") -} - -func TestClient_SetRecord(t *testing.T) { - client, mux, tearDown := setupTest() - defer tearDown() - - mux.HandleFunc("/dns-zones/zone/records", func(rw http.ResponseWriter, req *http.Request) { - if req.Method != http.MethodPatch { - http.Error(rw, fmt.Sprintf("unsupported method: %s", req.Method), http.StatusBadRequest) - return - } - - auth := req.Header.Get("X-Auth-Token") - if auth != fakeToken { - http.Error(rw, fmt.Sprintf("invalid token: %s", auth), http.StatusUnauthorized) - return - } - - raw, err := ioutil.ReadAll(req.Body) - if err != nil { - http.Error(rw, err.Error(), http.StatusBadRequest) - return - } - - expected := `{"dns_zone":"zone","changes":[{"set":{"name":"fqdn","type":"TXT","records":[{"data":"\"value\"","name":"fqdn","ttl":30,"type":"TXT"}]}}]}` - assert.Equal(t, expected+"\n", string(raw)) - }) - - record := Record{ - Type: "TXT", - TTL: 30, - Name: "fqdn", - Data: fmt.Sprintf(`"%s"`, "value"), - } - - err := client.SetRecord("zone", record) - require.NoError(t, err) -} - -func TestClient_DeleteRecord(t *testing.T) { - client, mux, tearDown := setupTest() - defer tearDown() - - mux.HandleFunc("/dns-zones/zone/records", func(rw http.ResponseWriter, req *http.Request) { - if req.Method != http.MethodPatch { - http.Error(rw, fmt.Sprintf("unsupported method: %s", req.Method), http.StatusBadRequest) - return - } - - auth := req.Header.Get("X-Auth-Token") - if auth != fakeToken { - http.Error(rw, fmt.Sprintf("invalid token: %s", auth), http.StatusUnauthorized) - return - } - - raw, err := ioutil.ReadAll(req.Body) - if err != nil { - http.Error(rw, err.Error(), http.StatusBadRequest) - return - } - - expected := `{"dns_zone":"zone","changes":[{"delete":{"data":"\"value\"","name":"fqdn","type":"TXT"}}]}` - assert.Equal(t, expected+"\n", string(raw)) - }) - - record := Record{ - Type: "TXT", - TTL: 30, - Name: "fqdn", - Data: fmt.Sprintf(`"%s"`, "value"), - } - - err := client.DeleteRecord("zone", record) - require.NoError(t, err) -} diff --git a/providers/dns/scaleway/scaleway.go b/providers/dns/scaleway/scaleway.go index 08ffd7da1c..4c42225de9 100644 --- a/providers/dns/scaleway/scaleway.go +++ b/providers/dns/scaleway/scaleway.go @@ -1,22 +1,19 @@ // Package scaleway implements a DNS provider for solving the DNS-01 challenge using Scaleway Domains API. -// Scaleway Domain API reference: https://developers.scaleway.com/en/products/domain/api/ // Token: https://www.scaleway.com/en/docs/generate-an-api-token/ package scaleway import ( "errors" "fmt" - "net/http" "time" "github.com/go-acme/lego/v4/challenge/dns01" "github.com/go-acme/lego/v4/platform/config/env" - "github.com/go-acme/lego/v4/providers/dns/scaleway/internal" + scwdomain "github.com/scaleway/scaleway-sdk-go/api/domain/v2beta1" + "github.com/scaleway/scaleway-sdk-go/scw" ) const ( - defaultBaseURL = "https://api.scaleway.com" - defaultVersion = "v2alpha2" minTTL = 60 defaultPollingInterval = 10 * time.Second defaultPropagationTimeout = 120 * time.Second @@ -26,49 +23,41 @@ const ( const ( envNamespace = "SCALEWAY_" - EnvBaseURL = envNamespace + "BASE_URL" - EnvAPIToken = envNamespace + "API_TOKEN" - EnvAPIVersion = envNamespace + "API_VERSION" + EnvAPIToken = envNamespace + "API_TOKEN" + EnvProjectID = envNamespace + "PROJECT_ID" EnvTTL = envNamespace + "TTL" EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" EnvPollingInterval = envNamespace + "POLLING_INTERVAL" - EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT" ) // Config is used to configure the creation of the DNSProvider. type Config struct { - BaseURL string - Version string + ProjectID string Token string PropagationTimeout time.Duration PollingInterval time.Duration TTL int - HTTPClient *http.Client } // NewDefaultConfig returns a default configuration for the DNSProvider. func NewDefaultConfig() *Config { return &Config{ - BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL), - Version: env.GetOrDefaultString(EnvAPIVersion, defaultVersion), TTL: env.GetOrDefaultInt(EnvTTL, minTTL), PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, defaultPropagationTimeout), PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, defaultPollingInterval), - HTTPClient: &http.Client{ - Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), - }, } } // DNSProvider implements the challenge.Provider interface. type DNSProvider struct { config *Config - client *internal.Client + client *scwdomain.API } // NewDNSProvider returns a DNSProvider instance configured for Scaleway Domains API. -// API token must be passed in the environment variable SCALEWAY_API_TOKEN. +// Credentials must be passed in the environment variables: +// SCALEWAY_API_TOKEN, SCALEWAY_PROJECT_ID. func NewDNSProvider() (*DNSProvider, error) { values, err := env.Get(EnvAPIToken) if err != nil { @@ -77,6 +66,7 @@ func NewDNSProvider() (*DNSProvider, error) { config := NewDefaultConfig() config.Token = values[EnvAPIToken] + config.ProjectID = env.GetOrFile(EnvProjectID) return NewDNSProviderConfig(config) } @@ -95,12 +85,22 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { config.TTL = minTTL } - client := internal.NewClient(internal.ClientOpts{ - BaseURL: fmt.Sprintf("%s/domain/%s", config.BaseURL, config.Version), - Token: config.Token, - }, config.HTTPClient) + configuration := []scw.ClientOption{ + scw.WithAuth("SCWXXXXXXXXXXXXXXXXX", config.Token), + scw.WithUserAgent("Scaleway Lego's provider"), + } + + if config.ProjectID != "" { + configuration = append(configuration, scw.WithDefaultProjectID(config.ProjectID)) + } + + // Create a Scaleway client + clientScw, err := scw.NewClient(configuration...) + if err != nil { + return nil, fmt.Errorf("scaleway: %w", err) + } - return &DNSProvider{config: config, client: client}, nil + return &DNSProvider{config: config, client: scwdomain.NewAPI(clientScw)}, nil } // Timeout returns the Timeout and interval to use when checking for DNS propagation. @@ -113,17 +113,27 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { func (d *DNSProvider) Present(domain, token, keyAuth string) error { fqdn, value := dns01.GetRecord(domain, keyAuth) - txtRecord := internal.Record{ - Type: "TXT", - TTL: uint32(d.config.TTL), - Name: fqdn, - Data: fmt.Sprintf(`"%s"`, value), + records := []*scwdomain.Record{{ + Data: fmt.Sprintf(`"%s"`, value), + Name: fqdn, + TTL: uint32(d.config.TTL), + Type: scwdomain.RecordTypeTXT, + Comment: scw.StringPtr("used by lego"), + }} + + req := &scwdomain.UpdateDNSZoneRecordsRequest{ + DNSZone: domain, + Changes: []*scwdomain.RecordChange{{ + Add: &scwdomain.RecordChangeAdd{Records: records}, + }}, + ReturnAllRecords: scw.BoolPtr(false), } - err := d.client.AddRecord(domain, txtRecord) + _, err := d.client.UpdateDNSZoneRecords(req) if err != nil { return fmt.Errorf("scaleway: %w", err) } + return nil } @@ -131,16 +141,24 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { fqdn, value := dns01.GetRecord(domain, keyAuth) - txtRecord := internal.Record{ - Type: "TXT", - TTL: uint32(d.config.TTL), + recordIdentifier := &scwdomain.RecordIdentifier{ Name: fqdn, - Data: fmt.Sprintf(`"%s"`, value), + Type: scwdomain.RecordTypeTXT, + Data: scw.StringPtr(fmt.Sprintf(`"%s"`, value)), } - err := d.client.DeleteRecord(domain, txtRecord) + req := &scwdomain.UpdateDNSZoneRecordsRequest{ + DNSZone: domain, + Changes: []*scwdomain.RecordChange{{ + Delete: &scwdomain.RecordChangeDelete{IDFields: recordIdentifier}, + }}, + ReturnAllRecords: scw.BoolPtr(false), + } + + _, err := d.client.UpdateDNSZoneRecords(req) if err != nil { return fmt.Errorf("scaleway: %w", err) } + return nil } diff --git a/providers/dns/scaleway/scaleway.toml b/providers/dns/scaleway/scaleway.toml index 8451889176..e1b109661c 100644 --- a/providers/dns/scaleway/scaleway.toml +++ b/providers/dns/scaleway/scaleway.toml @@ -12,13 +12,11 @@ lego --email myemail@example.com --dns scaleway --domains my.example.org run [Configuration] [Configuration.Credentials] SCALEWAY_API_TOKEN = "API token" + SCALEWAY_PROJECT_ID = "Project to use (optional)" [Configuration.Additional] - SCALEWAY_BASE_URL = "API endpoint URL" - SCALEWAY_API_VERSION = "API version" SCALEWAY_POLLING_INTERVAL = "Time between DNS propagation check" SCALEWAY_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation" SCALEWAY_TTL = "The TTL of the TXT record used for the DNS challenge" - SCALEWAY_HTTP_TIMEOUT = "API request timeout" [Links] - API = "https://developers.scaleway.com/en/products/domain/api/" + API = "https://developers.scaleway.com/en/products/domain/dns/api/" diff --git a/providers/dns/scaleway/scaleway_test.go b/providers/dns/scaleway/scaleway_test.go index 74776f4ba8..7dc8c06e0e 100644 --- a/providers/dns/scaleway/scaleway_test.go +++ b/providers/dns/scaleway/scaleway_test.go @@ -10,11 +10,12 @@ import ( "github.com/stretchr/testify/require" ) -const cleanUpDelay = 2 * time.Second +const envDomain = envNamespace + "DOMAIN" -func TestNewDNSProvider(t *testing.T) { - envTest := tester.NewEnvTest(EnvAPIToken, EnvTTL) +var envTest = tester.NewEnvTest(EnvAPIToken, EnvProjectID). + WithDomain(envDomain) +func TestNewDNSProvider(t *testing.T) { testCases := []struct { desc string envVars map[string]string @@ -23,13 +24,15 @@ func TestNewDNSProvider(t *testing.T) { { desc: "success", envVars: map[string]string{ - EnvAPIToken: "123", + EnvAPIToken: "00000000-0000-0000-0000-000000000000", + EnvProjectID: "", }, }, { desc: "missing api key", envVars: map[string]string{ - EnvAPIToken: "", + EnvAPIToken: "", + EnvProjectID: "", }, expected: fmt.Sprintf("scaleway: some credentials information are missing: %s", EnvAPIToken), }, @@ -65,7 +68,7 @@ func TestNewDNSProviderConfig(t *testing.T) { }{ { desc: "success", - token: "123", + token: "00000000-0000-0000-0000-000000000000", ttl: minTTL, }, { @@ -97,8 +100,6 @@ func TestNewDNSProviderConfig(t *testing.T) { } func TestLivePresent(t *testing.T) { - envTest := tester.NewEnvTest(EnvAPIToken, EnvTTL) - if !envTest.IsLiveTest() { t.Skip("skipping live test") } @@ -112,8 +113,6 @@ func TestLivePresent(t *testing.T) { } func TestLiveCleanUp(t *testing.T) { - envTest := tester.NewEnvTest(EnvAPIToken, EnvTTL) - if !envTest.IsLiveTest() { t.Skip("skipping live test") } @@ -122,7 +121,7 @@ func TestLiveCleanUp(t *testing.T) { provider, err := NewDNSProvider() require.NoError(t, err) - time.Sleep(cleanUpDelay) + time.Sleep(2 * time.Second) err = provider.CleanUp(envTest.GetDomain(), "", "123d==") require.NoError(t, err)