Skip to content

Commit 1742e6d

Browse files
authored
chore: replace official Civo API client by an internal API client (#2584)
1 parent a8e19ef commit 1742e6d

File tree

13 files changed

+548
-17
lines changed

13 files changed

+548
-17
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ require (
2929
github.com/aziontech/azionapi-go-sdk v0.142.0
3030
github.com/baidubce/bce-sdk-go v0.9.223
3131
github.com/cenkalti/backoff/v4 v4.3.0
32-
github.com/civo/civogo v0.3.11
3332
github.com/dnsimple/dnsimple-go/v4 v4.0.0
3433
github.com/exoscale/egoscale/v3 v3.1.13
3534
github.com/go-jose/go-jose/v4 v4.0.5

go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
243243
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
244244
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
245245
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
246-
github.com/civo/civogo v0.3.11 h1:mON/fyrV946Sbk6paRtOSGsN+asCgCmHCgArf5xmGxM=
247-
github.com/civo/civogo v0.3.11/go.mod h1:7+GeeFwc4AYTULaEshpT2vIcl3Qq8HPoxA17viX3l6g=
248246
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
249247
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
250248
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
@@ -724,7 +722,6 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
724722
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
725723
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
726724
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
727-
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
728725
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
729726
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
730727
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
@@ -1107,7 +1104,6 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx
11071104
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
11081105
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
11091106
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
1110-
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
11111107
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
11121108
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
11131109
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=

providers/dns/civo/civo.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
package civo
33

44
import (
5+
"context"
56
"errors"
67
"fmt"
8+
"net/http"
79
"time"
810

9-
"github.com/civo/civogo"
1011
"github.com/go-acme/lego/v4/challenge"
1112
"github.com/go-acme/lego/v4/challenge/dns01"
1213
"github.com/go-acme/lego/v4/platform/config/env"
14+
"github.com/go-acme/lego/v4/providers/dns/civo/internal"
1315
)
1416

1517
// Environment variables names.
@@ -21,6 +23,7 @@ const (
2123
EnvTTL = envNamespace + "TTL"
2224
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
2325
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
26+
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
2427
)
2528

2629
const (
@@ -33,11 +36,12 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
3336

3437
// Config is used to configure the creation of the DNSProvider.
3538
type Config struct {
36-
ProjectID string
37-
Token string
39+
Token string
40+
3841
PropagationTimeout time.Duration
3942
PollingInterval time.Duration
4043
TTL int
44+
HTTPClient *http.Client
4145
}
4246

4347
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -46,13 +50,16 @@ func NewDefaultConfig() *Config {
4650
TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
4751
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, defaultPropagationTimeout),
4852
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, defaultPollingInterval),
53+
HTTPClient: &http.Client{
54+
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
55+
},
4956
}
5057
}
5158

5259
// DNSProvider implements the challenge.Provider interface.
5360
type DNSProvider struct {
5461
config *Config
55-
client *civogo.Client
62+
client *internal.Client
5663
}
5764

5865
// NewDNSProvider returns a DNSProvider instance configured for CIVO.
@@ -84,7 +91,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
8491
}
8592

8693
// Create a Civo client - DNS is region independent, we can use any region
87-
client, err := civogo.NewClient(config.Token, "LON1")
94+
client, err := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.Token), "LON1")
8895
if err != nil {
8996
return nil, fmt.Errorf("civo: %w", err)
9097
}
@@ -96,14 +103,16 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
96103
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
97104
info := dns01.GetChallengeInfo(domain, keyAuth)
98105

106+
ctx := context.Background()
107+
99108
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
100109
if err != nil {
101110
return fmt.Errorf("civo: could not find zone for domain %q: %w", domain, err)
102111
}
103112

104113
zone := dns01.UnFqdn(authZone)
105114

106-
dnsDomain, err := d.client.GetDNSDomain(zone)
115+
domainID, err := d.getDomainIDByName(ctx, zone)
107116
if err != nil {
108117
return fmt.Errorf("civo: %w", err)
109118
}
@@ -113,10 +122,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
113122
return fmt.Errorf("civo: %w", err)
114123
}
115124

116-
_, err = d.client.CreateDNSRecord(dnsDomain.ID, &civogo.DNSRecordConfig{
125+
_, err = d.client.CreateDNSRecord(ctx, domainID, internal.Record{
117126
Name: subDomain,
118127
Value: info.Value,
119-
Type: civogo.DNSRecordTypeTXT,
128+
Type: "TXT",
120129
TTL: d.config.TTL,
121130
})
122131
if err != nil {
@@ -130,19 +139,21 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
130139
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
131140
info := dns01.GetChallengeInfo(domain, keyAuth)
132141

142+
ctx := context.Background()
143+
133144
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
134145
if err != nil {
135146
return fmt.Errorf("civo: could not find zone for domain %q: %w", domain, err)
136147
}
137148

138149
zone := dns01.UnFqdn(authZone)
139150

140-
dnsDomain, err := d.client.GetDNSDomain(zone)
151+
domainID, err := d.getDomainIDByName(ctx, zone)
141152
if err != nil {
142153
return fmt.Errorf("civo: %w", err)
143154
}
144155

145-
dnsRecords, err := d.client.ListDNSRecords(dnsDomain.ID)
156+
dnsRecords, err := d.client.ListDNSRecords(ctx, domainID)
146157
if err != nil {
147158
return fmt.Errorf("civo: %w", err)
148159
}
@@ -152,15 +163,15 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
152163
return fmt.Errorf("civo: %w", err)
153164
}
154165

155-
var dnsRecord civogo.DNSRecord
166+
var dnsRecord internal.Record
156167
for _, entry := range dnsRecords {
157168
if entry.Name == subDomain && entry.Value == info.Value {
158169
dnsRecord = entry
159170
break
160171
}
161172
}
162173

163-
_, err = d.client.DeleteDNSRecord(&dnsRecord)
174+
err = d.client.DeleteDNSRecord(ctx, dnsRecord)
164175
if err != nil {
165176
return fmt.Errorf("civo: %w", err)
166177
}
@@ -173,3 +184,18 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
173184
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
174185
return d.config.PropagationTimeout, d.config.PollingInterval
175186
}
187+
188+
func (d *DNSProvider) getDomainIDByName(ctx context.Context, domain string) (string, error) {
189+
domains, err := d.client.ListDomains(ctx)
190+
if err != nil {
191+
return "", fmt.Errorf("list domains: %w", err)
192+
}
193+
194+
for _, d := range domains {
195+
if d.Name == domain {
196+
return d.ID, nil
197+
}
198+
}
199+
200+
return "", fmt.Errorf("domain %q not found", domain)
201+
}

providers/dns/civo/civo_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ package civo
22

33
import (
44
"fmt"
5+
"net/http/httptest"
6+
"net/url"
7+
"path/filepath"
58
"testing"
69
"time"
710

811
"github.com/go-acme/lego/v4/platform/tester"
12+
"github.com/go-acme/lego/v4/platform/tester/servermock"
913
"github.com/stretchr/testify/assert"
1014
"github.com/stretchr/testify/require"
1115
)
@@ -124,3 +128,70 @@ func TestLiveCleanUp(t *testing.T) {
124128
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
125129
require.NoError(t, err)
126130
}
131+
132+
func mockBuilder() *servermock.Builder[*DNSProvider] {
133+
return servermock.NewBuilder(
134+
func(server *httptest.Server) (*DNSProvider, error) {
135+
config := NewDefaultConfig()
136+
config.Token = "secret"
137+
138+
p, err := NewDNSProviderConfig(config)
139+
if err != nil {
140+
return nil, err
141+
}
142+
143+
p.client.BaseURL, _ = url.Parse(server.URL)
144+
145+
return p, nil
146+
},
147+
servermock.CheckHeader().
148+
WithJSONHeaders().
149+
With("Authorization", "Bearer secret").
150+
WithRegexp("User-Agent", `goacme-lego/[0-9.]+ \(.+\)`),
151+
)
152+
}
153+
154+
func TestDNSProvider_Present(t *testing.T) {
155+
provider := mockBuilder().
156+
// https://www.civo.com/api/dns#list-domain-names
157+
Route("GET /dns",
158+
responseFromFixture("list_domain_names.json"),
159+
servermock.CheckQueryParameter().Strict().
160+
With("region", "LON1")).
161+
// https://www.civo.com/api/dns#create-a-new-dns-record
162+
Route("POST /dns/7088fcea-7658-43e6-97fa-273f901978fd/records",
163+
responseFromFixture("create_dns_record.json"),
164+
servermock.CheckRequestJSONBodyFromFile("create_dns_record-request.json").
165+
WithDirectory(filepath.Join("internal", "fixtures"))).
166+
Build(t)
167+
168+
err := provider.Present("example.com", "abd", "123d==")
169+
require.NoError(t, err)
170+
}
171+
172+
func TestDNSProvider_CleanUp(t *testing.T) {
173+
provider := mockBuilder().
174+
// https://www.civo.com/api/dns#list-domain-names
175+
Route("GET /dns",
176+
responseFromFixture("list_domain_names.json"),
177+
servermock.CheckQueryParameter().
178+
With("region", "LON1")).
179+
// https://www.civo.com/api/dns#list-dns-records
180+
Route("GET /dns/7088fcea-7658-43e6-97fa-273f901978fd/records",
181+
responseFromFixture("list_dns_records.json"),
182+
servermock.CheckQueryParameter().Strict().
183+
With("region", "LON1")).
184+
// https://www.civo.com/api/dns#deleting-a-dns-record
185+
Route("DELETE /dns/edc5dacf-a2ad-4757-41ee-c12f06259c70/records/76cc107f-fbef-4e2b-b97f-f5d34f4075d3",
186+
responseFromFixture("delete_dns_record.json"),
187+
servermock.CheckQueryParameter().Strict().
188+
With("region", "LON1")).
189+
Build(t)
190+
191+
err := provider.CleanUp("example.com", "abd", "123d==")
192+
require.NoError(t, err)
193+
}
194+
195+
func responseFromFixture(filename string) *servermock.ResponseFromFileHandler {
196+
return servermock.ResponseFromFile(filepath.Join("internal", "fixtures", filename))
197+
}

0 commit comments

Comments
 (0)