From f6ce421fdd2306fc778fd13b1346781542d6f864 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 20 Jan 2020 14:13:32 -0500 Subject: [PATCH] NEW PROVIDER: GANDI_V5 (deprecates GANDI) (#572) * GANDI_v5: Add Registrar support * Add GANDI deprecation warning * vendor github.com/tiramiseb/go-gandi --- docs/_includes/matrix.html | 32 ++ docs/_providers/gandi_v5.md | 62 +++ docs/writing-providers.md | 16 +- go.mod | 23 +- go.sum | 378 ++---------------- integrationTest/providers.json | 4 + models/dns.go | 13 + models/provider.go | 12 + models/record.go | 26 +- pkg/normalize/flatten.go | 2 +- providers/_all/all.go | 1 + providers/diff/diff.go | 26 ++ providers/gandi/gandiProvider.go | 6 + providers/gandi_v5/convert.go | 79 ++++ providers/gandi_v5/convert_test.go | 44 ++ providers/gandi_v5/gandi_v5Provider.go | 337 ++++++++++++++++ providers/ns1/ns1provider.go | 4 +- .../testify/assert/assertion_format.go | 82 ++++ .../testify/assert/assertion_forward.go | 164 ++++++++ .../testify/assert/assertion_order.go | 309 ++++++++++++++ .../stretchr/testify/assert/assertions.go | 96 ++++- .../github.com/tiramiseb/go-gandi/.gitignore | 2 + vendor/github.com/tiramiseb/go-gandi/LICENSE | 7 + .../github.com/tiramiseb/go-gandi/README.md | 13 + .../tiramiseb/go-gandi/domain/domain.go | 166 ++++++++ vendor/github.com/tiramiseb/go-gandi/gandi.go | 19 + vendor/github.com/tiramiseb/go-gandi/go.mod | 9 + vendor/github.com/tiramiseb/go-gandi/go.sum | 13 + .../go-gandi/internal/client/gandi.go | 157 ++++++++ .../tiramiseb/go-gandi/livedns/axfr.go | 76 ++++ .../tiramiseb/go-gandi/livedns/domain.go | 101 +++++ .../go-gandi/livedns/domainrecord.go | 97 +++++ .../tiramiseb/go-gandi/livedns/livedns.go | 20 + .../tiramiseb/go-gandi/livedns/snapshot.go | 29 ++ vendor/modules.txt | 7 +- 35 files changed, 2047 insertions(+), 385 deletions(-) create mode 100644 docs/_providers/gandi_v5.md create mode 100644 providers/gandi_v5/convert.go create mode 100644 providers/gandi_v5/convert_test.go create mode 100644 providers/gandi_v5/gandi_v5Provider.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_order.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/.gitignore create mode 100644 vendor/github.com/tiramiseb/go-gandi/LICENSE create mode 100644 vendor/github.com/tiramiseb/go-gandi/README.md create mode 100644 vendor/github.com/tiramiseb/go-gandi/domain/domain.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/gandi.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/go.mod create mode 100644 vendor/github.com/tiramiseb/go-gandi/go.sum create mode 100644 vendor/github.com/tiramiseb/go-gandi/internal/client/gandi.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/livedns/axfr.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/livedns/domain.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/livedns/domainrecord.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/livedns/livedns.go create mode 100644 vendor/github.com/tiramiseb/go-gandi/livedns/snapshot.go diff --git a/docs/_includes/matrix.html b/docs/_includes/matrix.html index 6d72f77ad..2945b43be 100644 --- a/docs/_includes/matrix.html +++ b/docs/_includes/matrix.html @@ -16,6 +16,7 @@
EXOSCALE
GANDI
GANDI-LIVEDNS
+
GANDI_V5
GCLOUD
HEXONET
LINODE
@@ -63,6 +64,9 @@ + + + @@ -153,6 +157,9 @@ + + + @@ -201,6 +208,9 @@ + + + @@ -263,6 +273,7 @@ + @@ -323,6 +334,9 @@ + + + @@ -378,6 +392,9 @@ + + + @@ -429,6 +446,7 @@ + SRV @@ -468,6 +486,9 @@ + + + @@ -523,6 +544,7 @@ + @@ -557,6 +579,7 @@ + @@ -595,6 +618,7 @@ + @@ -631,6 +655,7 @@ + @@ -673,6 +698,7 @@ + @@ -736,6 +762,9 @@ + + + @@ -805,6 +834,9 @@ + + + diff --git a/docs/_providers/gandi_v5.md b/docs/_providers/gandi_v5.md new file mode 100644 index 000000000..1f23e9510 --- /dev/null +++ b/docs/_providers/gandi_v5.md @@ -0,0 +1,62 @@ +--- +name: Gandi_v5 +title: Gandi_v5 Provider +layout: default +jsId: GANDI +--- +# Gandi_v5 Provider + +`GANDI_V5` uses the v5 API and can act as a registrar provider + or a DNS provider. It is only able to work with domains + migrated to the new LiveDNS API, which should be all domains. + API keys are assigned to particular users. Go to User Settings, + "Manage the user account and security settings", the "Security" + tab, then regenerate the "Production API key". + +* API Documentation: https://api.gandi.net/docs +* API Endpoint: https://api.gandi.net/ + +## Configuration +In your credentials file you must provide your Gandi.net API key. +The [sharing_id](https://api.gandi.net/docs/reference/) is optional. + +{% highlight json %} +{ + "gandi_v5": { + "apikey": "your-gandi-key", + "sharing_id": "your-sharing_id" + } +} +{% endhighlight %} + +## Metadata +This provider does not recognize any special metadata fields unique to Gandi. + +## Usage +Example Javascript: + +{% highlight js %} +var GANDI = NewDnsProvider("gandi", "GANDI_V5"); +var REG_GANDI = NewRegistrar("gandi", "GANDI_V5"); + +D("example.tld", REG_GANDI, DnsProvider(GANDI), + A("test","1.2.3.4") +); +{% endhighlight %} + +If you are converting from the old "GANDI" provider, simply +change "gandi" to "gandi_v5" in `creds.json`, and change "GANDI" +to "GANDI_V5" in `dnsconfig.js`. Be sure to test with +`dnscontrol preview` before running `dnscontrol push` + +## New domains +If a domain does not exist in your Gandi account, DNSControl will *not* automatically add it with the `create-domains` command. You'll need to do that via the web UI manually. + + +## Common errors + +This is the error you'll see if your API key is invalid. + +``` +Error getting corrections: 401: The server could not verify that you authorized to access the document you requested. Either you supplied the wrong credentials (e.g., bad api key), or your access token has expired +``` diff --git a/docs/writing-providers.md b/docs/writing-providers.md index 49e7ec864..cb3f43168 100644 --- a/docs/writing-providers.md +++ b/docs/writing-providers.md @@ -91,18 +91,24 @@ yourself.) Pick a similar provider as your base. Providers basically fall into three general categories: -* **zone:** The API requires you to upload the entire zone every time. (BIND, GANDI). +* **zone:** The API requires you to upload the entire zone every time. (BIND). * **incremental-record:** The API lets you add/change/delete individual DNS records. (ACTIVEDIR, CLOUDFLARE, NAMEDOTCOM, GCLOUD, ROUTE53) -* **incremental-label:** Similar to incremental, but the API requires you to update all the records related to a particular label each time. For example, if a label (www.example.com) has an A and MX record, any change requires replacing all the records for that label. +* **incremental-label:** Like incremental-record, but if there are + multiple records on a label (for example, example www.example.com +has A and MX records), you have to replace all the records at that +label. (GANDI_V5) +* **incremental-label-type:** Like incremental-record, but updates to any records at a label have to be done by type. For example, if a label (www.example.com) has many A and MX records, even the smallest change to one of the A records requires replacing all the A records. Any changes to the MX records requires replacing all the MX records. If an A record is converted to a CNAME, one must remove all the A records in one call, and add the CNAME record with another call. This is deceptively difficult to get right; if you have the voice between incremental-label-type and incremental-label, pick incremental-label. TODO: Categorize DNSIMPLE, NAMECHEAP All providers use the "diff" module to detect differences. It takes two zones and returns records that are unchanged, created, deleted, -and modified. The incremental providers use the differences to -update individual records or recordsets. The zone providers use the +and modified. +The zone providers use the information to print a human-readable list of what is being changed, but upload the entire new zone. +The incremental providers use the differences to +update individual records or recordsets. ## Step 3: Create the driver skeleton @@ -162,7 +168,7 @@ This will run the tests on Amazon AWS Route53: ``` export R53_DOMAIN=dnscontroltest-r53.com # Use a test domain. -export R53_KEY_ID=CHANGE_TO_THE_ID +export R53_KEY_ID='CHANGE_TO_THE_ID' export R53_KEY='CHANGE_TO_THE_KEY' go test -v -verbose -provider ROUTE53 ``` diff --git a/go.mod b/go.mod index 888af51a3..25fce98a1 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,7 @@ go 1.13 require ( cloud.google.com/go v0.41.1-0.20190703172311-335e9e09b93e // indirect - code.cloudfoundry.org/bytefmt v0.0.0-20180906201452-2aa6f33b730c // indirect github.com/Azure/azure-sdk-for-go v32.6.0+incompatible - github.com/Azure/go-autorest v13.0.1-0.20190820210012-403aff94c353+incompatible // indirect github.com/Azure/go-autorest/autorest v0.9.4 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 github.com/Azure/go-autorest/autorest/to v0.3.0 @@ -14,52 +12,51 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d github.com/aws/aws-sdk-go v1.19.39 github.com/billputer/go-namecheap v0.0.0-20170915210158-0c7adb0710f8 + github.com/cenkalti/backoff v2.1.1+incompatible // indirect github.com/dgrijalva/jwt-go v3.2.1-0.20190620180102-5e25c22bd5d6+incompatible // indirect github.com/digitalocean/godo v1.17.1-0.20190625192827-3ec0b9ce8cde github.com/dnsimple/dnsimple-go v0.20.1-0.20181001130357-234ec949d37c github.com/exoscale/egoscale v0.10.5 - github.com/frankban/quicktest v1.4.0 // indirect github.com/go-acme/lego v2.7.2-0.20190727050804-58d6d9f4767a+incompatible - github.com/go-ini/ini v1.32.1-0.20180214101753-32e4be5f41bb // indirect github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring v1.0.1-0.20190318165438-c8c88dbee036 // indirect github.com/google/uuid v1.1.2-0.20190416172445-c2e93f3ae59f github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 - github.com/hashicorp/vault v1.2.0-rc1.0.20190729090442-63bef6cb2b86 // indirect github.com/hashicorp/vault/api v1.0.4 github.com/hexonet/go-sdk v1.2.1 + github.com/jarcoal/httpmock v1.0.4 // indirect github.com/kolo/xmlrpc v0.0.0-20150413191830-0826b98aaa29 // indirect + github.com/kr/pretty v0.1.0 // indirect + github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8 // indirect github.com/miekg/dns v1.0.14 github.com/mjibson/esc v0.1.0 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 - github.com/onsi/ginkgo v1.8.0 // indirect - github.com/onsi/gomega v1.5.0 // indirect github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d - github.com/pierrec/cmdflag v0.0.2 // indirect github.com/pkg/errors v0.8.1 github.com/prasmussen/gandi-api v0.0.0-20180224132202-58d3d4205661 github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d - github.com/schollz/progressbar/v2 v2.12.1 // indirect + github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect github.com/softlayer/softlayer-go v0.0.0-20170804160555-5e1c8cccc730 - github.com/stretchr/testify v1.3.0 + github.com/stretchr/testify v1.4.0 github.com/tdewolff/buffer v2.0.0+incompatible // indirect github.com/tdewolff/minify v2.1.1-0.20170910185944-d515420d53ba+incompatible github.com/tdewolff/parse v2.3.4+incompatible // indirect github.com/tdewolff/strconv v1.0.0 // indirect + github.com/tdewolff/test v1.0.6 // indirect + github.com/tiramiseb/go-gandi v0.0.0-20200119104052-d61de35bb043 github.com/urfave/cli v1.20.1-0.20180106191048-75104e932ac2 github.com/vultr/govultr v0.1.7 - github.com/xenolf/lego v0.4.2-0.20180420000218-fad2257e11ae // indirect golang.org/x/net v0.0.0-20190628185345-da137c7871d7 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect - golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a // indirect google.golang.org/api v0.7.0 + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/ini.v1 v1.42.0 // indirect gopkg.in/ns1/ns1-go.v2 v2.0.0-20170502175150-c563826f4cbe gopkg.in/sourcemap.v1 v1.0.2 // indirect gopkg.in/yaml.v2 v2.2.2 - honnef.co/go/tools v0.0.0-20190628053538-6c2dcfbea27d // indirect ) diff --git a/go.sum b/go.sum index 2c671a36a..719048211 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.41.1-0.20190703172311-335e9e09b93e h1:E4NknbTPW+1SVNhlxaJolqh+W5FM4q7KsiR2zv8tVNg= cloud.google.com/go v0.41.1-0.20190703172311-335e9e09b93e/go.mod h1:05T3xsDVUIfRZP+EM2ftPky59P2i67FhEj6hjkpO5GE= -code.cloudfoundry.org/bytefmt v0.0.0-20180906201452-2aa6f33b730c/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= -code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= -contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= -git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v32.6.0+incompatible h1:PgaVceWF5idtJajyt1rzq1cep6eRPJ8+8hs4GnNzTo0= github.com/Azure/azure-sdk-for-go v32.6.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v13.0.1-0.20190820210012-403aff94c353+incompatible h1:z+q5CyDOBRziuST6XBaitfflJzaoI/la6fzwyhwyHuo= -github.com/Azure/go-autorest v13.0.1-0.20190820210012-403aff94c353+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v13.3.2+incompatible h1:VxzPyuhtnlBOzc4IWCZHqpyH2d+QMLQEuy3wREyY4oc= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest v0.9.4 h1:1cM+NmKw91+8h5vfjgzK4ZGLuN72k87XVZBWyGwNjUM= @@ -34,6 +22,7 @@ github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSW github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= @@ -43,68 +32,26 @@ github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VY github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55 h1:jbGlDKdzAZ92NzK65hUP98ri0/r50vVVvmZsFP/nIqo= github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= -github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/SAP/go-hdb v0.14.1/go.mod h1:7fdQLVC2lER3urZLjZCm0AuMQfApof92n3aylBPEkMo= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d h1:WtAMR0fPCOfK7TPGZ8ZpLLY18HRvL7XJ3xcs0wnREgo= github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d/go.mod h1:WML6KOYjeU8N6YyusMjj2qRvaPNUEvrQvaxuFcMRFJY= -github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190412020505-60e2075261b6/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= -github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apple/foundationdb/bindings/go v0.0.0-20190411004307-cd5c9d91fad2/go.mod h1:OMVSB21p9+xQUIqlGizHPZfjK+SHws1ht+ZytVDoz9U= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= -github.com/armon/go-proxyproto v0.0.0-20190211145416-68259f75880e/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.12.26-0.20171109001453-50411bcf38b6/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k= github.com/aws/aws-sdk-go v1.19.39 h1:pIez14zQWSd/TER2Scohm7aCEG2TgoyXSOX6srOKt6o= github.com/aws/aws-sdk-go v1.19.39/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -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/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/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/briankassouf/jose v0.9.2-0.20180619214549-d2569464773f/go.mod h1:HQhVmdUf7dBNwIIdBTivnCDxcf6IZY3/zrb+uKSJz6Y= github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/centrify/cloud-golang-sdk v0.0.0-20190214225812-119110094d0f/go.mod h1:C0rtzmGXgN78pYR0tGJFhtHgkbAs0lIbHwkB81VxDQE= -github.com/chrismalek/oktasdk-go v0.0.0-20181212195951-3430665dfaa0/go.mod h1:5d8DqS60xkj9k3aXfL3+mXBH0DPYO0FQjcKosxl+b/Q= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 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/denisenkom/go-mssqldb v0.0.0-20190412130859-3b1d194e553a/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.1-0.20190620180102-5e25c22bd5d6+incompatible h1:4jGdduO4ceTJFKf0IhgaB8NJapGqKHwC2b4xQ/cXujM= github.com/dgrijalva/jwt-go v3.2.1-0.20190620180102-5e25c22bd5d6+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -112,55 +59,20 @@ github.com/digitalocean/godo v1.17.1-0.20190625192827-3ec0b9ce8cde h1:RH/BMr8Gop github.com/digitalocean/godo v1.17.1-0.20190625192827-3ec0b9ce8cde/go.mod h1:AAPQ+tiM4st79QHlEBTg8LM7JQNre4SAQCbn56wEyKY= 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.20.1-0.20181001130357-234ec949d37c h1:Llo2tjvv1SspjFXiM8NJyxirMPTZvNPk3lLCPf61COo= github.com/dnsimple/dnsimple-go v0.20.1-0.20181001130357-234ec949d37c/go.mod h1:0FYu4qVNv/UcfZPNwa9zi68IkggJu3TIwM54D7rhmI4= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exoscale/egoscale v0.10.5 h1:pV1gDCsXPi9vfbZ1TIMz7mNGEDMiVHlQlbcJp1qxIaU= github.com/exoscale/egoscale v0.10.5/go.mod h1:Ee3U4ZjSDpbbEc9VkQ/jttUU8USE8Nv7L3YzVi03Y1U= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/frankban/quicktest v1.4.0/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= -github.com/gammazero/deque v0.0.0-20190130191400-2afb3858e9c7/go.mod h1:GeIq9qoE43YdGnDXURnmKTnGg15pQz4mYkXSTChbneI= -github.com/gammazero/workerpool v0.0.0-20190406235159-88d534f22b56/go.mod h1:w9RqFVO2BM3xwWEcAB8Fwp0OviTBBEiRmSBDfbXnd3w= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/go-acme/lego v2.7.2-0.20190727050804-58d6d9f4767a+incompatible h1:xZYTlXWZA2aqWmbOTE+M7uxRyIF2LVhfnx5fmmWlhsY= github.com/go-acme/lego v2.7.2-0.20190727050804-58d6d9f4767a+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-ini/ini v1.32.1-0.20180214101753-32e4be5f41bb/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe h1:zn8tqiUbec4wR94o7Qj3LZCAT6uGobhEgnDRg6isG5U= github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gocql/gocql v0.0.0-20190402132108-0e1d5de854df/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= -github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -168,350 +80,168 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-github v11.0.1-0.20170918062612-eee178af22a1+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= 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/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2-0.20190416172445-c2e93f3ae59f h1:XXzyYlFbxK3kWfcmu3Wc+Tv8/QQl/VqwsWuSYF1Rj0s= github.com/google/uuid v1.1.2-0.20190416172445-c2e93f3ae59f/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/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 h1:/gx6joY4PjXUu6mKM4yx7yj9Ti6yP8ljOxY/Qt0J25g= github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038/go.mod h1:xKR3tvLne+vYYPH9d4DM8X9MKlNV2yXDEomxulcK218= -github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.4.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= -github.com/hashicorp/consul/api v1.0.1/go.mod h1:LQlewHPiuaRhn1mP2XE4RrjnlRgOeWa/ZM0xWLCen2M= -github.com/hashicorp/consul/sdk v0.1.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-gcp-common v0.5.0/go.mod h1:IDGUI2N/OS3PiU4qZcXJeWKPI6O/9Y8hOrbSiMcqyYw= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-memdb v1.0.2/go.mod h1:I6dKdmYhZqU0RJSheVEWgTNWdVQH5QvTgIUQ0t/t32M= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.0.0/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= -github.com/hashicorp/go-raftchunking v0.6.1/go.mod h1:cGlg3JtDy7qy6c/3Bu660Mic1JF+7lWqIwCFSb08fX0= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.3 h1:tuulM+WnToeqa05z83YLmKabZxrySOmJAd4mJ+s2Nfg= github.com/hashicorp/go-retryablehttp v0.6.3/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/nomad/api v0.0.0-20190412184103-1c38ced33adf/go.mod h1:BDngVi1f4UA6aJq9WYTgxhfWSE1+42xshvstLU2fRGk= -github.com/hashicorp/raft v1.0.1/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= -github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= -github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= -github.com/hashicorp/raft-snapshot v1.0.1/go.mod h1:5sL9eUn72lH5DzsFIJ9jaysITbHksSSszImWSOTC8Ic= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/vault v1.2.0-rc1.0.20190729090442-63bef6cb2b86 h1:nxplXj5D3c80g8KNcwmTBbb1MLqzJobO9Y2Y17sMT7c= -github.com/hashicorp/vault v1.2.0-rc1.0.20190729090442-63bef6cb2b86/go.mod h1:bDMG/2ixNJml+kxH5r0nFASiow92RKBpbuu64gc80bc= -github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2-0.20190725165955-db428c1b0976/go.mod h1:gGDuTBheAxJNRSuMP9GXYaZG6fcmJwZmeCDnkeGh1dY= -github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190725170003-0fc4bd518aa2/go.mod h1:8ohKOZvLdPcgxcGG2Y0xt3a8T4xQzxRPIgyGj9Y9pnE= -github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190725170023-9d8d5e0b03e6/go.mod h1:1AEVetqwm/CpGJLS3kbmesG2DXlcodD1q9md3InmIwE= -github.com/hashicorp/vault-plugin-auth-gcp v0.5.1/go.mod h1:eLj92eX8MPI4vY1jaazVLF2sVbSAJ3LRHLRhF/pUmlI= -github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190725170032-0aa7d1c92039/go.mod h1:RQabTr6JNn3J4K4CGY9CohFO0shpAK6QCx2LrntPehg= -github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20190725170041-1cfee03e8d3a/go.mod h1:vtUJ+05r7coC4TyKEdZ8Fw/wzRKikDkoBuHFS/9JJgo= -github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190725170047-354505be0ecf/go.mod h1:vbsD/KqeeknPR31viJ/Ch3pii1NHFxsBrdBSxIV7HSs= -github.com/hashicorp/vault-plugin-auth-pcf v0.0.0-20190725170053-826a135618c1/go.mod h1:+Zk2sV+Ga2KPH5QTmDU3v7qBJDD9GljESoNdU/Ea/0A= -github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190725170059-5c0d558eb59d/go.mod h1:KD56g+aeTNH2AM1l8iOBf5KxX+DSNKleEswJxXE8nI8= -github.com/hashicorp/vault-plugin-secrets-ad v0.5.3-0.20190725170108-e1b17ad0c772/go.mod h1:Cjw2YZt7x4arOBPReUAiYwVLVcN+Grre/XZxDjhhNEk= -github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2-0.20190725170114-7d66a3fa0600/go.mod h1:ndDvbwS9SkZrxzlnjsNtmYc2Qz1WNFtQEvlYuljE+NM= -github.com/hashicorp/vault-plugin-secrets-azure v0.5.2-0.20190725170121-541440395211/go.mod h1:R/PeTA9E4NfMd8NGy9gmOFJNyB+JcQDsckD0HXv7wZw= -github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20190725170127-aa49df112140/go.mod h1:GJjJ2oa9CenWs35tZwParXQzhGgwQxAtlZ+CelUBtSE= -github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2-0.20190725170135-aaf270943731/go.mod h1:He7TWjrGUzez4tDq/cEzQWmqr/puNAnUdrn+t6uNoxw= -github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20190725170141-1c4dac87f383/go.mod h1:NVTIsqXgIu1CW+Dsnkn8AE4+QVrivR8sAzlGT7+aO58= -github.com/hashicorp/vault/api v1.0.1/go.mod h1:AV/+M5VPDpB90arloVX0rVDUIHkONiwz5Uza9HRtpUE= github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU= github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= -github.com/hashicorp/vault/sdk v0.1.8/go.mod h1:tHZfc6St71twLizWNHvnnbiGFo1aq0eD2jGPLtP8kAU= github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8= github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hexonet/go-sdk v1.2.1 h1:UpoeqZQt2y2pypiQOW/+uBUk6DfyEnOzwJaW2LIerVQ= github.com/hexonet/go-sdk v1.2.1/go.mod h1:B0oC4YZT3P2o0DHTm5SH0WCItW3N+r16nCTOykJZF1c= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jeffchao/backoff v0.0.0-20140404060208-9d7fd7aa17f2/go.mod h1:xkfESuHriIekR+4RoV+fu91j/CfnYM29Zi2tMFw5iD4= -github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f/go.mod h1:3J2qVK16Lq8V+wfiL2lPeDZ7UWMxk5LemerHa1p6N00= -github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ= +github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA= +github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/joyent/triton-go v0.0.0-20190112182421-51ffac552869/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kolo/xmlrpc v0.0.0-20150413191830-0826b98aaa29 h1:A9Cxbd2chMbJwYR6WpWelyovi0v8Pv4xTUc64pO1gxE= github.com/kolo/xmlrpc v0.0.0-20150413191830-0826b98aaa29/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.0.0/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI= +github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8 h1:A6SLdFpRzUUF5v9F/7T1fu3DERmOCgTwwP6x54eyFfU= +github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8/go.mod h1:UtpLyb/EupVKXF/N0b4NRe1DNg+QYJsnsHQ038romhM= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/matttproud/golang_protobuf_extensions v1.0.0/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/michaelklishin/rabbit-hole v1.5.0/go.mod h1:vvI1uOitYZi0O5HEGXhaWC1XT80Gy+HvFheJ+5Krlhk= -github.com/miekg/dns v0.0.0-20171110103317-9fc4eb252eed/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/pointerstructure v0.0.0-20190430161007-f252a8fd71c8/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mjibson/esc v0.1.0 h1:5ch+murgrcwDFLOE2hwj0f7kE4xJfJhkSCAjSLY182o= github.com/mjibson/esc v0.1.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1OPs= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= -github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= 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/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -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/cmdflag v0.0.2/go.mod h1:a3zKGZ3cdQUfxjd0RGMLZr8xI3nvpJOB+m6o/1X5BmU= -github.com/pierrec/lz4 v1.0.2-0.20190701081048-057d66e894a4/go.mod h1:i5iVM8Tm8BGXjrx6RR3Wz6sQZlZvYr/QQ+kwo1ocGwk= github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20170316201538-ff09b135c25a/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= -github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= github.com/prasmussen/gandi-api v0.0.0-20180224132202-58d3d4205661 h1:Frjzb2MZatv22HHLQ6BVv2rFBnYxITOk/tePom2DY0o= github.com/prasmussen/gandi-api v0.0.0-20180224132202-58d3d4205661/go.mod h1:zZBfqqLFWgViJUcsGfFksd9RK9pDUVPkYDiWE/uIHy4= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20180612222113-7d6f385de8be/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4= github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/schollz/progressbar/v2 v2.12.1/go.mod h1:fBI3onORwtNtwCWJHsrXtjE3QnJOtqIZrvr3rDaF7L0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tdewolff/buffer v2.0.0+incompatible h1:wg/0v5GqF/dSJq0uTcJlPfvAy2elLU0jVGIC7/rYRlg= github.com/tdewolff/buffer v2.0.0+incompatible/go.mod h1:2aVmbfts5BiODsIH0lFp+FX5BiqjSS7P7+cKqieIAb0= github.com/tdewolff/minify v2.1.1-0.20170910185944-d515420d53ba+incompatible h1:m8LRzseqmFEjYJxycH0MtRuexgkBJWGG6wycNXSXVyU= github.com/tdewolff/minify v2.1.1-0.20170910185944-d515420d53ba+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= -github.com/tdewolff/parse v2.2.0+incompatible h1:U0qTU+Hs57RaV/w2ZDPciOnEVgDDuXBU7CuA3p06qow= -github.com/tdewolff/parse v2.2.0+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38= github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= github.com/tdewolff/strconv v1.0.0 h1:24XNqjjvOsomnQpeNgk2YAhjH8CsDhlXsF1Jru+wYw0= github.com/tdewolff/strconv v1.0.0/go.mod h1:GsDKvhaPwpcoLZ2SVdfZ0oLc4+X5OT6fabULs+cQGec= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= -github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= +github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tiramiseb/go-gandi v0.0.0-20200119104052-d61de35bb043 h1:3M6bLkZ/wu9QyhstHzmoxihT9KBmH0iEiZXsNMuQ4gE= +github.com/tiramiseb/go-gandi v0.0.0-20200119104052-d61de35bb043/go.mod h1:wevS0bE43PMSmEldbtya+tp+Ow180ftEPix8Onwh+E4= github.com/urfave/cli v1.20.1-0.20180106191048-75104e932ac2 h1:jbDY/Ito1YgbqbjqN+gsskuc8oWeYJV8ig09ZgP6LMk= github.com/urfave/cli v1.20.1-0.20180106191048-75104e932ac2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vultr/govultr v0.1.7 h1:+AilzQB5HAStp/mOyBRNil+l8FHWRfHgDEKfC0oQMzY= github.com/vultr/govultr v0.1.7/go.mod h1:glSLa57Jdj5s860EEc6+DEBbb/t3aUOKnB4gVPmDVlQ= -github.com/xenolf/lego v0.4.2-0.20180420000218-fad2257e11ae/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20190412021913-f29b1ada1971/go.mod h1:KSGwdbiFchh5KIC9My2+ZVl5/3ANcwohw50dpPwa2cw= -go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= -go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180608092829-8ac0e0d97ce4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -521,12 +251,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -534,44 +260,30 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20190410170021-cc4d4f50624c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/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-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20170117123646-11dbc599981c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -582,89 +294,45 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= -google.golang.org/api v0.0.0-20170917000347-9133bb5dadbe/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= -google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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= -google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180608181217-32ee49c4dd80/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190513181449-d00d292a067c/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190701230453-710ae3a149df h1:k3DT34vxk64+4bD5x+fRy6U0SXxZehzUHRSYUJcKfII= google.golang.org/genproto v0.0.0-20190701230453-710ae3a149df/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.41.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/ns1/ns1-go.v2 v2.0.0-20170502175150-c563826f4cbe h1:fuu3vZ8C6O8mk8Ich8YfkDv/Zpnx1HUotQk8JocBcSw= gopkg.in/ns1/ns1-go.v2 v2.0.0-20170502175150-c563826f4cbe/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw= -gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.2 h1:PZCr2Fvp0Z96+VGPbmbmFal8SXcL4GBpLm4K7cb8gaU= gopkg.in/sourcemap.v1 v1.0.2/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= -gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190628053538-6c2dcfbea27d/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.0.0-20190409092523-d687e77c8ae9/go.mod h1:FQEUn50aaytlU65qqBn/w+5ugllHwrBzKm7DzbnXdzE= -k8s.io/apimachinery v0.0.0-20190409092423-760d1845f48b/go.mod h1:FW86P8YXVLsbuplGMZeb20J3jYHscrDqw4jELaFJvRU= -k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -layeh.com/radius v0.0.0-20190322222518-890bc1058917/go.mod h1:fywZKyu//X7iRzaxLgPWsvc0L26IUpVvE/aeIL2JtIQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/integrationTest/providers.json b/integrationTest/providers.json index 0f58229d4..0faeea61d 100644 --- a/integrationTest/providers.json +++ b/integrationTest/providers.json @@ -61,6 +61,10 @@ "domain": "$GANDILIVE_DOMAIN", "knownFailures": "5" }, + "GANDI_V5": { + "apikey": "$GANDI_V5_APIKEY", + "domain": "$GANDI_V5_DOMAIN" + }, "GCLOUD": { "type": "$GCLOUD_TYPE", "client_email": "$GCLOUD_EMAIL", diff --git a/models/dns.go b/models/dns.go index 331157e6e..20f853270 100644 --- a/models/dns.go +++ b/models/dns.go @@ -41,6 +41,11 @@ type DNSProviderConfig struct { Metadata json.RawMessage `json:"meta,omitempty"` } +// FIXME(tal): In hindsight, the Nameserver struct is overkill. We +// could have just used []string. Now every provider calls StringsToNameservers +// and ever user calls StringsToNameservers. We should refactor this +// some day. https://github.com/StackExchange/dnscontrol/issues/577 + // Nameserver describes a nameserver. type Nameserver struct { Name string `json:"name"` // Normalized to a FQDN with NO trailing "." @@ -59,6 +64,14 @@ func StringsToNameservers(nss []string) []*Nameserver { return nservers } +// NameserversToStrings constructs a list of lists from *Nameserver structs +func NameserversToStrings(nss []*Nameserver) (s []string) { + for _, ns := range nss { + s = append(s, ns.Name) + } + return s +} + // Correction is anything that can be run. Implementation is up to the specific provider. type Correction struct { F func() error `json:"-"` diff --git a/models/provider.go b/models/provider.go index 3f063b683..3a93a23c6 100644 --- a/models/provider.go +++ b/models/provider.go @@ -6,6 +6,18 @@ type DNSProvider interface { GetDomainCorrections(dc *DomainConfig) ([]*Correction, error) } +// DNSProvider3 will replace DNSProvider in 3.0. +// If you want to future-proof your code, implement these +// functions and implement GetDomainCorrections() as in +// providers/gandi_v5/gandi_v5Provider.go +//type DNSProvider3 interface { +// GetNameservers(domain string) ([]*Nameserver, error) +// GetZoneRecords(domain string) (Records, error) +// PrepFoundRecords(recs Records) Records +// PrepDesiredRecords(dc *DomainConfig) +// GenerateDomainCorrections(dc *DomainConfig, existing Records) ([]*Correction, error) +//} + // Registrar is an interface for Registrar plug-ins. type Registrar interface { GetRegistrarCorrections(dc *DomainConfig) ([]*Correction, error) diff --git a/models/record.go b/models/record.go index 71415060e..6ca8e5725 100644 --- a/models/record.go +++ b/models/record.go @@ -306,8 +306,18 @@ func (rc *RecordConfig) Key() RecordKey { // Records is a list of *RecordConfig. type Records []*RecordConfig +// FQDNMap returns a map of all LabelFQDNs. Useful for making a +// truthtable of labels that exist in Records. +func (r Records) FQDNMap() (m map[string]bool) { + m = map[string]bool{} + for _, rec := range r { + m[rec.GetLabelFQDN()] = true + } + return m +} + // Grouped returns a map of keys to records. -func (r Records) Grouped() map[RecordKey]Records { +func (r Records) GroupedByKey() map[RecordKey]Records { groups := map[RecordKey]Records{} for _, rec := range r { groups[rec.Key()] = append(groups[rec.Key()], rec) @@ -328,6 +338,20 @@ func (r Records) GroupedByLabel() ([]string, map[string]Records) { return order, groups } +// GroupedByFQDN returns a map of keys to records, grouped by FQDN. +func (r Records) GroupedByFQDN() ([]string, map[string]Records) { + order := []string{} + groups := map[string]Records{} + for _, rec := range r { + namefqdn := rec.GetLabelFQDN() + if _, found := groups[namefqdn]; !found { + order = append(order, namefqdn) + } + groups[namefqdn] = append(groups[namefqdn], rec) + } + return order, groups +} + // PostProcessRecords does any post-processing of the downloaded DNS records. func PostProcessRecords(recs []*RecordConfig) { downcase(recs) diff --git a/pkg/normalize/flatten.go b/pkg/normalize/flatten.go index c62b95794..ad1234ea0 100644 --- a/pkg/normalize/flatten.go +++ b/pkg/normalize/flatten.go @@ -15,7 +15,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error { var errs []error var err error for _, domain := range cfg.Domains { - apexTXTs := domain.Records.Grouped()[models.RecordKey{Type: "TXT", NameFQDN: domain.Name}] + apexTXTs := domain.Records.GroupedByKey()[models.RecordKey{Type: "TXT", NameFQDN: domain.Name}] // flatten all spf records that have the "flatten" metadata for _, txt := range apexTXTs { var rec *spflib.SPFRecord diff --git a/providers/_all/all.go b/providers/_all/all.go index 3d95aaf72..4380cf288 100644 --- a/providers/_all/all.go +++ b/providers/_all/all.go @@ -12,6 +12,7 @@ import ( _ "github.com/StackExchange/dnscontrol/providers/dnsimple" _ "github.com/StackExchange/dnscontrol/providers/exoscale" _ "github.com/StackExchange/dnscontrol/providers/gandi" + _ "github.com/StackExchange/dnscontrol/providers/gandi_v5" _ "github.com/StackExchange/dnscontrol/providers/gcloud" _ "github.com/StackExchange/dnscontrol/providers/hexonet" _ "github.com/StackExchange/dnscontrol/providers/linode" diff --git a/providers/diff/diff.go b/providers/diff/diff.go index e36b592ee..4c6915f09 100644 --- a/providers/diff/diff.go +++ b/providers/diff/diff.go @@ -221,6 +221,32 @@ func (d *differ) ChangedGroups(existing []*models.RecordConfig) map[models.Recor return changedKeys } +// DebugKeyMapMap debug prints the results from ChangedGroups. +func DebugKeyMapMap(note string, m map[models.RecordKey][]string) { + // The output isn't pretty but it is useful. + fmt.Println("DEBUG:", note) + + // Extract the keys + var keys []models.RecordKey + for k := range m { + keys = append(keys, k) + } + sort.SliceStable(keys, func(i, j int) bool { + if keys[i].NameFQDN == keys[j].NameFQDN { + return keys[i].Type < keys[j].Type + } + return keys[i].NameFQDN < keys[j].NameFQDN + }) + + // Pretty print the map: + for _, k := range keys { + fmt.Printf(" %v %v:\n", k.Type, k.NameFQDN) + for _, s := range m[k] { + fmt.Printf(" -- %q\n", s) + } + } +} + func (c Correlation) String() string { if c.Existing == nil { return fmt.Sprintf("CREATE %s %s %s", c.Desired.Type, c.Desired.GetLabelFQDN(), c.d.content(c.Desired)) diff --git a/providers/gandi/gandiProvider.go b/providers/gandi/gandiProvider.go index 1ad92712f..f674f2963 100644 --- a/providers/gandi/gandiProvider.go +++ b/providers/gandi/gandiProvider.go @@ -26,6 +26,8 @@ Info required in `creds.json`: */ +var deprecationWarned bool + var features = providers.DocumentationNotes{ providers.CanUseCAA: providers.Can(), providers.CanUsePTR: providers.Can(), @@ -165,6 +167,10 @@ func newReg(conf map[string]string) (providers.Registrar, error) { } func newGandi(m map[string]string, metadata json.RawMessage) (*GandiApi, error) { + if !deprecationWarned { + deprecationWarned = true + fmt.Printf("WARNING: GANDI is deprecated and will disappear in 3.0. Please migrate to GANDI_V5.\n") + } api := &GandiApi{} api.ApiKey = m["apikey"] if api.ApiKey == "" { diff --git a/providers/gandi_v5/convert.go b/providers/gandi_v5/convert.go new file mode 100644 index 000000000..de3563e6e --- /dev/null +++ b/providers/gandi_v5/convert.go @@ -0,0 +1,79 @@ +package gandi5 + +// Convert the provider's native record description to models.RecordConfig. + +import ( + "github.com/StackExchange/dnscontrol/models" + "github.com/StackExchange/dnscontrol/pkg/printer" + "github.com/pkg/errors" + "github.com/tiramiseb/go-gandi/livedns" +) + +// nativeToRecord takes a DNS record from Gandi and returns a native RecordConfig struct. +func nativeToRecords(n livedns.DomainRecord, origin string) (rcs []*models.RecordConfig) { + + // Gandi returns all the values for a given label/rtype pair in each + // livedns.DomainRecord. In other words, if there are multiple A + // records for a label, all the IP addresses are listed in + // n.RrsetValues rather than having many livedns.DomainRecord's. + // We must split them out into individual records, one for each value. + for _, value := range n.RrsetValues { + rc := &models.RecordConfig{ + TTL: uint32(n.RrsetTTL), + Original: n, + } + rc.SetLabel(n.RrsetName, origin) + switch rtype := n.RrsetType; rtype { + default: // "A", "AAAA", "CAA", "NS", "CNAME", "MX", "PTR", "SRV", "TXT" + if err := rc.PopulateFromString(rtype, value, origin); err != nil { + panic(errors.Wrap(err, "unparsable record received from gandi")) + } + } + rcs = append(rcs, rc) + } + + return rcs +} + +func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.DomainRecord { + // Take a list of RecordConfig and return an equivalent list of ZoneRecords. + // Gandi requires one ZoneRecord for each label:key tuple, therefore we + // might collapse many RecordConfig into one ZoneRecord. + + var keys = map[models.RecordKey]*livedns.DomainRecord{} + var zrs []livedns.DomainRecord + + for _, r := range rcs { + label := r.GetLabel() + if label == "@" { + label = origin + } + key := r.Key() + + if zr, ok := keys[key]; !ok { + // Allocate a new ZoneRecord: + zr := livedns.DomainRecord{ + RrsetType: r.Type, + RrsetTTL: int(r.TTL), + RrsetName: label, + RrsetValues: []string{r.GetTargetCombined()}, + } + zrs = append(zrs, zr) + //keys[key] = &zr // This didn't work. + keys[key] = &zrs[len(zrs)-1] // This does work. I don't know why. + + } else { + zr.RrsetValues = append(zr.RrsetValues, r.GetTargetCombined()) + + if r.TTL != uint32(zr.RrsetTTL) { + printer.Warnf("All TTLs for a rrset (%v) must be the same. Using smaller of %v and %v.\n", key, r.TTL, zr.RrsetTTL) + if r.TTL < uint32(zr.RrsetTTL) { + zr.RrsetTTL = int(r.TTL) + } + } + + } + } + + return zrs +} diff --git a/providers/gandi_v5/convert_test.go b/providers/gandi_v5/convert_test.go new file mode 100644 index 000000000..cb332023d --- /dev/null +++ b/providers/gandi_v5/convert_test.go @@ -0,0 +1,44 @@ +package gandi5 + +import ( + "testing" + + "github.com/StackExchange/dnscontrol/models" +) + +func TestRecordsToNative_1(t *testing.T) { + var rcs = []*models.RecordConfig{{}} + rcs[0].SetLabelFromFQDN("foo.example.com", "example.com") + rcs[0].Type = "A" + rcs[0].SetTarget("1.2.3.4") + + ns := recordsToNative(rcs, "example.com") + + if len(ns) != 1 { + t.Errorf("len(ns) != 1; got=%v", len(ns)) + } + if len(ns[0].RrsetValues) != 1 { + t.Errorf("len(ns[0].RrsetValues) != 1; got=%v", ns[0].RrsetValues) + } + +} + +func TestRecordsToNative_2(t *testing.T) { + var rcs = []*models.RecordConfig{{}, {}} + rcs[0].SetLabelFromFQDN("foo.example.com", "example.com") + rcs[0].Type = "A" + rcs[0].SetTarget("1.2.3.4") + rcs[1].SetLabelFromFQDN("foo.example.com", "example.com") + rcs[1].Type = "A" + rcs[1].SetTarget("5.6.7.8") + + ns := recordsToNative(rcs, "example.com") + + if len(ns) != 1 { + t.Errorf("len(ns) != 1; got=%v", len(ns)) + } + if len(ns[0].RrsetValues) != 2 { + t.Errorf("len(ns[0].RrsetValues) != 2; got=%v", ns[0].RrsetValues) + } + +} diff --git a/providers/gandi_v5/gandi_v5Provider.go b/providers/gandi_v5/gandi_v5Provider.go new file mode 100644 index 000000000..cad54666e --- /dev/null +++ b/providers/gandi_v5/gandi_v5Provider.go @@ -0,0 +1,337 @@ +package gandi5 + +/* + +Gandi API V5 LiveDNS provider: + +Documentation: https://api.gandi.net/docs/ +Endpoint: https://api.gandi.net/ + +Settings from `creds.json`: + - apikey + - sharing_id (optional) + +*/ + +import ( + "encoding/json" + "fmt" + "os" + "sort" + "strconv" + "strings" + + gandi "github.com/tiramiseb/go-gandi" + + "github.com/miekg/dns/dnsutil" + + "github.com/StackExchange/dnscontrol/models" + "github.com/StackExchange/dnscontrol/pkg/printer" + "github.com/StackExchange/dnscontrol/providers" + "github.com/StackExchange/dnscontrol/providers/diff" + "github.com/pkg/errors" +) + +// Section 1: Register this provider in the system. + +// init registers the provider to dnscontrol. +func init() { + providers.RegisterDomainServiceProviderType("GANDI_V5", newDsp, features) + providers.RegisterRegistrarType("GANDI_V5", newReg) +} + +// features declares which features and options are available. +var features = providers.DocumentationNotes{ + providers.CanUseCAA: providers.Can(), + providers.CanUsePTR: providers.Can(), + providers.CanUseSRV: providers.Can(), + providers.CantUseNOPURGE: providers.Cannot(), + providers.DocCreateDomains: providers.Cannot("Can only manage domains registered through their service"), + providers.DocOfficiallySupported: providers.Cannot(), +} + +// Section 2: Define the API client. + +// api is the api handle used to store any client-related state. +type api struct { + apikey string + sharingid string + debug bool +} + +// newDsp generates a DNS Service Provider client handle. +func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { + return newHelper(conf, metadata) +} + +// newReg generates a Registrar Provider client handle. +func newReg(conf map[string]string) (providers.Registrar, error) { + return newHelper(conf, nil) +} + +// newHelper generates a handle. +func newHelper(m map[string]string, metadata json.RawMessage) (*api, error) { + api := &api{} + api.apikey = m["apikey"] + if api.apikey == "" { + return nil, errors.Errorf("missing Gandi apikey") + } + api.sharingid = m["sharing_id"] + debug, err := strconv.ParseBool(os.Getenv("GANDI_V5_DEBUG")) + if err == nil { + api.debug = debug + } + + return api, nil +} + +// Section 3: Domain Service Provider (DSP) related functions + +// NB(tal): To future-proof your code, all new providers should +// implement GetDomainCorrections exactly as you see here +// (byte-for-byte the same). In 3.0 +// we plan on using just the individual calls to GetZoneRecords, +// PostProcessRecords, and so on. +// +// Currently every provider does things differently, which prevents +// us from doing things like using GetZoneRecords() of a provider +// to make convertzone work with all providers. + +// GetDomainCorrections get the current and existing records, +// post-process them, and generate corrections. +func (client *api) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + existing, err := client.GetZoneRecords(dc.Name) + if err != nil { + return nil, err + } + models.PostProcessRecords(existing) + clean := PrepFoundRecords(existing) + PrepDesiredRecords(dc) + return client.GenerateDomainCorrections(dc, clean) +} + +// GetZoneRecords gathers the DNS records and converts them to +// dnscontrol's format. +func (client *api) GetZoneRecords(domain string) (models.Records, error) { + g := gandi.NewLiveDNSClient(client.apikey, gandi.Config{SharingID: client.sharingid, Debug: client.debug}) + + // Get all the existing records: + records, err := g.ListDomainRecords(domain) + if err != nil { + return nil, err + } + + // Convert them to DNScontrol's native format: + existingRecords := []*models.RecordConfig{} + for _, rr := range records { + existingRecords = append(existingRecords, nativeToRecords(rr, domain)...) + } + + return existingRecords, nil +} + +// PrepFoundRecords munges any records to make them compatible with +// this provider. Usually this is a no-op. +func PrepFoundRecords(recs models.Records) models.Records { + // If there are records that need to be modified, removed, etc. we + // do it here. Usually this is a no-op. + return recs +} + +// PrepDesiredRecords munges any records to best suit this provider. +func PrepDesiredRecords(dc *models.DomainConfig) { + // Sort through the dc.Records, eliminate any that can't be + // supported; modify any that need adjustments to work with the + // provider. We try to do minimal changes otherwise it gets + // confusing. + + dc.Punycode() + + recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records)) + for _, rec := range dc.Records { + if rec.TTL < 300 { + printer.Warnf("Gandi does not support ttls < 300. Setting %s from %d to 300\n", rec.GetLabelFQDN(), rec.TTL) + rec.TTL = 300 + } + if rec.TTL > 2592000 { + printer.Warnf("Gandi does not support ttls > 30 days. Setting %s from %d to 2592000\n", rec.GetLabelFQDN(), rec.TTL) + rec.TTL = 2592000 + } + if rec.Type == "TXT" { + rec.SetTarget("\"" + rec.GetTargetField() + "\"") // FIXME(tlim): Should do proper quoting. + } + if rec.Type == "NS" && rec.GetLabel() == "@" { + if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") { + printer.Warnf("Gandi does not support changing apex NS records. Ignoring %s\n", rec.GetTargetField()) + } + continue + } + recordsToKeep = append(recordsToKeep, rec) + } + dc.Records = recordsToKeep +} + +// GenerateDomainCorrections takes the desired and existing records +// and produces a Correction list. The correction list is simply +// a list of functions to call to actually make the desired +// correction, and a message to output to the user when the change is +// made. +func (client *api) GenerateDomainCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) { + if client.debug { + debugRecords("GenDC input", existing) + } + + var corrections = []*models.Correction{} + + // diff existing vs. current. + differ := diff.New(dc) + keysToUpdate := differ.ChangedGroups(existing) + if client.debug { + diff.DebugKeyMapMap("GenDC diff", keysToUpdate) + } + if len(keysToUpdate) == 0 { + return nil, nil + } + + // Regroup data by FQDN. ChangedGroups returns data grouped by label:RType tuples. + affectedLabels, msgsForLabel := gatherAffectedLabels(keysToUpdate) + _, desiredRecords := dc.Records.GroupedByFQDN() + doesLabelExist := existing.FQDNMap() + + g := gandi.NewLiveDNSClient(client.apikey, gandi.Config{SharingID: client.sharingid, Debug: client.debug}) + + // For any key with an update, delete or replace those records. + for label := range affectedLabels { + if len(desiredRecords[label]) == 0 { + // No records matching this key? This can only mean that all + // the records were deleted. Delete them. + + msgs := strings.Join(msgsForLabel[label], "\n") + domain := dc.Name + shortname := dnsutil.TrimDomainName(label, dc.Name) + corrections = append(corrections, + &models.Correction{ + Msg: msgs, + F: func() error { + err := g.DeleteDomainRecords(domain, shortname) + if err != nil { + return err + } + return nil + }, + }) + + } else { + // Replace all the records at a label with our new records. + + // Generate the new data in Gandi's format. + ns := recordsToNative(desiredRecords[label], dc.Name) + + if doesLabelExist[label] { + // Records exist for this label. Replace them with what we have. + + msg := strings.Join(msgsForLabel[label], "\n") + domain := dc.Name + shortname := dnsutil.TrimDomainName(label, dc.Name) + corrections = append(corrections, + &models.Correction{ + Msg: msg, + F: func() error { + res, err := g.ChangeDomainRecordsWithName(domain, shortname, ns) + if err != nil { + return errors.Wrapf(err, "%+v", res) + } + return nil + }, + }) + + } else { + // First time putting data on this label. Create it. + + // We have to create the label one rtype at a time. + for _, n := range ns { + msg := strings.Join(msgsForLabel[label], "\n") + domain := dc.Name + shortname := dnsutil.TrimDomainName(label, dc.Name) + rtype := n.RrsetType + ttl := n.RrsetTTL + values := n.RrsetValues + corrections = append(corrections, + &models.Correction{ + Msg: msg, + F: func() error { + res, err := g.CreateDomainRecord(domain, shortname, rtype, ttl, values) + if err != nil { + return errors.Wrapf(err, "%+v", res) + } + return nil + }, + }) + } + } + } + } + + return corrections, nil +} + +// debugRecords prints a list of RecordConfig. +func debugRecords(note string, recs []*models.RecordConfig) { + fmt.Println("DEBUG:", note) + for k, v := range recs { + fmt.Printf(" %v: %v %v %v %v\n", k, v.GetLabel(), v.Type, v.TTL, v.GetTargetCombined()) + } +} + +// gatherAffectedLabels takes the output of diff.ChangedGroups and +// regroups it by FQDN of the label, not by Key. It also returns +// a list of all the FQDNs. +func gatherAffectedLabels(groups map[models.RecordKey][]string) (labels map[string]bool, msgs map[string][]string) { + labels = map[string]bool{} + msgs = map[string][]string{} + for k, v := range groups { + labels[k.NameFQDN] = true + msgs[k.NameFQDN] = append(msgs[k.NameFQDN], v...) + } + return labels, msgs +} + +// Section 3: Registrar-related functions + +// GetNameservers returns a list of nameservers for domain. +func (client *api) GetNameservers(domain string) ([]*models.Nameserver, error) { + g := gandi.NewLiveDNSClient(client.apikey, gandi.Config{SharingID: client.sharingid, Debug: client.debug}) + nameservers, err := g.GetDomainNS(domain) + if err != nil { + return nil, err + } + return models.StringsToNameservers(nameservers), nil +} + +// GetRegistrarCorrections returns a list of corrections for this registrar. +func (client *api) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + gd := gandi.NewDomainClient(client.apikey, gandi.Config{SharingID: client.sharingid, Debug: client.debug}) + + existingNs, err := gd.GetNameServers(dc.Name) + if err != nil { + return nil, err + } + sort.Strings(existingNs) + existing := strings.Join(existingNs, ",") + + desiredNs := models.NameserversToStrings(dc.Nameservers) + sort.Strings(desiredNs) + desired := strings.Join(desiredNs, ",") + + if existing != desired { + return []*models.Correction{ + { + Msg: fmt.Sprintf("Change Nameservers from '%s' to '%s'", existing, desired), + F: func() (err error) { + err = gd.UpdateNameServers(dc.Name, desiredNs) + return + }}, + }, nil + } + return nil, nil +} diff --git a/providers/ns1/ns1provider.go b/providers/ns1/ns1provider.go index ae33baa7a..f17545b46 100644 --- a/providers/ns1/ns1provider.go +++ b/providers/ns1/ns1provider.go @@ -63,8 +63,8 @@ func (n *nsone) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correct } found = append(found, zrs...) } - foundGrouped := found.Grouped() - desiredGrouped := dc.Records.Grouped() + foundGrouped := found.GroupedByKey() + desiredGrouped := dc.Records.GroupedByKey() // Normalize models.PostProcessRecords(found) diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index aa1c2b95c..e0364e9e7 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -113,6 +113,17 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { return Error(t, err, append([]interface{}{msg}, args...)...) } +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) +} + // Exactlyf asserts that two objects are equal in value and type. // // assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123)) @@ -157,6 +168,31 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool return FileExists(t, path, append([]interface{}{msg}, args...)...) } +// Greaterf asserts that the first element is greater than the second +// +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1)) +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Greater(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) +} + // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // @@ -289,6 +325,14 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...) } +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...) +} + // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // @@ -300,6 +344,31 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf return Len(t, object, length, append([]interface{}{msg}, args...)...) } +// Lessf asserts that the first element is less than the second +// +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2)) +// assert.Lessf(t, "a", "b", "error message %s", "formatted") +func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Less(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) +} + // Nilf asserts that the specified object is nil. // // assert.Nilf(t, err, "error message %s", "formatted") @@ -444,6 +513,19 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in return Regexp(t, rx, str, append([]interface{}{msg}, args...)...) } +// Samef asserts that two pointers reference the same object. +// +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Same(t, expected, actual, append([]interface{}{msg}, args...)...) +} + // Subsetf asserts that the specified list(array, slice...) contains all // elements given in the specified subset(array, slice...). // diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index de39f794e..26830403a 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -215,6 +215,28 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { return Errorf(a.t, err, msg, args...) } +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Eventually(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Eventuallyf(a.t, condition, waitFor, tick, msg, args...) +} + // Exactly asserts that two objects are equal in value and type. // // a.Exactly(int32(123), int64(123)) @@ -303,6 +325,56 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) b return FileExistsf(a.t, path, msg, args...) } +// Greater asserts that the first element is greater than the second +// +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") +func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Greater(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") +func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqualf(a.t, e1, e2, msg, args...) +} + +// Greaterf asserts that the first element is greater than the second +// +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1)) +// a.Greaterf("b", "a", "error message %s", "formatted") +func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Greaterf(a.t, e1, e2, msg, args...) +} + // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // @@ -567,6 +639,22 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args .. return JSONEqf(a.t, expected, actual, msg, args...) } +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEqf(a.t, expected, actual, msg, args...) +} + // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // @@ -589,6 +677,56 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in return Lenf(a.t, object, length, msg, args...) } +// Less asserts that the first element is less than the second +// +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") +func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Less(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") +func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return LessOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return LessOrEqualf(a.t, e1, e2, msg, args...) +} + +// Lessf asserts that the first element is less than the second +// +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1, "error message %s", "formatted"), float64(2)) +// a.Lessf("a", "b", "error message %s", "formatted") +func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Lessf(a.t, e1, e2, msg, args...) +} + // Nil asserts that the specified object is nil. // // a.Nil(err) @@ -877,6 +1015,32 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args . return Regexpf(a.t, rx, str, msg, args...) } +// Same asserts that two pointers reference the same object. +// +// a.Same(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Same(a.t, expected, actual, msgAndArgs...) +} + +// Samef asserts that two pointers reference the same object. +// +// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Samef(a.t, expected, actual, msg, args...) +} + // Subset asserts that the specified list(array, slice...) contains all // elements given in the specified subset(array, slice...). // diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go new file mode 100644 index 000000000..15a486ca6 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -0,0 +1,309 @@ +package assert + +import ( + "fmt" + "reflect" +) + +func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) { + switch kind { + case reflect.Int: + { + intobj1 := obj1.(int) + intobj2 := obj2.(int) + if intobj1 > intobj2 { + return -1, true + } + if intobj1 == intobj2 { + return 0, true + } + if intobj1 < intobj2 { + return 1, true + } + } + case reflect.Int8: + { + int8obj1 := obj1.(int8) + int8obj2 := obj2.(int8) + if int8obj1 > int8obj2 { + return -1, true + } + if int8obj1 == int8obj2 { + return 0, true + } + if int8obj1 < int8obj2 { + return 1, true + } + } + case reflect.Int16: + { + int16obj1 := obj1.(int16) + int16obj2 := obj2.(int16) + if int16obj1 > int16obj2 { + return -1, true + } + if int16obj1 == int16obj2 { + return 0, true + } + if int16obj1 < int16obj2 { + return 1, true + } + } + case reflect.Int32: + { + int32obj1 := obj1.(int32) + int32obj2 := obj2.(int32) + if int32obj1 > int32obj2 { + return -1, true + } + if int32obj1 == int32obj2 { + return 0, true + } + if int32obj1 < int32obj2 { + return 1, true + } + } + case reflect.Int64: + { + int64obj1 := obj1.(int64) + int64obj2 := obj2.(int64) + if int64obj1 > int64obj2 { + return -1, true + } + if int64obj1 == int64obj2 { + return 0, true + } + if int64obj1 < int64obj2 { + return 1, true + } + } + case reflect.Uint: + { + uintobj1 := obj1.(uint) + uintobj2 := obj2.(uint) + if uintobj1 > uintobj2 { + return -1, true + } + if uintobj1 == uintobj2 { + return 0, true + } + if uintobj1 < uintobj2 { + return 1, true + } + } + case reflect.Uint8: + { + uint8obj1 := obj1.(uint8) + uint8obj2 := obj2.(uint8) + if uint8obj1 > uint8obj2 { + return -1, true + } + if uint8obj1 == uint8obj2 { + return 0, true + } + if uint8obj1 < uint8obj2 { + return 1, true + } + } + case reflect.Uint16: + { + uint16obj1 := obj1.(uint16) + uint16obj2 := obj2.(uint16) + if uint16obj1 > uint16obj2 { + return -1, true + } + if uint16obj1 == uint16obj2 { + return 0, true + } + if uint16obj1 < uint16obj2 { + return 1, true + } + } + case reflect.Uint32: + { + uint32obj1 := obj1.(uint32) + uint32obj2 := obj2.(uint32) + if uint32obj1 > uint32obj2 { + return -1, true + } + if uint32obj1 == uint32obj2 { + return 0, true + } + if uint32obj1 < uint32obj2 { + return 1, true + } + } + case reflect.Uint64: + { + uint64obj1 := obj1.(uint64) + uint64obj2 := obj2.(uint64) + if uint64obj1 > uint64obj2 { + return -1, true + } + if uint64obj1 == uint64obj2 { + return 0, true + } + if uint64obj1 < uint64obj2 { + return 1, true + } + } + case reflect.Float32: + { + float32obj1 := obj1.(float32) + float32obj2 := obj2.(float32) + if float32obj1 > float32obj2 { + return -1, true + } + if float32obj1 == float32obj2 { + return 0, true + } + if float32obj1 < float32obj2 { + return 1, true + } + } + case reflect.Float64: + { + float64obj1 := obj1.(float64) + float64obj2 := obj2.(float64) + if float64obj1 > float64obj2 { + return -1, true + } + if float64obj1 == float64obj2 { + return 0, true + } + if float64obj1 < float64obj2 { + return 1, true + } + } + case reflect.String: + { + stringobj1 := obj1.(string) + stringobj2 := obj2.(string) + if stringobj1 > stringobj2 { + return -1, true + } + if stringobj1 == stringobj2 { + return 0, true + } + if stringobj1 < stringobj2 { + return 1, true + } + } + } + + return 0, false +} + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + e1Kind := reflect.ValueOf(e1).Kind() + e2Kind := reflect.ValueOf(e2).Kind() + if e1Kind != e2Kind { + return Fail(t, "Elements should be the same type", msgAndArgs...) + } + + res, isComparable := compare(e1, e2, e1Kind) + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + } + + if res != -1 { + return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...) + } + + return true +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") +func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + e1Kind := reflect.ValueOf(e1).Kind() + e2Kind := reflect.ValueOf(e2).Kind() + if e1Kind != e2Kind { + return Fail(t, "Elements should be the same type", msgAndArgs...) + } + + res, isComparable := compare(e1, e2, e1Kind) + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + } + + if res != -1 && res != 0 { + return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...) + } + + return true +} + +// Less asserts that the first element is less than the second +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + e1Kind := reflect.ValueOf(e1).Kind() + e2Kind := reflect.ValueOf(e2).Kind() + if e1Kind != e2Kind { + return Fail(t, "Elements should be the same type", msgAndArgs...) + } + + res, isComparable := compare(e1, e2, e1Kind) + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + } + + if res != 1 { + return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...) + } + + return true +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") +func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + e1Kind := reflect.ValueOf(e1).Kind() + e2Kind := reflect.ValueOf(e2).Kind() + if e1Kind != e2Kind { + return Fail(t, "Elements should be the same type", msgAndArgs...) + } + + res, isComparable := compare(e1, e2, e1Kind) + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + } + + if res != 1 && res != 0 { + return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...) + } + + return true +} diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index 9bd4a80e4..044da8b01 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -18,6 +18,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/pmezard/go-difflib/difflib" + yaml "gopkg.in/yaml.v2" ) //go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl @@ -350,6 +351,37 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) } +// Same asserts that two pointers reference the same object. +// +// assert.Same(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual) + if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr { + return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...) + } + + expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual) + if expectedType != actualType { + return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v", + expectedType, actualType), msgAndArgs...) + } + + if expected != actual { + return Fail(t, fmt.Sprintf("Not same: \n"+ + "expected: %p %#v\n"+ + "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...) + } + + return true +} + // formatUnequalValues takes two values of arbitrary types and returns string // representations appropriate to be presented to the user. // @@ -479,14 +511,14 @@ func isEmpty(object interface{}) bool { // collection types are empty when they have no element case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: return objValue.Len() == 0 - // pointers are empty if nil or if the value they point to is empty + // pointers are empty if nil or if the value they point to is empty case reflect.Ptr: if objValue.IsNil() { return true } deref := objValue.Elem().Interface() return isEmpty(deref) - // for all other types, compare against the zero value + // for all other types, compare against the zero value default: zero := reflect.Zero(objValue.Type()) return reflect.DeepEqual(object, zero.Interface()) @@ -629,7 +661,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{ func includeElement(list interface{}, element interface{}) (ok, found bool) { listValue := reflect.ValueOf(list) - elementValue := reflect.ValueOf(element) + listKind := reflect.TypeOf(list).Kind() defer func() { if e := recover(); e != nil { ok = false @@ -637,11 +669,12 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) { } }() - if reflect.TypeOf(list).Kind() == reflect.String { + if listKind == reflect.String { + elementValue := reflect.ValueOf(element) return true, strings.Contains(listValue.String(), elementValue.String()) } - if reflect.TypeOf(list).Kind() == reflect.Map { + if listKind == reflect.Map { mapKeys := listValue.MapKeys() for i := 0; i < len(mapKeys); i++ { if ObjectsAreEqual(mapKeys[i].Interface(), element) { @@ -1337,6 +1370,24 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) } +// YAMLEq asserts that two YAML strings are equivalent. +func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + var expectedYAMLAsInterface, actualYAMLAsInterface interface{} + + if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...) + } + + if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...) + } + + return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...) +} + func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { t := reflect.TypeOf(v) k := t.Kind() @@ -1371,8 +1422,8 @@ func diff(expected interface{}, actual interface{}) string { e = spewConfig.Sdump(expected) a = spewConfig.Sdump(actual) } else { - e = expected.(string) - a = actual.(string) + e = reflect.ValueOf(expected).String() + a = reflect.ValueOf(actual).String() } diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ @@ -1414,3 +1465,34 @@ var spewConfig = spew.ConfigState{ type tHelper interface { Helper() } + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + timer := time.NewTimer(waitFor) + ticker := time.NewTicker(tick) + checkPassed := make(chan bool) + defer timer.Stop() + defer ticker.Stop() + defer close(checkPassed) + for { + select { + case <-timer.C: + return Fail(t, "Condition never satisfied", msgAndArgs...) + case result := <-checkPassed: + if result { + return true + } + case <-ticker.C: + go func() { + checkPassed <- condition() + }() + } + } +} diff --git a/vendor/github.com/tiramiseb/go-gandi/.gitignore b/vendor/github.com/tiramiseb/go-gandi/.gitignore new file mode 100644 index 000000000..409a1f9fd --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/.gitignore @@ -0,0 +1,2 @@ +/cmd/gandi +.idea diff --git a/vendor/github.com/tiramiseb/go-gandi/LICENSE b/vendor/github.com/tiramiseb/go-gandi/LICENSE new file mode 100644 index 000000000..f952681d1 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/LICENSE @@ -0,0 +1,7 @@ +Copyright 2017 Sébastien Maccagnoni + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/tiramiseb/go-gandi/README.md b/vendor/github.com/tiramiseb/go-gandi/README.md new file mode 100644 index 000000000..ee6801ae5 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/README.md @@ -0,0 +1,13 @@ +Gandi Go library +================ + +WIP: migrating from https://github.com/tiramiseb/go-gandi-livedns + +cmd not working, fix needed + +[![GoDoc](https://godoc.org/github.com/tiramiseb/go-gandi?status.svg)](https://godoc.org/github.com/tiramiseb/go-gandi) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/tiramiseb/go-gandi/master/LICENSE) + +This library interacts with [Gandi's API](https://api.gandi.net/docs/), to manage Gandi services. This API returns some data as HTTP headers, please note those are ignored by this library. + +A simple CLI is also shipped with this library. It returns responses to the requests in JSON. diff --git a/vendor/github.com/tiramiseb/go-gandi/domain/domain.go b/vendor/github.com/tiramiseb/go-gandi/domain/domain.go new file mode 100644 index 000000000..3e236694f --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/domain/domain.go @@ -0,0 +1,166 @@ +package domain + +import ( + "time" + + "github.com/tiramiseb/go-gandi/internal/client" +) + +type Domain struct { + client client.Gandi +} + +func New(apikey string, sharingid string, debug bool) *Domain { + client := client.New(apikey, sharingid, debug) + client.SetEndpoint("domain/") + return &Domain{client: *client} +} + +func NewFromClient(g client.Gandi) *Domain { + g.SetEndpoint("domain/") + return &Domain{client: g} +} + +// Contact represents a contact associated with a domain +type Contact struct { + Country string `json:"country"` + Email string `json:"email"` + Family string `json:"family"` + Given string `json:"given"` + StreetAddr string `json:"streetaddr"` + ContactType int `json:"type"` + BrandNumber string `json:"brand_number,omitempty"` + City string `json:"city,omitempty"` + DataObfuscated *bool `json:"data_obfuscated,omitempty"` + Fax string `json:"fax,omitempty"` + Language string `json:"lang,omitempty"` + MailObfuscated *bool `json:"mail_obfuscated,omitempty"` + Mobile string `json:"mobile,omitempty"` + OrgName string `json:"orgname,omitempty"` + Phone string `json:"phone,omitempty"` + Siren string `json:"siren,omitempty"` + State string `json:"state,omitempty"` + Validation string `json:"validation,omitempty"` + Zip string `json:"zip,omitempty"` +} + +// DomainResponseDates represents all the dates associated with a domain +type DomainResponseDates struct { + RegistryCreatedAt time.Time `json:"registry_created_at"` + UpdatedAt time.Time `json:"updated_at"` + AuthInfoExpiresAt time.Time `json:"authinfo_expires_at,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty"` + DeletesAt time.Time `json:"deletes_at,omitempty"` + HoldBeginsAt time.Time `json:"hold_begins_at,omitempty"` + HoldEndsAt time.Time `json:"hold_ends_at,omitempty"` + PendingDeleteEndsAt time.Time `json:"pending_delete_ends_at,omitempty"` + RegistryEndsAt time.Time `json:"registry_ends_at,omitempty"` + RenewBeginsAt time.Time `json:"renew_begins_at,omitempty"` + RenewEndsAt time.Time `json:"renew_ends_at,omitempty"` +} + +// NameServerConfig represents the name server configuration for a domain +type NameServerConfig struct { + Current string `json:"current"` + Hosts []string `json:"hosts,omitempty"` +} + +// DomainListResponse is the response object returned by listing domains +type DomainListResponse struct { + AutoRenew *bool `json:"autorenew"` + Dates DomainResponseDates `json:"dates"` + DomainOwner string `json:"domain_owner"` + FQDN string `json:"fqdn"` + FQDNUnicode string `json:"fqdn_unicode"` + Href string `json:"href"` + ID string `json:"id"` + NameServer NameServerConfig `json:"nameserver"` + OrgaOwner string `json:"orga_owner"` + Owner string `json:"owner"` + Status []string `json:"status"` + TLD string `json:"tld"` + SharingID string `json:"sharing_id,omitempty"` + Tags []string `json:"tags,omitempty"` +} + +// AutoRenew is the auto renewal information for the domain +type AutoRenew struct { + Href string `json:"href"` + Dates []time.Time `json:"dates,omitempty"` + Duration int `json:"duration,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + OrgID string `json:"org_id,omitempty"` +} + +// The Organisation that owns the domain +type SharingSpace struct { + ID string `json:"id"` + Name string `json:"name"` +} + +// DomainResponse describes a single domain +type DomainResponse struct { + AutoRenew AutoRenew `json:"autorenew"` + CanTLDLock *bool `json:"can_tld_lock"` + Contacts DomainContacts `json:"contacts"` + Dates DomainResponseDates `json:"dates"` + FQDN string `json:"fqdn"` + FQDNUnicode string `json:"fqdn_unicode"` + Href string `json:"href"` + Nameservers []string `json:"nameservers,omitempty"` + Services []string `json:"services"` + SharingSpace SharingSpace `json:"sharing_space"` + Status []string `json:"status"` + TLD string `json:"tld"` + AuthInfo string `json:"authinfo,omitempty"` + ID string `json:"id,omitempty"` + SharingID string `json:"sharing_id,omitempty"` + Tags []string `json:"tags,omitempty"` + TrusteeRoles []string `json:"trustee_roles,omitempty"` +} + +// DomainContacts is the set of contacts associated with a Domain +type DomainContacts struct { + Admin Contact `json:"admin,omitempty"` + Bill Contact `json:"bill,omitempty"` + Owner Contact `json:"owner,omitempty"` + Tech Contact `json:"tech,omitempty"` +} + +// Nameservers represents a list of nameservers +type Nameservers struct { + Nameservers []string `json:"nameservers,omitempty"` +} + +func (g *Domain) ListDomains() (domains []DomainListResponse, err error) { + _, err = g.client.Get("domains", nil, &domains) + return +} + +func (g *Domain) GetDomain(domain string) (domainResponse DomainResponse, err error) { + _, err = g.client.Get("domains/"+domain, nil, &domainResponse) + return +} + +func (g *Domain) GetNameServers(domain string) (nameservers []string, err error) { + _, err = g.client.Get("domains/"+domain+"/nameservers", nil, &nameservers) + return +} + +// UpdateNameServers sets the list of the nameservers for a domain +func (g *Domain) UpdateNameServers(domain string, ns []string) (err error) { + _, err = g.client.Put("domains/"+domain+"/nameservers", Nameservers{ns}, nil) + return +} + +// GetContacts returns the contact objects for a domain +func (g *Domain) GetContacts(domain string) (contacts DomainContacts, err error) { + _, err = g.client.Get("domains/"+domain+"/contacts", nil, &contacts) + return +} + +// SetContacts returns the contact objects for a domain +func (g *Domain) SetContacts(domain string, contacts DomainContacts) (err error) { + _, err = g.client.Patch("domains/"+domain+"/contacts", contacts, nil) + return +} diff --git a/vendor/github.com/tiramiseb/go-gandi/gandi.go b/vendor/github.com/tiramiseb/go-gandi/gandi.go new file mode 100644 index 000000000..c62573100 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/gandi.go @@ -0,0 +1,19 @@ +package gandi + +import ( + "github.com/tiramiseb/go-gandi/domain" + "github.com/tiramiseb/go-gandi/livedns" +) + +type Config struct { + SharingID string + Debug bool +} + +func NewDomainClient(apikey string, config Config) *domain.Domain { + return domain.New(apikey, config.SharingID, config.Debug) +} + +func NewLiveDNSClient(apikey string, config Config) *livedns.LiveDNS { + return livedns.New(apikey, config.SharingID, config.Debug) +} diff --git a/vendor/github.com/tiramiseb/go-gandi/go.mod b/vendor/github.com/tiramiseb/go-gandi/go.mod new file mode 100644 index 000000000..6b395832c --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/go.mod @@ -0,0 +1,9 @@ +module github.com/tiramiseb/go-gandi + +go 1.13 + +require ( + github.com/alecthomas/kingpin v2.2.6+incompatible + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect + github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect +) diff --git a/vendor/github.com/tiramiseb/go-gandi/go.sum b/vendor/github.com/tiramiseb/go-gandi/go.sum new file mode 100644 index 000000000..604ebee99 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/go.sum @@ -0,0 +1,13 @@ +github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/tiramiseb/go-gandi-livedns v0.0.0-20200115114823-77cf002f44da h1:8yQIyyxIjektbd5aNbi9BZadosFjU3Xg3imyTS6fUcM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/tiramiseb/go-gandi/internal/client/gandi.go b/vendor/github.com/tiramiseb/go-gandi/internal/client/gandi.go new file mode 100644 index 000000000..eb082d3c3 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/internal/client/gandi.go @@ -0,0 +1,157 @@ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/http/httputil" + "strings" +) + +const ( + gandiEndpoint = "https://api.gandi.net/v5/" +) + +// Gandi is the handle used to interact with the Gandi API +type Gandi struct { + apikey string + endpoint string + sharingID string + debug bool +} + +// New instantiates a new Gandi instance +func New(apikey string, sharingID string, debug bool) *Gandi { + return &Gandi{apikey: apikey, endpoint: gandiEndpoint, sharingID: sharingID, debug: debug} +} + +func (g *Gandi) SetEndpoint(endpoint string) { + g.endpoint = gandiEndpoint + endpoint +} + +func (g *Gandi) Get(path string, params, recipient interface{}) (http.Header, error) { + return g.askGandi(http.MethodGet, path, params, recipient) +} + +func (g *Gandi) Post(path string, params, recipient interface{}) (http.Header, error) { + return g.askGandi(http.MethodPost, path, params, recipient) +} + +func (g *Gandi) Patch(path string, params, recipient interface{}) (http.Header, error) { + return g.askGandi(http.MethodPatch, path, params, recipient) +} + +func (g *Gandi) Delete(path string, params, recipient interface{}) (http.Header, error) { + return g.askGandi(http.MethodDelete, path, params, recipient) +} + +func (g *Gandi) Put(path string, params, recipient interface{}) (http.Header, error) { + return g.askGandi(http.MethodPut, path, params, recipient) +} + +func (g *Gandi) askGandi(method, path string, params, recipient interface{}) (http.Header, error) { + resp, err := g.doAskGandi(method, path, params, nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + decoder := json.NewDecoder(resp.Body) + decoder.Decode(recipient) + return resp.Header, nil +} + +func (g *Gandi) GetBytes(path string, params interface{}) (http.Header, []byte, error) { + headers := [][2]string{ + {"Accept", "text/plain"}, + } + resp, err := g.doAskGandi(http.MethodGet, path, params, headers) + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + content, err := ioutil.ReadAll(resp.Body) + return resp.Header, content, err +} + +func (g *Gandi) doAskGandi(method, path string, p interface{}, extraHeaders [][2]string) (*http.Response, error) { + var ( + err error + req *http.Request + ) + params, err := json.Marshal(p) + if err != nil { + return nil, err + } + client := &http.Client{} + suffix := "" + if len(g.sharingID) != 0 { + suffix += "?sharing_id=" + g.sharingID + } + if params != nil && string(params) != "null" { + req, err = http.NewRequest(method, g.endpoint+path+suffix, bytes.NewReader(params)) + } else { + req, err = http.NewRequest(method, g.endpoint+path+suffix, nil) + } + if err != nil { + return nil, err + } + req.Header.Add("Authorization", "Apikey "+g.apikey) + req.Header.Add("Content-Type", "application/json") + for _, header := range extraHeaders { + req.Header.Add(header[0], header[1]) + } + if g.debug { + dump, _ := httputil.DumpRequestOut(req, true) + fmt.Println("=======================================\nREQUEST:") + fmt.Println(string(dump)) + } + resp, err := client.Do(req) + if err != nil { + return resp, err + } + if g.debug { + dump, _ := httputil.DumpResponse(resp, true) + fmt.Println("=======================================\nREQUEST:") + fmt.Println(string(dump)) + } + if resp.StatusCode < 200 || resp.StatusCode > 299 { + defer resp.Body.Close() + var message StandardResponse + defer resp.Body.Close() + decoder := json.NewDecoder(resp.Body) + decoder.Decode(&message) + if message.Message != "" { + err = fmt.Errorf("%d: %s", resp.StatusCode, message.Message) + } else if len(message.Errors) > 0 { + var errors []string + for _, oneError := range message.Errors { + errors = append(errors, fmt.Sprintf("%s: %s", oneError.Name, oneError.Description)) + } + err = fmt.Errorf(strings.Join(errors, ", ")) + } else { + err = fmt.Errorf("%d", resp.StatusCode) + + } + } + return resp, err +} + +// StandardResponse is a standard response +type StandardResponse struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` + UUID string `json:"uuid,omitempty"` + Object string `json:"object,omitempty"` + Cause string `json:"cause,omitempty"` + Status string `json:"status,omitempty"` + Errors []StandardError `json:"errors,omitempty"` +} + +// StandardError is embedded in a standard error +type StandardError struct { + Location string `json:"location"` + Name string `json:"name"` + Description string `json:"description"` +} diff --git a/vendor/github.com/tiramiseb/go-gandi/livedns/axfr.go b/vendor/github.com/tiramiseb/go-gandi/livedns/axfr.go new file mode 100644 index 000000000..e92237e7a --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/livedns/axfr.go @@ -0,0 +1,76 @@ +package livedns + +// Tsig contains tsig data (no kidding!) +type Tsig struct { + KeyName string `json:"key_name, omitempty"` + Secret string `json:"secret,omitempty"` + UUID string `json:"uuid,omitempty"` + AxfrTsigURL string `json:"axfr_tsig_url,omitempty"` + ConfigSamples interface{} `json:"config_samples,omitempty"` +} + +// ListTsigs lists all tsigs +func (g *LiveDNS) ListTsigs() (tsigs []Tsig, err error) { + _, err = g.client.Get("axfr/tsig", nil, &tsigs) + return +} + +// GetTsig lists more tsig details +func (g *LiveDNS) GetTsig(uuid string) (tsig Tsig, err error) { + _, err = g.client.Get("axfr/tsig/"+uuid, nil, &tsig) + return +} + +// GetTsigBIND shows a BIND nameserver config, and includes the nameservers available for zone transfers +func (g *LiveDNS) GetTsigBIND(uuid string) ([]byte, error) { + _, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/bind", nil) + return content, err +} + +// GetTsigPowerDNS shows a PowerDNS nameserver config, and includes the nameservers available for zone transfers +func (g *LiveDNS) GetTsigPowerDNS(uuid string) ([]byte, error) { + _, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/powerdns", nil) + return content, err +} + +// GetTsigNSD shows a NSD nameserver config, and includes the nameservers available for zone transfers +func (g *LiveDNS) GetTsigNSD(uuid string) ([]byte, error) { + _, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/nsd", nil) + return content, err +} + +// GetTsigKnot shows a Knot nameserver config, and includes the nameservers available for zone transfers +func (g *LiveDNS) GetTsigKnot(uuid string) ([]byte, error) { + _, content, err := g.client.GetBytes("axfr/tsig/"+uuid+"/config/knot", nil) + return content, err +} + +// CreateTsig creates a tsig +func (g *LiveDNS) CreateTsig() (tsig Tsig, err error) { + _, err = g.client.Post("axfr/tsig", nil, &tsig) + return +} + +// AddTsigToDomain adds a tsig to a domain +func (g *LiveDNS) AddTsigToDomain(fqdn, uuid string) (err error) { + _, err = g.client.Put("domains/"+fqdn+"/axfr/tsig/"+uuid, nil, nil) + return +} + +// AddSlaveToDomain adds a slave to a domain +func (g *LiveDNS) AddSlaveToDomain(fqdn, host string) (err error) { + _, err = g.client.Put("domains/"+fqdn+"/axfr/slaves/"+host, nil, nil) + return +} + +// ListSlavesInDomain lists slaves in a domain +func (g *LiveDNS) ListSlavesInDomain(fqdn string) (slaves []string, err error) { + _, err = g.client.Get("domains/"+fqdn+"/axfr/slaves", nil, &slaves) + return +} + +// DelSlaveFromDomain removes a slave from a domain +func (g *LiveDNS) DelSlaveFromDomain(fqdn, host string) (err error) { + _, err = g.client.Delete("domains/"+fqdn+"/axfr/slaves/"+host, nil, nil) + return +} diff --git a/vendor/github.com/tiramiseb/go-gandi/livedns/domain.go b/vendor/github.com/tiramiseb/go-gandi/livedns/domain.go new file mode 100644 index 000000000..e8d854452 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/livedns/domain.go @@ -0,0 +1,101 @@ +package livedns + +import "github.com/tiramiseb/go-gandi/internal/client" + +// Domain represents a DNS domain +type Domain struct { + FQDN string `json:"fqdn,omitempty"` + DomainHref string `json:"domain_href,omitempty"` + DomainKeysHref string `json:"domain_keys_href,omitempty"` + DomainRecordsHref string `json:"domain_records_href,omitempty"` + ZoneUUID string `json:"zone_uuid,omitempty"` + ZoneHref string `json:"zone_href,omitempty"` + ZoneRecordsHref string `json:"zone_records_href,omitempty"` +} + +// SigningKey holds data about a DNSSEC signing key +type SigningKey struct { + Status string `json:"status,omitempty"` + UUID string `json:"uuid,omitempty"` + Algorithm int `json:"algorithm,omitempty"` + Deleted *bool `json:"deleted"` + AlgorithmName string `json:"algorithm_name,omitempty"` + FQDN string `json:"fqdn,omitempty"` + Flags int `json:"flags,omitempty"` + DS string `json:"ds,omitempty"` + KeyHref string `json:"key_href,omitempty"` +} + +type zone struct { + TTL int `json:"ttl"` +} + +type createDomainRequest struct { + FQDN string `json:"fqdn"` + Zone zone `json:"zone,omitempty"` +} + +type UpdateDomainRequest struct { + AutomaticSnapshots *bool `json:"automatic_snapshots,omitempty"` +} + +// ListDomains lists all domains +func (g *LiveDNS) ListDomains() (domains []Domain, err error) { + _, err = g.client.Get("domains", nil, &domains) + return +} + +// CreateDomain adds a domain to a zone +func (g *LiveDNS) CreateDomain(fqdn string, ttl int) (response client.StandardResponse, err error) { + _, err = g.client.Post("domains", createDomainRequest{FQDN: fqdn, Zone: zone{TTL: ttl}}, &response) + return +} + +// GetDomain returns a domain +func (g *LiveDNS) GetDomain(fqdn string) (domain Domain, err error) { + _, err = g.client.Get("domains/"+fqdn, nil, &domain) + return +} + +// ChangeAssociatedZone changes the zone associated to a domain +func (g *LiveDNS) UpdateDomain(fqdn string, details UpdateDomainRequest) (response client.StandardResponse, err error) { + _, err = g.client.Patch("domains/"+fqdn, details, &response) + return +} + +// DetachDomain detaches a domain from the zone it is attached to +func (g *LiveDNS) DetachDomain(fqdn string) (err error) { + _, err = g.client.Delete("domains/"+fqdn, nil, nil) + return +} + +// SignDomain creates a DNSKEY and asks Gandi servers to automatically sign the domain +func (g *LiveDNS) SignDomain(fqdn string) (response client.StandardResponse, err error) { + f := SigningKey{Flags: 257} + _, err = g.client.Post("domains/"+fqdn+"/keys", f, &response) + return +} + +// GetDomainKeys returns data about the signing keys created for a domain +func (g *LiveDNS) GetDomainKeys(fqdn string) (keys []SigningKey, err error) { + _, err = g.client.Get("domains/"+fqdn+"/keys", nil, &keys) + return +} + +// DeleteDomainKey deletes a signing key from a domain +func (g *LiveDNS) DeleteDomainKey(fqdn, uuid string) (err error) { + _, err = g.client.Delete("domains/"+fqdn+"/keys/"+uuid, nil, nil) + return +} + +// UpdateDomainKey updates a signing key for a domain (only the deleted status, actually...) +func (g *LiveDNS) UpdateDomainKey(fqdn, uuid string, deleted bool) (err error) { + _, err = g.client.Put("domains/"+fqdn+"/keys/"+uuid, SigningKey{Deleted: &deleted}, nil) + return +} + +// GetDomainNS returns the list of the nameservers for a domain +func (g *LiveDNS) GetDomainNS(fqdn string) (ns []string, err error) { + _, err = g.client.Get("nameservers/"+fqdn, nil, &ns) + return +} diff --git a/vendor/github.com/tiramiseb/go-gandi/livedns/domainrecord.go b/vendor/github.com/tiramiseb/go-gandi/livedns/domainrecord.go new file mode 100644 index 000000000..e9be7bc81 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/livedns/domainrecord.go @@ -0,0 +1,97 @@ +package livedns + +import "github.com/tiramiseb/go-gandi/internal/client" + +// DomainRecord represents a DNS Record +type DomainRecord struct { + RrsetType string `json:"rrset_type,omitempty"` + RrsetTTL int `json:"rrset_ttl,omitempty"` + RrsetName string `json:"rrset_name,omitempty"` + RrsetHref string `json:"rrset_href,omitempty"` + RrsetValues []string `json:"rrset_values,omitempty"` +} + +// ListDomainRecords lists all records in the zone associated with a domain +func (g *LiveDNS) ListDomainRecords(fqdn string) (records []DomainRecord, err error) { + _, err = g.client.Get("domains/"+fqdn+"/records", nil, &records) + return +} + +// ListDomainRecordsAsText lists all records in a zone and returns them as a text file +// ... and by text, I mean a slice of bytes +func (g *LiveDNS) ListDomainRecordsAsText(uuid string) ([]byte, error) { + _, content, err := g.client.GetBytes("domains/"+uuid+"/records", nil) + return content, err +} + +// ListDomainRecordsWithName lists all records with a specific name in a zone +func (g *LiveDNS) ListDomainRecordsWithName(fqdn, name string) (records []DomainRecord, err error) { + _, err = g.client.Get("domains/"+fqdn+"/records/"+name, nil, &records) + return +} + +// GetDomainRecordWithNameAndType gets the record with specific name and type in the zone attached to the domain +func (g *LiveDNS) GetDomainRecordWithNameAndType(fqdn, name, recordtype string) (record DomainRecord, err error) { + _, err = g.client.Get("domains/"+fqdn+"/records/"+name+"/"+recordtype, nil, &record) + return +} + +// CreateDomainRecord creates a record in the zone attached to a domain +func (g *LiveDNS) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response client.StandardResponse, err error) { + _, err = g.client.Post("domains/"+fqdn+"/records", + DomainRecord{ + RrsetType: recordtype, + RrsetTTL: ttl, + RrsetName: name, + RrsetValues: values, + }, + &response) + return +} + +type itemsPrefixForZoneRecords struct { + Items []DomainRecord `json:"items"` +} + +// ChangeDomainRecords changes all records in the zone attached to a domain +func (g *LiveDNS) ChangeDomainRecords(fqdn string, records []DomainRecord) (response client.StandardResponse, err error) { + prefixedRecords := itemsPrefixForZoneRecords{Items: records} + _, err = g.client.Put("domains/"+fqdn+"/records", prefixedRecords, &response) + return +} + +// ChangeDomainRecordsWithName changes all records with the given name in the zone attached to the domain +func (g *LiveDNS) ChangeDomainRecordsWithName(fqdn, name string, records []DomainRecord) (response client.StandardResponse, err error) { + prefixedRecords := itemsPrefixForZoneRecords{Items: records} + _, err = g.client.Put("domains/"+fqdn+"/records/"+name, prefixedRecords, &response) + return +} + +// ChangeDomainRecordWithNameAndType changes the record with the given name and the given type in the zone attached to a domain +func (g *LiveDNS) ChangeDomainRecordWithNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response client.StandardResponse, err error) { + _, err = g.client.Put("domains/"+fqdn+"/records/"+name+"/"+recordtype, + DomainRecord{ + RrsetTTL: ttl, + RrsetValues: values, + }, + &response) + return +} + +// DeleteAllDomainRecords deletes all records in the zone attached to a domain +func (g *LiveDNS) DeleteAllDomainRecords(fqdn string) (err error) { + _, err = g.client.Delete("domains/"+fqdn+"/records", nil, nil) + return +} + +// DeleteDomainRecords deletes all records with the given name in the zone attached to a domain +func (g *LiveDNS) DeleteDomainRecords(fqdn, name string) (err error) { + _, err = g.client.Delete("domains/"+fqdn+"/records/"+name, nil, nil) + return +} + +// DeleteDomainRecord deletes the record with the given name and the given type in the zone attached to a domain +func (g *LiveDNS) DeleteDomainRecord(fqdn, name, recordtype string) (err error) { + _, err = g.client.Delete("domains/"+fqdn+"/records/"+name+"/"+recordtype, nil, nil) + return +} diff --git a/vendor/github.com/tiramiseb/go-gandi/livedns/livedns.go b/vendor/github.com/tiramiseb/go-gandi/livedns/livedns.go new file mode 100644 index 000000000..98ab4d29e --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/livedns/livedns.go @@ -0,0 +1,20 @@ +package livedns + +import ( + "github.com/tiramiseb/go-gandi/internal/client" +) + +type LiveDNS struct { + client client.Gandi +} + +func New(apikey string, sharingid string, debug bool) *LiveDNS { + client := client.New(apikey, sharingid, debug) + client.SetEndpoint("livedns/") + return &LiveDNS{client: *client} +} + +func NewFromClient(g client.Gandi) *LiveDNS { + g.SetEndpoint("livedns/") + return &LiveDNS{client: g} +} diff --git a/vendor/github.com/tiramiseb/go-gandi/livedns/snapshot.go b/vendor/github.com/tiramiseb/go-gandi/livedns/snapshot.go new file mode 100644 index 000000000..36c9c3e28 --- /dev/null +++ b/vendor/github.com/tiramiseb/go-gandi/livedns/snapshot.go @@ -0,0 +1,29 @@ +package livedns + +import "github.com/tiramiseb/go-gandi/internal/client" + +// Snapshot represents a zone snapshot +type Snapshot struct { + UUID string `json:"uuid,omitempty"` + DateCreated string `json:"date_created,omitempty"` + ZoneUUID string `json:"zone_uuid,omitempty"` + ZoneData []DomainRecord `json:"zone_data,omitempty"` +} + +// ListSnapshots lists all domains +func (g *LiveDNS) ListSnapshots(fqdn string) (snapshots []Snapshot, err error) { + _, err = g.client.Get("domains/"+fqdn+"/snapshots", nil, &snapshots) + return +} + +// CreateSnapshot creates a domain +func (g *LiveDNS) CreateSnapshot(fqdn string) (response client.StandardResponse, err error) { + _, err = g.client.Post("domains/"+fqdn+"/snapshots", nil, &response) + return +} + +// GetSnapshot returns a domain +func (g *LiveDNS) GetSnapshot(fqdn, snapUUID string) (snapshot Snapshot, err error) { + _, err = g.client.Get("domains/"+fqdn+"/snapshots/"+snapUUID, nil, &snapshot) + return +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1b1fd27dd..992fffa88 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -217,7 +217,7 @@ github.com/softlayer/softlayer-go/filter github.com/softlayer/softlayer-go/services github.com/softlayer/softlayer-go/session github.com/softlayer/softlayer-go/sl -# github.com/stretchr/testify v1.3.0 +# github.com/stretchr/testify v1.4.0 github.com/stretchr/testify/assert # github.com/tdewolff/buffer v2.0.0+incompatible github.com/tdewolff/buffer @@ -230,6 +230,11 @@ github.com/tdewolff/parse/buffer github.com/tdewolff/parse/json # github.com/tdewolff/strconv v1.0.0 github.com/tdewolff/strconv +# github.com/tiramiseb/go-gandi v0.0.0-20200119104052-d61de35bb043 +github.com/tiramiseb/go-gandi +github.com/tiramiseb/go-gandi/domain +github.com/tiramiseb/go-gandi/internal/client +github.com/tiramiseb/go-gandi/livedns # github.com/urfave/cli v1.20.1-0.20180106191048-75104e932ac2 github.com/urfave/cli # github.com/vultr/govultr v0.1.7