From be1f03fb75a48083b7d4d46db0052e8f9939eeca Mon Sep 17 00:00:00 2001 From: Steven Vernick <78868407+svernick@users.noreply.github.com> Date: Tue, 22 Jun 2021 10:24:49 -0400 Subject: [PATCH] NEW PROVIDER: AkamaiEdgeDNS (#1174) * downcase TLSA * Akamai provider * Akamai provider * EdgeDNS provider * AkamaiEdgeDNS provider * AkamaiEdgeDNS provider * AkamaiEdgeDNS provider Co-authored-by: Tom Limoncelli --- OWNERS | 1 + README.md | 1 + build/generate/featureMatrix.go | 2 + docs/_functions/domain/AKAMAICDN.md | 10 + docs/_includes/matrix.html | 96 ++++++ docs/_providers/akamaiedgedns.md | 76 +++++ docs/provider-list.md | 1 + go.mod | 31 +- go.sum | 102 ++++-- integrationTest/integration_test.go | 5 +- integrationTest/providers.json | 9 + models/domain.go | 2 +- models/record.go | 4 +- models/t_parse.go | 2 +- models/target.go | 2 +- pkg/js/helpers.js | 3 + pkg/js/parse_tests/015-tlsa/foo.com.zone | 2 +- pkg/normalize/validate.go | 3 +- pkg/printer/printer.go | 4 +- providers/_all/all.go | 1 + .../akamaiedgedns/akamaiEdgeDnsProvider.go | 247 ++++++++++++++ .../akamaiedgedns/akamaiEdgeDnsService.go | 305 ++++++++++++++++++ providers/akamaiedgedns/auditrecords.go | 8 + providers/capabilities.go | 3 + 24 files changed, 857 insertions(+), 63 deletions(-) create mode 100644 docs/_functions/domain/AKAMAICDN.md create mode 100644 docs/_providers/akamaiedgedns.md create mode 100644 providers/akamaiedgedns/akamaiEdgeDnsProvider.go create mode 100644 providers/akamaiedgedns/akamaiEdgeDnsService.go create mode 100644 providers/akamaiedgedns/auditrecords.go diff --git a/OWNERS b/OWNERS index d045330d2..f7ca55cb1 100644 --- a/OWNERS +++ b/OWNERS @@ -1,4 +1,5 @@ # providers/activedir +providers/akamaiedgedns @svernick providers/axfrddns @hnrgrgr providers/azuredns @vatsalyagoel providers/bind @tlimoncelli diff --git a/README.md b/README.md index 5adeb02dd..2748917fe 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Currently supported DNS providers: - AWS Route 53 - AXFR+DDNS - Active Directory (Deprecated, see Microsoft DNS) + - Akamai Edge DNS - Azure DNS - BIND - ClouDNS diff --git a/build/generate/featureMatrix.go b/build/generate/featureMatrix.go index 1bfd45806..f25b554a2 100644 --- a/build/generate/featureMatrix.go +++ b/build/generate/featureMatrix.go @@ -42,6 +42,7 @@ func generateFeatureMatrix() error { {"R53_ALIAS", "Provider supports Route 53 limited ALIAS"}, {"AZURE_ALIAS", "Provider supports Azure DNS limited ALIAS"}, {"DS", "Provider supports adding DS records"}, + { "AKAMAICDN", "Provider supports adding AKAMAICDN records"}, {"dual host", "This provider is recommended for use in 'dual hosting' scenarios. Usually this means the provider allows full control over the apex NS records"}, {"create-domains", "This means the provider can automatically create domains that do not currently exist on your account. The 'dnscontrol create-domains' command will initialize any missing domains"}, @@ -88,6 +89,7 @@ func generateFeatureMatrix() error { setCap("SRV", providers.CanUseSRV) setCap("SSHFP", providers.CanUseSSHFP) setCap("TLSA", providers.CanUseTLSA) + setCap("AKAMAICDN", providers.CanUseAKAMAICDN) setCap("get-zones", providers.CanGetZones) setCap("DS", providers.CanUseDS) setDoc("dual host", providers.DocDualHost, false) diff --git a/docs/_functions/domain/AKAMAICDN.md b/docs/_functions/domain/AKAMAICDN.md new file mode 100644 index 000000000..176355d49 --- /dev/null +++ b/docs/_functions/domain/AKAMAICDN.md @@ -0,0 +1,10 @@ +--- +name: AKAMAICDN +parameters: +- name +- target +- modifiers... +--- + +AKAMAICDN is a proprietary record type that is used to configure [Zone Apex Mapping](https://blogs.akamai.com/2019/08/fast-dns-zone-apex-mapping-dnssec.html). +The AKAMAICDN target must be preconfigured in the Akamai network. diff --git a/docs/_includes/matrix.html b/docs/_includes/matrix.html index 79036fe52..6f6e885d1 100644 --- a/docs/_includes/matrix.html +++ b/docs/_includes/matrix.html @@ -7,6 +7,7 @@
ACTIVEDIRECTORY_PS
+
AKAMAIEDGEDNS
AXFRDDNS
AZURE_DNS
BIND
@@ -52,6 +53,9 @@ + + + @@ -172,6 +176,9 @@ + + + @@ -280,6 +287,9 @@ + + + @@ -373,6 +383,9 @@ + + + @@ -455,6 +468,9 @@ AUTODNSSEC + + + @@ -526,6 +542,9 @@ + + + @@ -612,6 +631,9 @@ + + + @@ -698,6 +720,9 @@ + + + @@ -753,6 +778,9 @@ SOA + + + @@ -810,6 +838,9 @@ + + + @@ -894,6 +925,9 @@ + + + @@ -968,6 +1002,9 @@ + + + @@ -1081,6 +1118,7 @@ + R53_ALIAS @@ -1101,6 +1139,7 @@ + @@ -1130,6 +1169,7 @@ AZURE_ALIAS + @@ -1173,6 +1213,9 @@ DS + + + @@ -1230,11 +1273,55 @@ + + AKAMAICDN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + dual host + + + @@ -1327,6 +1414,9 @@ + + + @@ -1438,6 +1528,9 @@ + + + @@ -1543,6 +1636,9 @@ + + + diff --git a/docs/_providers/akamaiedgedns.md b/docs/_providers/akamaiedgedns.md new file mode 100644 index 000000000..fd2b22e32 --- /dev/null +++ b/docs/_providers/akamaiedgedns.md @@ -0,0 +1,76 @@ +--- +name: AkamaiEdgeDns +title: Akamai Edge DNS Provider +layout: default +jsId: AKAMAIEDGEDNS +--- + +# Akamai Edge DNS Provider + +"Akamai Edge DNS Provider" configures Akamai's +[Edge DNS](https://www.akamai.com/us/en/products/security/edge-dns.jsp) service. + +This provider interacts with Edge DNS via the +[Edge DNS Zone Management API](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html). + +Before you can use this provider, you need to create an "API Client" with authorization to use the +[Edge DNS Zone Management API](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html). + +See the "Get Started" section of [Edge DNS Zone Management API](https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html), +which says, "To enable this API, choose the API service named DNS—Zone Record Management, and set the access level to READ-WRITE." + +Follow directions at [Authenticate With EdgeGrid](https://developer.akamai.com/getting-started/edgegrid) to generate +the required credentials. + +## Configuration + +In the credentials file (creds.json), you must provide the following: +{% highlight json %} +"akamaiedgedns": { + "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "host": "akaa-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxx.akamaiapis.net", + "access_token": "akaa-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "client_token": "akaa-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "contract_id": "X-XXXX", + "group_id": "NNNNNN" +} +{% endhighlight %} + +## Usage + +A new zone created by DNSControl: + +``` +dnscontrol create-domains +``` + +automatically creates SOA and authoritative NS records. + +Akamai assigns a unique set of authoritative nameservers for each contract. These authorities should be +used as the NS records on all zones belonging to this contract. + +The NS records for these authorities have a TTL of 86400. + +Add: + +``` +NAMESERVER_TTL(86400) +``` + +modifier to the dnscontrol.js D() function so that DNSControl does not change the TTL of the authoritative NS records. + +Example 'dnsconfig.js': +{% highlight js %} +var REG_NONE = NewRegistrar('none', 'NONE'); +var DNS_AKAMAIEDGEDNS = NewDnsProvider('akamaiedgedns', 'AKAMAIEDGEDNS'); + +D('example.com', REG_NONE, DnsProvider(DNS_AKAMAIEDGEDNS), + NAMESERVER_TTL(86400), + AUTODNSSEC_ON, + AKAMAICDN("@", "www.preconfigured.edgesuite.net", TTL(20)), + A('foo','1.2.3.4') +); +{% endhighlight %} + +AKAMAICDN is a proprietary record type that is used to configure [Zone Apex Mapping](https://blogs.akamai.com/2019/08/fast-dns-zone-apex-mapping-dnssec.html). +The AKAMAICDN target must be preconfigured in the Akamai network. diff --git a/docs/provider-list.md b/docs/provider-list.md index ca4279b4e..d188c36ca 100644 --- a/docs/provider-list.md +++ b/docs/provider-list.md @@ -72,6 +72,7 @@ provided to help community members support their code independently. Maintainers of contributed providers: * `AXFRDDNS` @hnrgrgr +* `AKAMAIEDGEDNS` @svernick * `CLOUDNS` @pragmaton * `CSCGLOBAL` @Air-New-Zealand * `DESEC` @D3luxee diff --git a/go.mod b/go.mod index b3c10bbb7..401a9ec8d 100644 --- a/go.mod +++ b/go.mod @@ -3,36 +3,35 @@ module github.com/StackExchange/dnscontrol/v3 go 1.16 require ( - github.com/Azure/azure-sdk-for-go v55.1.0+incompatible + github.com/Azure/azure-sdk-for-go v55.2.0+incompatible github.com/Azure/go-autorest/autorest v0.11.18 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.5.7 github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 github.com/PuerkitoBio/goquery v1.6.1 github.com/TomOnTime/utfutil v0.0.0-20200626160131-0b0178852c8f + github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 github.com/andybalholm/cascadia v1.2.0 // indirect - github.com/aws/aws-sdk-go v1.38.53 + github.com/aws/aws-sdk-go v1.38.58 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e - github.com/billputer/go-namecheap v0.0.0-20170915210158-0c7adb0710f8 + github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/daaku/go.zipexe v1.0.1 // indirect - github.com/digitalocean/godo v1.61.0 + github.com/digitalocean/godo v1.62.0 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c - github.com/dnsimple/dnsimple-go v0.62.0 - github.com/exoscale/egoscale v0.23.0 + github.com/dnsimple/dnsimple-go v0.70.1 + github.com/exoscale/egoscale v1.19.0 github.com/fatih/color v1.10.0 // indirect github.com/frankban/quicktest v1.11.3 // indirect github.com/go-acme/lego v2.7.2+incompatible github.com/go-gandi/go-gandi v0.0.0-20200921091836-0d8a64b9cc09 github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe github.com/gofrs/uuid v4.0.0+incompatible // indirect - github.com/golang/snappy v0.0.3 // indirect - github.com/google/go-github/v35 v35.2.0 - github.com/google/go-querystring v1.0.1-0.20190318165438-c8c88dbee036 // indirect + github.com/google/go-github/v35 v35.3.0 github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -49,32 +48,30 @@ require ( github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 github.com/nrdcg/goinwx v0.8.1 github.com/oracle/oci-go-sdk/v32 v32.0.0 - github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 + github.com/ovh/go-ovh v1.1.0 github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d github.com/pierrec/lz4 v2.6.0+incompatible // indirect github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.3.0 github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 - github.com/renier/xmlrpc v0.0.0-20191022213033-ce560eccbd00 // indirect github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/smartystreets/assertions v1.0.0 // indirect - github.com/smartystreets/goconvey v1.6.4 // indirect - github.com/softlayer/softlayer-go v0.0.0-20170804160555-5e1c8cccc730 + github.com/softlayer/softlayer-go v1.0.3 github.com/stretchr/objx v0.3.0 // indirect github.com/stretchr/testify v1.7.0 github.com/tdewolff/minify/v2 v2.9.17 github.com/urfave/cli/v2 v2.3.0 - github.com/vultr/govultr v1.0.0 + github.com/vultr/govultr v1.1.1 github.com/xddxdd/ottoext v0.0.0-20210101073831-439879ee6281 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect - golang.org/x/net v0.0.0-20210525063256-abc453219eb5 + golang.org/x/net v0.0.0-20210610132358-84b48f89b13b golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect - google.golang.org/api v0.47.0 + google.golang.org/api v0.48.0 gopkg.in/ini.v1 v1.62.0 // indirect - gopkg.in/ns1/ns1-go.v2 v2.4.4 + gopkg.in/ns1/ns1-go.v2 v2.5.1 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index d1f3c4a11..df6df3fd6 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,9 @@ cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKP cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0 h1:bAMqZidYkmIsUqe6PtkEPT7Q+vfizScn+jfNA6jwK9c= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -37,8 +38,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go v55.1.0+incompatible h1:B+zsJuu6v/LyVPO59e6/7T/JoU6+eLLE574wLJ1NT6A= -github.com/Azure/azure-sdk-for-go v55.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v55.2.0+incompatible h1:TL2/vJWJEPOrmv97nHcbvjXES0Ntlb9P95hqGA1J2dU= +github.com/Azure/azure-sdk-for-go v55.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= @@ -75,6 +76,8 @@ github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFG github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/TomOnTime/utfutil v0.0.0-20200626160131-0b0178852c8f h1:MXp+2PP1RxWWoE3qmOecVblerzKCryXkFXq9er+EDr8= github.com/TomOnTime/utfutil v0.0.0-20200626160131-0b0178852c8f/go.mod h1:FiuynIwe98RFhWI8nZ0dnsldPVsBy9rHH1hn2WYwme4= +github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 h1:bLzehmpyCwQiqCE1Qe9Ny6fbFqs7hPlmo9vKv2orUxs= +github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/kong v0.2.2/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= @@ -85,16 +88,16 @@ github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxB github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.38.53 h1:Qj5OvKPrDGTiCnWj+kwQXAlBO6OaFBH/WaRzJPZPg3w= -github.com/aws/aws-sdk-go v1.38.53/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.58 h1:s4BKYcepKuX73xRTSRI3dQCfAM3zwmKgTLvjG/wtBEM= +github.com/aws/aws-sdk-go v1.38.58/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e h1:KCjb01YiNoRaJ5c+SbnPLWjVzU9vqRYHg3e5JcN50nM= github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e/go.mod h1:f7vw6ObmmNcyFQLhZX9eUGBJGpnwTJFDvVjqZxIxHWY= -github.com/billputer/go-namecheap v0.0.0-20170915210158-0c7adb0710f8 h1:sIv3xbwhhAG94a62Q/rrSBtrWcXiYgldNOeqifyKSgo= -github.com/billputer/go-namecheap v0.0.0-20170915210158-0c7adb0710f8/go.mod h1:bqqNsI2akL+lLWyApkYY0cxquWPKwEBU0Wd3chi3TEg= +github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 h1:2vQTbEJvFsyd1VefzZ34GUkUD6TkJleYYJh9/25WBE4= +github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9/go.mod h1:bqqNsI2akL+lLWyApkYY0cxquWPKwEBU0Wd3chi3TEg= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -121,15 +124,15 @@ github.com/daaku/go.zipexe v1.0.1/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzU github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/digitalocean/godo v1.61.0 h1:PChvUn5+Ajwvl7caOJoFbcM9r+y91ssQbM0W0k3pnZU= -github.com/digitalocean/godo v1.61.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= +github.com/digitalocean/godo v1.62.0 h1:7Gw2KFsWkxl36qJa0s50tgXaE0Cgm51JdRP+MFQvNnM= +github.com/digitalocean/godo v1.62.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE= -github.com/dnsimple/dnsimple-go v0.62.0 h1:Lr4U8F08FBL90rMEtQMR547RebifgwTPGCRC/+6ZW4g= -github.com/dnsimple/dnsimple-go v0.62.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= +github.com/dnsimple/dnsimple-go v0.70.1 h1:cSZndVjttLpgplDuesY4LFIvfKf/zRA1J7mCATBbzSM= +github.com/dnsimple/dnsimple-go v0.70.1/go.mod h1:F9WHww9cC76hrnwGFfAfrqdW99j3MOYasQcIwTS/aUk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -138,8 +141,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/exoscale/egoscale v0.23.0 h1:hoUDzrO8yNoobNdnrRvlRFjfg3Ng0vQTrv6bXRJu6z0= -github.com/exoscale/egoscale v0.23.0/go.mod h1:hRo78jkjkCDKpivQdRBEpNYF5+cVpCJCPDg2/r45KaY= +github.com/exoscale/egoscale v1.19.0 h1:DbSyyzaPyxDBgGOuduCU26rQ4PJb/GP+8srXRabRf5U= +github.com/exoscale/egoscale v1.19.0/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= @@ -213,16 +216,18 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v35 v35.2.0 h1:s/soW8jauhjUC3rh8JI0FePuocj0DEI9DNBg/bVplE8= -github.com/google/go-github/v35 v35.2.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v35 v35.3.0 h1:fU+WBzuukn0VssbayTT+Zo3/ESKX9JYWjbZTLOTEyho= +github.com/google/go-github/v35 v35.3.0/go.mod h1:yWB7uCcVWaUbUP74Aq3whuMySRMatyRmq5U9FTNlbio= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.0.1-0.20190318165438-c8c88dbee036 h1:Avad62mreCc9la5buHvHZXbvsY+GPYUVjd8xsi48FYY= -github.com/google/go-querystring v1.0.1-0.20190318165438-c8c88dbee036/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -234,7 +239,10 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= @@ -287,6 +295,7 @@ github.com/hexonet/go-sdk/v3 v3.5.2 h1:zNY5NjlKdamBHy9NKmX4WSAL9wvKJ+KoWLrrQAbmC github.com/hexonet/go-sdk/v3 v3.5.2/go.mod h1:X/TQ5RQ7MMNsTajP4/lr3/eBkOoz8qUiha2lydNBGZE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -333,6 +342,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b h1:iNjcivnc6lhbvJA3LD622NPrUponluJrBWPIwGG/3Bg= github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -385,9 +396,11 @@ github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oracle/oci-go-sdk/v32 v32.0.0 h1:SSbzrQO3WRcPJEZ8+b3SFPYsPtkFM96clqrp03lrwbU= github.com/oracle/oci-go-sdk/v32 v32.0.0/go.mod h1:aZc4jC59IuNP3cr5y1nj555QvwojMX2nMJaBiozuuEs= -github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c= -github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= +github.com/ovh/go-ovh v1.1.0 h1:bHXZmw8nTgZin4Nv7JuaLs0KG5x54EQR7migYTd1zrk= +github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d h1:nf4+lHs8TQeIGFYZMcNg4iQOnZndLfYxnQaKEdqHVA4= github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d/go.mod h1:VDIGNBy0tHXMDAu4gxHFQJDq3NuwqUxw2Kok7wi+6ck= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -408,8 +421,6 @@ github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7q github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= -github.com/renier/xmlrpc v0.0.0-20191022213033-ce560eccbd00 h1:mKU5SDtoxNCBexJlsba8dNKN8SoDNMibWxVEowW1fig= -github.com/renier/xmlrpc v0.0.0-20191022213033-ce560eccbd00/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -422,15 +433,20 @@ github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIH github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/softlayer/softlayer-go v0.0.0-20170804160555-5e1c8cccc730 h1:NFtcXPhyIM81jGPrxh5OvdRM1esrM2lIYlO0SFm3KOg= -github.com/softlayer/softlayer-go v0.0.0-20170804160555-5e1c8cccc730/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= +github.com/softlayer/softlayer-go v1.0.3 h1:9FONm5xzQ9belQtbdryR6gBg4EF6hX6lrjNKi0IvZkU= +github.com/softlayer/softlayer-go v1.0.3/go.mod h1:6HepcfAXROz0Rf63krk5hPZyHT6qyx2MNvYyHof7ik4= +github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e h1:3OgWYFw7jxCZPcvAg+4R8A50GZ+CCkARF10lxu2qDsQ= +github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e/go.mod h1:fKZCUVdirrxrBpwd9wb+lSoVixvpwAu8eHzbQB2tums= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -449,10 +465,13 @@ github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/vultr/govultr v1.0.0 h1:yeJrYp9wyA4xXaQZ7eOL2u1wKn2JU79HjRevwvpxbJ4= -github.com/vultr/govultr v1.0.0/go.mod h1:wZZXZbYbqyY1n3AldoeYNZK4Wnmmoq6dNFkvd5TV3ss= +github.com/vultr/govultr v1.1.1 h1:ntltxMYyJstjKz1v2CLNxFZiqjlt/8HqD1GZeJ/fAMc= +github.com/vultr/govultr v1.1.1/go.mod h1:QXCNTRg0nwu95ayiMC3feYvrAFTLnj94s2FiibIpoC4= github.com/xddxdd/ottoext v0.0.0-20210101073831-439879ee6281 h1:QruJ/b9zaFRxtNYvekIXlqWh/BoJJrSJg+FdmMNp8cw= github.com/xddxdd/ottoext v0.0.0-20210101073831-439879ee6281/go.mod h1:8Hr+gV9GtucFQOptKfzuYxqg++CyIjg4E7QCR7F3Dxw= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -553,8 +572,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -588,6 +607,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -627,8 +647,9 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644 h1:CA1DEQ4NdKphKeL70tvsWNdT5oFh1lOjihRcEDROi0I= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -680,6 +701,7 @@ golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -694,6 +716,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -720,8 +743,9 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0 h1:sQLWZQvP6jPGIP4JGPkJu4zHswrv81iobiyszr3b/0I= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0 h1:RDAPWfNFY06dffEXfn7hZF5Fr1ZbnChzfQZAPyBd1+I= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -769,8 +793,10 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384 h1:z+j74wi4yV+P7EtK9gPLGukOk7mFOy9wMQaC0wNb7eY= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 h1:pc16UedxnxXXtGxHCSUhafAoVHQZ0yXl8ZelMH4EETc= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -791,8 +817,11 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.1 h1:ARnQJNWxGyYJpdf/JXscNlQr/uv607ZPU9Z7ogHi+iI= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -814,15 +843,18 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v1 v1.0.0-20161222125816-442357a80af5/go.mod h1:u0ALmqvLRxLI95fkdCEWrE6mhWYZW1aMOJHp5YXLHTg= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/h2non/gock.v1 v1.0.14 h1:fTeu9fcUvSnLNacYvYI54h+1/XEteDyHvrVCZEEEYNM= gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= +gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= +gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/httprequest.v1 v1.1.1/go.mod h1:/CkavNL+g3qLOrpFHVrEx4NKepeqR4XTZWNj4sGGjz0= +gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/ns1/ns1-go.v2 v2.4.4 h1:xV/rJE2m8p3IncnwMEFrv36K4NDnRXu4CoIkgq+AZek= -gopkg.in/ns1/ns1-go.v2 v2.4.4/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk= +gopkg.in/ns1/ns1-go.v2 v2.5.1 h1:yDCffh6bVBQuOUHuikJ2CC3cnMmsu8biEEwtLkpxVSI= +gopkg.in/ns1/ns1-go.v2 v2.5.1/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk= gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 8ca87b777..5c4ccfb64 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -986,8 +986,9 @@ func makeTests(t *testing.T) []*TestGroup { testgroup("pager1201", only( - //"MSDNS", // No paging done. No need to test. - //"AZURE_DNS", // Currently failing. See https://github.com/StackExchange/dnscontrol/issues/770 + //"MSDNS", // No paging done. No need to test. + //"AKAMAIEDGEDNS", // No paging done. No need to test. + //"AZURE_DNS", // Currently failing. See https://github.com/StackExchange/dnscontrol/issues/770 "HEXONET", "HOSTINGDE", //"ROUTE53", // Currently failing. See https://github.com/StackExchange/dnscontrol/issues/908 diff --git a/integrationTest/providers.json b/integrationTest/providers.json index 68f08f9f6..a5f82708f 100644 --- a/integrationTest/providers.json +++ b/integrationTest/providers.json @@ -58,6 +58,15 @@ "api_key": "$DNSMADEEASY_API_KEY", "secret_key": "$DNSMADEEASY_SECRET_KEY" }, + "AKAMAIEDGEDNS": { + "client_secret": "$AED_CLIENT_SECRET", + "host": "$AED_HOST", + "access_token": "$AED_ACCESS_TOKEN", + "client_token": "$AED_CLIENT_TOKEN", + "contract_id": "$AED_CONTRACT_ID", + "group_id": "$AED_GROUP_ID", + "domain": "$AED_DOMAIN" + }, "EXOSCALE": { "apikey": "$EXOSCALE_API_KEY", "dns-endpoint": "https://api.exoscale.ch/dns", diff --git a/models/domain.go b/models/domain.go index f3fa4c51c..5d342b948 100644 --- a/models/domain.go +++ b/models/domain.go @@ -77,7 +77,7 @@ func (dc *DomainConfig) Punycode() error { // Set the target: switch rec.Type { // #rtype_variations - case "ALIAS", "MX", "NS", "CNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS", "NS1_URLFWD": + case "ALIAS", "MX", "NS", "CNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS", "NS1_URLFWD", "AKAMAICDN": // These rtypes are hostnames, therefore need to be converted (unlike, for example, an AAAA record) t, err := idna.ToASCII(rec.GetTargetField()) if err != nil { diff --git a/models/record.go b/models/record.go index 1137afd1d..a29d693f1 100644 --- a/models/record.go +++ b/models/record.go @@ -499,10 +499,10 @@ func downcase(recs []*RecordConfig) { r.Name = strings.ToLower(r.Name) r.NameFQDN = strings.ToLower(r.NameFQDN) switch r.Type { // #rtype_variations - case "ANAME", "CNAME", "DS", "MX", "NS", "PTR", "NAPTR", "SRV": + case "ANAME", "CNAME", "DS", "MX", "NS", "PTR", "NAPTR", "SRV", "TLSA", "AKAMAICDN": // These record types have a target that is case insensitive, so we downcase it. r.target = strings.ToLower(r.target) - case "A", "AAAA", "ALIAS", "CAA", "IMPORT_TRANSFORM", "TLSA", "TXT", "SSHFP", "CF_REDIRECT", "CF_TEMP_REDIRECT": + case "A", "AAAA", "ALIAS", "CAA", "IMPORT_TRANSFORM", "TXT", "SSHFP", "CF_REDIRECT", "CF_TEMP_REDIRECT": // These record types have a target that is case sensitive, or is an IP address. We leave them alone. // Do nothing. case "SOA": diff --git a/models/t_parse.go b/models/t_parse.go index 4c47b0770..00aba0812 100644 --- a/models/t_parse.go +++ b/models/t_parse.go @@ -29,7 +29,7 @@ func (r *RecordConfig) PopulateFromString(rtype, contents, origin string) error return fmt.Errorf("invalid IP in AAAA record: %s", contents) } return r.SetTargetIP(ip) // Reformat to canonical form. - case "ALIAS", "ANAME", "CNAME", "NS", "PTR": + case "AKAMAICDN", "ALIAS", "ANAME", "CNAME", "NS", "PTR": return r.SetTarget(contents) case "CAA": return r.SetTargetCAAString(contents) diff --git a/models/target.go b/models/target.go index 2e0358448..ffe8401bb 100644 --- a/models/target.go +++ b/models/target.go @@ -91,7 +91,7 @@ func (rc *RecordConfig) GetTargetSortable() string { func (rc *RecordConfig) GetTargetDebug() string { content := fmt.Sprintf("%s %s %s %d", rc.Type, rc.NameFQDN, rc.target, rc.TTL) switch rc.Type { // #rtype_variations - case "A", "AAAA", "CNAME", "NS", "PTR", "TXT": + case "A", "AAAA", "CNAME", "NS", "PTR", "TXT", "AKAMAICDN": // Nothing special. case "DS": content += fmt.Sprintf(" ds_algorithm=%d ds_keytag=%d ds_digesttype=%d ds_digest=%s", rc.DsAlgorithm, rc.DsKeyTag, rc.DsDigestType, rc.DsDigest) diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index ec3c8763e..3689c6693 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -215,6 +215,9 @@ var A = recordBuilder('A'); // AAAA(name,ip, recordModifiers...) var AAAA = recordBuilder('AAAA'); +// AKAMAICDN(name, target, recordModifiers...) +var AKAMAICDN = recordBuilder('AKAMAICDN'); + // ALIAS(name,target, recordModifiers...) var ALIAS = recordBuilder('ALIAS'); diff --git a/pkg/js/parse_tests/015-tlsa/foo.com.zone b/pkg/js/parse_tests/015-tlsa/foo.com.zone index db5cbadcc..9e872198f 100644 --- a/pkg/js/parse_tests/015-tlsa/foo.com.zone +++ b/pkg/js/parse_tests/015-tlsa/foo.com.zone @@ -1,2 +1,2 @@ $TTL 300 -_443._tcp IN TLSA 3 1 1 MDFiYTQ3MTljODBiNmZlOTExYjA5MWE3YzA1MTI0YjY0ZWVlY2U5NjRlMDljMDU4ZWY4Zjk4MDVkYWNhNTQ2YiAgLQo= +_443._tcp IN TLSA 3 1 1 mdfiytq3mtljodbinmzlotexyja5mwe3yza1mti0yjy0zwvly2u5njrlmdljmdu4zwy4zjk4mdvkywnhntq2yiaglqo= diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 201ca2043..3852188b9 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -248,7 +248,7 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra r := newRec() r.SetTarget(transformCNAME(r.GetTargetField(), srcDomain.Name, dstDomain.Name)) dstDomain.Records = append(dstDomain.Records, r) - case "MX", "NAPTR", "NS", "SOA", "SRV", "TXT", "CAA", "TLSA": + case "AKAMAICDN", "MX", "NAPTR", "NS", "SOA", "SRV", "TXT", "CAA", "TLSA": // Not imported. continue default: @@ -555,6 +555,7 @@ var providerCapabilityChecks = []pairTypeCapability{ capabilityCheck("SRV", providers.CanUseSRV), capabilityCheck("TLSA", providers.CanUseTLSA), capabilityCheck("AZURE_ALIAS", providers.CanUseAzureAlias), + capabilityCheck("AKAMAICDN", providers.CanUseAKAMAICDN), // DS needs special record-level checks { diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go index 65ae88266..ab0df97bd 100644 --- a/pkg/printer/printer.go +++ b/pkg/printer/printer.go @@ -105,7 +105,7 @@ func (c ConsolePrinter) StartDNSProvider(provider string, skip bool) { if skip { lbl = " (skipping)\n" } - fmt.Fprintf(c.Writer, "----- DNS Provider: %s...%s", provider, lbl) + fmt.Fprintf(c.Writer, "----- DNS Provider: %s...%s\n", provider, lbl) } // StartRegistrar is called at the start of each new registrar. @@ -114,7 +114,7 @@ func (c ConsolePrinter) StartRegistrar(provider string, skip bool) { if skip { lbl = " (skipping)\n" } - fmt.Fprintf(c.Writer, "----- Registrar: %s...%s", provider, lbl) + fmt.Fprintf(c.Writer, "----- Registrar: %s...%s\n", provider, lbl) } // EndProvider is called at the end of each provider. diff --git a/providers/_all/all.go b/providers/_all/all.go index 2f1bbbb01..3b268c082 100644 --- a/providers/_all/all.go +++ b/providers/_all/all.go @@ -4,6 +4,7 @@ package all import ( // Define all known providers here. They should each register themselves with the providers package via init function. _ "github.com/StackExchange/dnscontrol/v3/providers/activedir" + _ "github.com/StackExchange/dnscontrol/v3/providers/akamaiedgedns" _ "github.com/StackExchange/dnscontrol/v3/providers/axfrddns" _ "github.com/StackExchange/dnscontrol/v3/providers/azuredns" _ "github.com/StackExchange/dnscontrol/v3/providers/bind" diff --git a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go new file mode 100644 index 000000000..91c5306ac --- /dev/null +++ b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go @@ -0,0 +1,247 @@ +package akamaiedgedns + +/* +Akamai Edge DNS provider + +For information about Akamai Edge DNS, see: +https://www.akamai.com/us/en/products/security/edge-dns.jsp +https://learn.akamai.com/en-us/products/cloud_security/edge_dns.html +https://www.akamai.com/us/en/multimedia/documents/product-brief/edge-dns-product-brief.pdf +*/ + +import ( + "encoding/json" + "fmt" + "github.com/StackExchange/dnscontrol/v3/models" + "github.com/StackExchange/dnscontrol/v3/pkg/diff" + "github.com/StackExchange/dnscontrol/v3/pkg/printer" + "github.com/StackExchange/dnscontrol/v3/pkg/txtutil" + "github.com/StackExchange/dnscontrol/v3/providers" + "strings" +) + +var features = providers.DocumentationNotes{ + // The default for unlisted capabilities is 'Cannot'. + // See providers/capabilities.go for the entire list of capabilties. + providers.CanUseAlias: providers.Cannot(), + providers.CanUseCAA: providers.Can(), + providers.CanUseDS: providers.Cannot(), + providers.CanUseDSForChildren: providers.Can(), + providers.CanUsePTR: providers.Can(), + providers.CanUseNAPTR: providers.Can(), + providers.CanUseSRV: providers.Can(), + providers.CanUseSSHFP: providers.Can(), + providers.CanUseTLSA: providers.Can(), + providers.CanAutoDNSSEC: providers.Can(), + providers.CantUseNOPURGE: providers.Cannot(), + providers.DocOfficiallySupported: providers.Cannot(), + providers.DocDualHost: providers.Can(), + providers.CanUseSOA: providers.Cannot(), + providers.DocCreateDomains: providers.Can(), + providers.CanGetZones: providers.Can(), + providers.CanUseAKAMAICDN: providers.Can(), +} + +type edgeDNSProvider struct { + contractID string + groupID string +} + +func init() { + fns := providers.DspFuncs{ + Initializer: newEdgeDNSDSP, + RecordAuditor: AuditRecords, + } + providers.RegisterDomainServiceProviderType("AKAMAIEDGEDNS", fns, features) + providers.RegisterCustomRecordType("AKAMAICDN", "AKAMAIEDGEDNS", "") +} + +// DnsServiceProvider +func newEdgeDNSDSP(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { + clientSecret := config["client_secret"] + host := config["host"] + accessToken := config["access_token"] + clientToken := config["client_token"] + contractID := config["contract_id"] + groupID := config["group_id"] + + if clientSecret == "" { + return nil, fmt.Errorf("creds.json: client_secret must not be empty") + } + if host == "" { + return nil, fmt.Errorf("creds.json: host must not be empty") + } + if accessToken == "" { + return nil, fmt.Errorf("creds.json: accessToken must not be empty") + } + if clientToken == "" { + return nil, fmt.Errorf("creds.json: clientToken must not be empty") + } + if contractID == "" { + return nil, fmt.Errorf("creds.json: contractID must not be empty") + } + if groupID == "" { + return nil, fmt.Errorf("creds.json: groupID must not be empty") + } + + initialize(clientSecret, host, accessToken, clientToken) + + api := &edgeDNSProvider{ + contractID: contractID, + groupID: groupID, + } + return api, nil +} + +// EnsureDomainExists configures a new zone if the zone does not already exist. +func (a *edgeDNSProvider) EnsureDomainExists(domain string) error { + if zoneDoesExist(domain) { + printer.Debugf("Zone %s already exists\n", domain) + return nil + } + return createZone(domain, a.contractID, a.groupID) +} + +// GetDomainCorrections return a list of corrections. Each correction is a text string describing the change +// and a function that, if called, will make the change. +// “dnscontrol preview” simply prints the text strings. +// "dnscontrol push" prints the strings and calls the functions. +func (a *edgeDNSProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + err := dc.Punycode() + if err != nil { + return nil, err + } + + existingRecords, err := getRecords(dc.Name) + if err != nil { + return nil, err + } + + models.PostProcessRecords(existingRecords) + txtutil.SplitSingleLongTxt(dc.Records) + + keysToUpdate, err := (diff.New(dc)).ChangedGroups(existingRecords) + if err != nil { + return nil, err + } + + existingRecordsMap := make(map[models.RecordKey][]*models.RecordConfig) + for _, r := range existingRecords { + key := models.RecordKey{NameFQDN: r.NameFQDN, Type: r.Type} + existingRecordsMap[key] = append(existingRecordsMap[key], r) + } + + desiredRecordsMap := dc.Records.GroupedByKey() + + // Deletes must occur first. For example, if replacing a existing CNAME with an A of the same name: + // DELETE CNAME foo.example.net + // must occur before + // CREATE A foo.example.net + // because both an A and a CNAME for the same name is not allowed. + + corrections := []*models.Correction{} // deletes first + lastCorrections := []*models.Correction{} // creates and replaces last + + for key, msg := range keysToUpdate { + existing, okExisting := existingRecordsMap[key] + desired, okDesired := desiredRecordsMap[key] + + if okExisting && !okDesired { + // In the existing map but not in the desired map: Delete + corrections = append(corrections, &models.Correction{ + Msg: strings.Join(msg, "\n "), + F: func() error { + return deleteRecordset(existing, dc.Name) + }, + }) + printer.Debugf("deleteRecordset: %s %s\n", key.NameFQDN, key.Type) + for _, rdata := range existing { + printer.Debugf(" Rdata: %s\n", rdata.GetTargetCombined()) + } + } else if !okExisting && okDesired { + // Not in the existing map but in the desired map: Create + lastCorrections = append(lastCorrections, &models.Correction{ + Msg: strings.Join(msg, "\n "), + F: func() error { + return createRecordset(desired, dc.Name) + }, + }) + printer.Debugf("createRecordset: %s %s\n", key.NameFQDN, key.Type) + for _, rdata := range desired { + printer.Debugf(" Rdata: %s\n", rdata.GetTargetCombined()) + } + } else if okExisting && okDesired { + // In the existing map and in the desired map: Replace + lastCorrections = append(lastCorrections, &models.Correction{ + Msg: strings.Join(msg, "\n "), + F: func() error { + return replaceRecordset(desired, dc.Name) + }, + }) + printer.Debugf("replaceRecordset: %s %s\n", key.NameFQDN, key.Type) + for _, rdata := range desired { + printer.Debugf(" Rdata: %s\n", rdata.GetTargetCombined()) + } + } + } + + // Deletes first, then creates and replaces + corrections = append(corrections, lastCorrections...) + + // AutoDnsSec correction + existingAutoDNSSecEnabled, err := isAutoDNSSecEnabled(dc.Name) + if err != nil { + return nil, err + } + + desiredAutoDNSSecEnabled := dc.AutoDNSSEC == "on" + + if !existingAutoDNSSecEnabled && desiredAutoDNSSecEnabled { + // Existing false (disabled), Desired true (enabled) + corrections = append(corrections, &models.Correction{ + Msg: "Enable AutoDnsSec\n", + F: func() error { + return autoDNSSecEnable(true, dc.Name) + }, + }) + printer.Debugf("autoDNSSecEnable: Enable AutoDnsSec for zone %s\n", dc.Name) + } else if existingAutoDNSSecEnabled && !desiredAutoDNSSecEnabled { + // Existing true (enabled), Desired false (disabled) + corrections = append(corrections, &models.Correction{ + Msg: "Disable AutoDnsSec\n", + F: func() error { + return autoDNSSecEnable(false, dc.Name) + }, + }) + printer.Debugf("autoDNSSecEnable: Disable AutoDnsSec for zone %s\n", dc.Name) + } + + return corrections, nil +} + +// GetNameservers returns the nameservers for a domain. +func (a *edgeDNSProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { + authorities, err := getAuthorities(a.contractID) + if err != nil { + return nil, err + } + return models.ToNameserversStripTD(authorities) +} + +// GetZoneRecords returns an array of RecordConfig structs for a zone. +func (a *edgeDNSProvider) GetZoneRecords(domain string) (models.Records, error) { + records, err := getRecords(domain) + if err != nil { + return nil, err + } + return records, nil +} + +// ListZones returns all DNS zones managed by this provider. +func (a *edgeDNSProvider) ListZones() ([]string, error) { + zones, err := listZones(a.contractID) + if err != nil { + return nil, err + } + return zones, nil +} diff --git a/providers/akamaiedgedns/akamaiEdgeDnsService.go b/providers/akamaiedgedns/akamaiEdgeDnsService.go new file mode 100644 index 000000000..76a3df8c8 --- /dev/null +++ b/providers/akamaiedgedns/akamaiEdgeDnsService.go @@ -0,0 +1,305 @@ +package akamaiedgedns + +/* +For information about Akamai's "Edge DNS Zone Management API", see: +https://developer.akamai.com/api/cloud_security/edge_dns_zone_management/v2.html + +For information about "AkamaiOPEN-edgegrid-golang" library, see: +https://github.com/akamai/AkamaiOPEN-edgegrid-golang +*/ + +import ( + "fmt" + "github.com/StackExchange/dnscontrol/v3/models" + "github.com/StackExchange/dnscontrol/v3/pkg/printer" + dnsv2 "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v2" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid" +) + +// initialize initializes the "Akamai OPEN EdgeGrid" library +func initialize(clientSecret string, host string, accessToken string, clientToken string) { + + eg := edgegrid.Config{ + ClientSecret: clientSecret, + Host: host, + AccessToken: accessToken, + ClientToken: clientToken, + MaxBody: 131072, + Debug: false, + } + dnsv2.Init(eg) +} + +// zoneDoesExist returns true if the zone exists, false otherwise. +func zoneDoesExist(zonename string) bool { + _, err := dnsv2.GetZone(zonename) + return err == nil +} + +// createZone create a new zone and creates SOA and NS records for the zone. +// Akamai assigns a unique set of authoritative nameservers for each contract. These authorities should be +// used as the NS records on all zones belonging to this contract. +func createZone(zonename string, contractID string, groupID string) error { + zone := &dnsv2.ZoneCreate{ + Zone: zonename, + Type: "PRIMARY", + Comment: "This zone created by DNSControl (http://dnscontrol.org)", + SignAndServe: false, + SignAndServeAlgorithm: "RSA_SHA512", + ContractId: contractID, + } + + queryArgs := &dnsv2.ZoneQueryString{ + Contract: contractID, + Group: groupID, + } + + err := dnsv2.ValidateZone(zone) + if err != nil { + return fmt.Errorf("Invalid value provided for zone. Error: %s", err.Error()) + } + + err = zone.Save(*queryArgs) + if err != nil { + return fmt.Errorf("Zone create failed. Error: %s", err.Error()) + } + + // Indirectly create NS and SOA records + err = zone.SaveChangelist() + if err != nil { + return fmt.Errorf("Zone initialization failed. SOA and NS records need to be created") + } + err = zone.SubmitChangelist() + if err != nil { + return fmt.Errorf("Zone create failed. Error: %s", err.Error()) + } + + printer.Printf("Created zone: %s\n", zone.Zone) + printer.Printf(" Type: %s\n", zone.Type) + printer.Printf(" Comment: %s\n", zone.Comment) + printer.Printf(" SignAndServe: %v\n", zone.SignAndServe) + printer.Printf(" SignAndServeAlgorithm: %s\n", zone.SignAndServeAlgorithm) + printer.Printf(" ContractId: %s\n", zone.ContractId) + printer.Printf(" GroupId: %s\n", queryArgs.Group) + + return nil +} + +// listZones lists all zones associated with this contract. +func listZones(contractID string) ([]string, error) { + queryArgs := dnsv2.ZoneListQueryArgs{ + ContractIds: contractID, + ShowAll: true, + } + + zoneListResp, err := dnsv2.ListZones(queryArgs) + if err != nil { + return nil, fmt.Errorf("Zone List retrieval failed. Error: %s", err.Error()) + } + + edgeDNSZones := zoneListResp.Zones // what we have + var zones []string // what we return + + for _, edgeDNSZone := range edgeDNSZones { + zones = append(zones, edgeDNSZone.Zone) + } + + return zones, nil +} + +// isAutoDNSSecEnabled returns true if AutoDNSSEC (SignAndServe) is enabled, false otherwise. +func isAutoDNSSecEnabled(zonename string) (bool, error) { + zone, err := dnsv2.GetZone(zonename) + if err != nil { + if dnsv2.IsConfigDNSError(err) && err.(dnsv2.ConfigDNSError).NotFound() { + return false, fmt.Errorf("Zone %s does not exist. Error: %s", + zonename, err.Error()) + } + return false, fmt.Errorf("Error retrieving information for zone %s. Error: %s", + zonename, err.Error()) + } + return zone.SignAndServe, nil +} + +// autoDNSSecEnable enables or disables AutoDNSSEC (SignAndServe) for the zone. +func autoDNSSecEnable(enable bool, zonename string) error { + zone, err := dnsv2.GetZone(zonename) + if err != nil { + if dnsv2.IsConfigDNSError(err) && err.(dnsv2.ConfigDNSError).NotFound() { + return fmt.Errorf("Zone %s does not exist. Error: %s", + zonename, err.Error()) + } + return fmt.Errorf("Error retrieving information for zone %s. Error: %s", + zonename, err.Error()) + } + + algorithm := "RSA_SHA512" + if zone.SignAndServeAlgorithm != "" { + algorithm = zone.SignAndServeAlgorithm + } + + modifiedzone := &dnsv2.ZoneCreate{ + Zone: zone.Zone, + Type: zone.Type, + Masters: zone.Masters, + Comment: zone.Comment, + SignAndServe: enable, // AutoDNSSEC + SignAndServeAlgorithm: algorithm, + TsigKey: zone.TsigKey, + EndCustomerId: zone.EndCustomerId, + ContractId: zone.ContractId, + } + + queryArgs := dnsv2.ZoneQueryString{} + + err = modifiedzone.Update(queryArgs) + if err != nil { + return fmt.Errorf("Error updating zone %s. Error: %s", + zonename, err.Error()) + } + + return nil +} + +// getAuthorities returns the list of authoritative nameservers for the contract. +// Akamai assigns a unique set of authoritative nameservers for each contract. These authorities should be +// used as the NS records on all zones belonging to this contract. +func getAuthorities(contractID string) ([]string, error) { + authorityResponse, err := dnsv2.GetAuthorities(contractID) + if err != nil { + return nil, fmt.Errorf("getAuthorities - ContractID %s: Authorities retrieval failed. Error: %s", + contractID, err.Error()) + } + contracts := authorityResponse.Contracts + if len(contracts) != 1 { + return nil, fmt.Errorf("getAuthorities - ContractID %s: Expected 1 element in array but got %d", + contractID, len(contracts)) + } + cid := contracts[0].ContractID + if cid != contractID { + return nil, fmt.Errorf("getAuthorities - ContractID %s: Got authorities for wrong contractID (%s)", + contractID, cid) + } + authorities := contracts[0].Authorities + return authorities, nil +} + +// rcToRs converts DNSControl RecordConfig records to an AkamaiEdgeDNS recordset. +func rcToRs(records []*models.RecordConfig, zonename string) (*dnsv2.RecordBody, error) { + if len(records) == 0 { + return nil, fmt.Errorf("No records to replace") + } + + akaRecord := &dnsv2.RecordBody{ + Name: records[0].NameFQDN, + RecordType: records[0].Type, + TTL: int(records[0].TTL), + } + + for _, r := range records { + akaRecord.Target = append(akaRecord.Target, r.GetTargetCombined()) + } + + return akaRecord, nil +} + +// createRecordset creates a new AkamaiEdgeDNS recordset in the zone. +func createRecordset(records []*models.RecordConfig, zonename string) error { + akaRecord, err := rcToRs(records, zonename) + if err != nil { + return err + } + + err = akaRecord.Save(zonename, true) + if err != nil { + return fmt.Errorf("Recordset creation failed. Error: %s", err.Error()) + } + return nil +} + +// replaceRecordset replaces an existing AkamaiEdgeDNS recordset in the zone. +func replaceRecordset(records []*models.RecordConfig, zonename string) error { + akaRecord, err := rcToRs(records, zonename) + if err != nil { + return err + } + + err = akaRecord.Update(zonename, true) + if err != nil { + return fmt.Errorf("Recordset update failed. Error: %s", err.Error()) + } + return nil +} + +// deleteRecordset deletes an existing AkamaiEdgeDNS recordset in the zone. +func deleteRecordset(records []*models.RecordConfig, zonename string) error { + akaRecord, err := rcToRs(records, zonename) + if err != nil { + return err + } + + err = akaRecord.Delete(zonename, true) + if err != nil { + if dnsv2.IsConfigDNSError(err) && err.(dnsv2.ConfigDNSError).NotFound() { + return fmt.Errorf("Recordset not found") + } + return fmt.Errorf("Failed to delete recordset. Error: %s", err.Error()) + } + return nil +} + +/* + Example AkamaiEdgeDNS Recordset (as JSON): + { + "name": "test.com", + "rdata": [ + "a7.akafp.net.", + "a4.akafp.net.", + "a0.akafp.net." + ], + "ttl": 10000, + "type": "NS" + } +*/ + +// getRecords returns all RecordConfig records in the zone. +func getRecords(zonename string) ([]*models.RecordConfig, error) { + queryArgs := dnsv2.RecordsetQueryArgs{ShowAll: true} + + rsetResp, err := dnsv2.GetRecordsets(zonename, queryArgs) + if err != nil { + return nil, fmt.Errorf("Recordset list retrieval failed. Error: %s", err.Error()) + } + + akaRecordsets := rsetResp.Recordsets // what we have + var recordConfigs []*models.RecordConfig // what we return + + // For each AkamaiEdgeDNS recordset... + for _, akarecset := range akaRecordsets { + akaname := akarecset.Name + akatype := akarecset.Type + akattl := akarecset.TTL + + // Don't report the existence of an SOA record (because DnsControl will try to delete the SOA record). + if akatype == "SOA" { + continue + } + + // ... convert the recordset into 1 or more RecordConfig structs + for _, r := range akarecset.Rdata { + rc := &models.RecordConfig{ + Type: akatype, + TTL: uint32(akattl), + } + rc.SetLabelFromFQDN(akaname, zonename) + err = rc.PopulateFromString(akatype, r, zonename) + if err != nil { + return nil, err + } + + recordConfigs = append(recordConfigs, rc) + } + } + + return recordConfigs, nil +} diff --git a/providers/akamaiedgedns/auditrecords.go b/providers/akamaiedgedns/auditrecords.go new file mode 100644 index 000000000..4729c6d8f --- /dev/null +++ b/providers/akamaiedgedns/auditrecords.go @@ -0,0 +1,8 @@ +package akamaiedgedns + +import "github.com/StackExchange/dnscontrol/v3/models" + +// AuditRecords returns an error if any records are not supportable by this provider. +func AuditRecords(records []*models.RecordConfig) error { + return nil +} diff --git a/providers/capabilities.go b/providers/capabilities.go index 58a239fed..0a00be13f 100644 --- a/providers/capabilities.go +++ b/providers/capabilities.go @@ -69,6 +69,9 @@ const ( // CanUseSOA indicates the provider supports full management of a zone's SOA record CanUseSOA + + // CanUseAKAMAICDN indicates the provider support the specific AKAMAICDN records that only the Akamai EdgeDns provider supports + CanUseAKAMAICDN ) var providerCapabilities = map[string]map[Capability]bool{}