mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Release 3.0.0 Candidate (#699)
Final changes before V3.0.0 release * Remove old Gandi. Fixes #575 * Many cleanups * go mod tidy && go mod vendor * integration_test.go: Output subtest name * Cleanups * integration_test.go: Description should include sub-test name * Add a whitespace test to js/parse_tests/017-txt.js * Cloudflare strips whitespace from end of TXT * Fixes https://github.com/StackExchange/dnscontrol/issues/700 * Whitespace at end of TXT records Name.com strips the whitespace from the end of a TXT record. There's nothing we can do other than file a bug. * Fixes https://github.com/StackExchange/dnscontrol/issues/701
This commit is contained in:
2
OWNERS
2
OWNERS
@ -5,7 +5,7 @@ providers/bind @tlimoncelli
|
||||
providers/cloudns @pragmaton
|
||||
providers/digitalocean @Deraen
|
||||
providers/dnsimple @aeden
|
||||
providers/gandi @TomOnTime
|
||||
providers/gandi_v5 @TomOnTime
|
||||
# providers/gcloud
|
||||
providers/hexonet @papakai
|
||||
providers/internetbs @pragmaton
|
||||
|
@ -62,14 +62,14 @@ jobs:
|
||||
DO_DOMAIN: $(DO_DOMAIN)
|
||||
DO_TOKEN: $(DO_TOKEN)
|
||||
|
||||
- job: Gandi
|
||||
- job: GandiV5
|
||||
steps:
|
||||
- template: go-env.yaml
|
||||
- script: go test -v -verbose -provider GANDI
|
||||
- script: go test -v -verbose -provider GANDI_V5
|
||||
workingDirectory: $(wd)
|
||||
env:
|
||||
GANDI_KEY: $(GANDI_KEY)
|
||||
GANDI_DOMAIN: $(GANDI_DOMAIN)
|
||||
GANDI_KEY: $(GANDI_V5_APIKEY)
|
||||
GANDI_DOMAIN: $(GANDI_V5_DOMAIN)
|
||||
|
||||
# - job: GandiLive
|
||||
# steps:
|
||||
|
@ -14,8 +14,6 @@
|
||||
<th class="rotate"><div><span>DIGITALOCEAN</span></div></th>
|
||||
<th class="rotate"><div><span>DNSIMPLE</span></div></th>
|
||||
<th class="rotate"><div><span>EXOSCALE</span></div></th>
|
||||
<th class="rotate"><div><span>GANDI</span></div></th>
|
||||
<th class="rotate"><div><span>GANDI-LIVEDNS</span></div></th>
|
||||
<th class="rotate"><div><span>GANDI_V5</span></div></th>
|
||||
<th class="rotate"><div><span>GCLOUD</span></div></th>
|
||||
<th class="rotate"><div><span>HEXONET</span></div></th>
|
||||
|
@ -1,58 +0,0 @@
|
||||
---
|
||||
name: Gandi
|
||||
title: Gandi Provider
|
||||
layout: default
|
||||
jsId: GANDI
|
||||
---
|
||||
# Gandi Provider
|
||||
|
||||
There are two providers for Gandi:
|
||||
|
||||
1. `GANDI` uses the v3 API and is able to act as a registrar provider
|
||||
and a DNS provider. It is not able to handle domains that have
|
||||
migrated to the new LiveDNS API. You need to get the API key from
|
||||
the [v4 interface][].
|
||||
|
||||
2. `GANDI-LIVEDNS` uses the LiveDNS API and is only able to act as a
|
||||
DNS provider. You need to get the API key from the [v5 interface][].
|
||||
|
||||
[v4 interface]: https://v4.gandi.net
|
||||
[v5 interface]: https://v5.gandi.net
|
||||
|
||||
## Configuration
|
||||
In your credentials file you must provide your Gandi.net API key:
|
||||
|
||||
{% highlight json %}
|
||||
{
|
||||
"gandi": {
|
||||
"apikey": "your-gandi-key"
|
||||
}
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
## Metadata
|
||||
This provider does not recognize any special metadata fields unique to Gandi.
|
||||
|
||||
## Usage
|
||||
Example Javascript:
|
||||
|
||||
{% highlight js %}
|
||||
var GANDI = NewDnsProvider("gandi", "GANDI");
|
||||
var REG_GANDI = NewRegistrar("gandi", "GANDI");
|
||||
|
||||
D("example.tld", REG_GANDI, DnsProvider(GANDI),
|
||||
A("test","1.2.3.4")
|
||||
);
|
||||
{% endhighlight %}
|
||||
|
||||
## 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 control panel manually.
|
||||
|
||||
|
||||
## Common errors
|
||||
|
||||
This is the error we see when someone uses GANDI instead of GANDI-LIVEDNS.
|
||||
|
||||
```
|
||||
Error getting corrections: error: "Error on object : OBJECT_ZONE (CAUSE_NOTFOUND) [no such zone (id: 0)]" code: 581042
|
||||
```
|
@ -2,7 +2,7 @@
|
||||
name: Gandi_v5
|
||||
title: Gandi_v5 Provider
|
||||
layout: default
|
||||
jsId: GANDI
|
||||
jsId: GANDI_V5
|
||||
---
|
||||
# Gandi_v5 Provider
|
||||
|
||||
|
@ -125,9 +125,9 @@ jq:
|
||||
|
||||
jq < creds.json
|
||||
|
||||
FYI: `creds.json` fields can be an environment variable. The field must begin with a `$` followed by the variable name. No other text. For example:
|
||||
FYI: `creds.json` fields can be read from an environment variable. The field must begin with a `$` followed by the variable name. No other text. For example:
|
||||
|
||||
"apiuser": "$GANDI_APIUSER",
|
||||
"apikey": "$GANDI_V5_APIKEY",
|
||||
|
||||
## 5. Test the sample files.
|
||||
|
||||
|
@ -76,8 +76,6 @@ Maintainers of contributed providers:
|
||||
* `DNSIMPLE` @aeden
|
||||
* `EXOSCALE` @pierre-emmanuelJ
|
||||
* `GANDI_V5` @TomOnTime
|
||||
* `GANDI-LIVEDNS` (going away in 3.0)
|
||||
* `GANDI` (going away in 3.0)
|
||||
* `HEXONET` @papakai
|
||||
* `INTERNETBS` @pragmaton
|
||||
* `LINODE` @koesie10
|
||||
|
3
go.mod
3
go.mod
@ -25,20 +25,17 @@ require (
|
||||
github.com/google/go-cmp v0.4.0 // 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/api v1.0.4
|
||||
github.com/hexonet/go-sdk v2.2.3+incompatible
|
||||
github.com/jarcoal/httpmock v1.0.4 // indirect
|
||||
github.com/jmespath/go-jmespath v0.0.0-20200310193758-2437e8417af5 // indirect
|
||||
github.com/kolo/xmlrpc v0.0.0-20150413191830-0826b98aaa29 // indirect
|
||||
github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8 // indirect
|
||||
github.com/miekg/dns v1.1.27
|
||||
github.com/mjibson/esc v0.2.0
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014
|
||||
github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d
|
||||
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-20191219234010-c382bd3c16ff
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -112,8 +112,6 @@ github.com/google/go-querystring v1.0.1-0.20190318165438-c8c88dbee036/go.mod h1:
|
||||
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/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 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
@ -166,8 +164,6 @@ github.com/jmespath/go-jmespath v0.0.0-20200310193758-2437e8417af5/go.mod h1:9Qt
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
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/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/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.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@ -206,8 +202,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
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/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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
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=
|
||||
|
@ -139,7 +139,7 @@ func testPermitted(t *testing.T, p string, f TestGroup) error {
|
||||
func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.DomainConfig, tst *TestCase, desc string, expectChanges bool, origConfig map[string]string) bool {
|
||||
domainName := dc.Name
|
||||
|
||||
return t.Run(desc, func(t *testing.T) {
|
||||
return t.Run(desc+":"+tst.Desc, func(t *testing.T) {
|
||||
dom, _ := dc.Copy()
|
||||
for _, r := range tst.Records {
|
||||
rc := models.RecordConfig(*r)
|
||||
@ -631,12 +631,18 @@ func makeTests(t *testing.T) []*TestGroup {
|
||||
tc("Change a TXT", txt("foo", "changed")),
|
||||
clear(),
|
||||
tc("Create a TXT with spaces", txt("foo", "with spaces")),
|
||||
tc("Change a TXT with spaces", txt("foo", "with whitespace ")),
|
||||
tc("Create 1 TXT as array", txtmulti("foo", []string{"simple"})),
|
||||
clear(),
|
||||
tc("Create a 255-byte TXT", txt("foo", strings.Repeat("A", 255))),
|
||||
),
|
||||
|
||||
testgroup("ws TXT",
|
||||
not("CLOUDFLAREAPI", "NAMEDOTCOM"),
|
||||
// These providers strip whitespace at the end of TXT records.
|
||||
// TODO(tal): Add a check for this in normalize/validate.go
|
||||
tc("Change a TXT with ws at end", txt("foo", "with space at end ")),
|
||||
),
|
||||
|
||||
testgroup("empty TXT", not("DNSIMPLE", "CLOUDFLAREAPI"),
|
||||
tc("TXT with empty str", txt("foo1", "")),
|
||||
// https://github.com/StackExchange/dnscontrol/issues/598
|
||||
@ -676,10 +682,10 @@ func makeTests(t *testing.T) []*TestGroup {
|
||||
testgroup("page size",
|
||||
// Tests the paging code of providers. Many providers page at 100.
|
||||
// Notes:
|
||||
// - gandi: page size is 100, therefore we test with 99, 100, and 101
|
||||
// - ns1: free acct only allows 50 records, therefore we skip
|
||||
// - digitalocean: fails due to rate limiting, not page limits.
|
||||
not("NS1"),
|
||||
// - Gandi: page size is 100, therefore we test with 99, 100, and 101
|
||||
// - NS1: free acct only allows 50 records, therefore we skip
|
||||
// - DigitalOcean: fails due to rate limiting, not page limits.
|
||||
not("NS1", "DIGITALOCEAN"),
|
||||
tc("99 records", manyA("rec%04d", "1.2.3.4", 99)...),
|
||||
tc("100 records", manyA("rec%04d", "1.2.3.4", 100)...),
|
||||
tc("101 records", manyA("rec%04d", "1.2.3.4", 101)...),
|
||||
@ -745,7 +751,7 @@ func makeTests(t *testing.T) []*TestGroup {
|
||||
tc("Change Weight", srv("_sip._tcp", 52, 62, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
||||
tc("Change Port", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
|
||||
),
|
||||
testgroup("SRV w/ null target", not("NAMEDOTCOM", "HEXONET", "EXOSCALE"),
|
||||
testgroup("SRV w/ null target", not("EXOSCALE", "HEXONET", "NAMEDOTCOM"),
|
||||
tc("Null Target", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, ".")),
|
||||
),
|
||||
|
||||
|
@ -33,7 +33,6 @@
|
||||
"token": "$DO_TOKEN"
|
||||
},
|
||||
"DNSIMPLE": {
|
||||
"COMMENT": "20-22: no ns records managable. Not even for subdomains.",
|
||||
"baseurl": "https://api.sandbox.dnsimple.com",
|
||||
"domain": "$DNSIMPLE_DOMAIN",
|
||||
"token": "$DNSIMPLE_TOKEN"
|
||||
@ -44,16 +43,6 @@
|
||||
"domain": "$EXOSCALE_DOMAIN",
|
||||
"secretkey": "$EXOSCALE_SECRET_KEY"
|
||||
},
|
||||
"GANDI": {
|
||||
"COMMENT": "5: gandi does not accept TTLs less than 300",
|
||||
"apikey": "$GANDI_KEY",
|
||||
"domain": "$GANDI_DOMAIN"
|
||||
},
|
||||
"GANDI-LIVEDNS": {
|
||||
"COMMENT": "5: gandi does not accept TTLs less than 300",
|
||||
"apikey": "$GANDILIVE_KEY",
|
||||
"domain": "$GANDILIVE_DOMAIN"
|
||||
},
|
||||
"GANDI_V5": {
|
||||
"apikey": "$GANDI_V5_APIKEY",
|
||||
"domain": "$GANDI_V5_DOMAIN"
|
||||
@ -74,7 +63,6 @@
|
||||
"ipaddress": "$HEXONET_IP"
|
||||
},
|
||||
"LINODE": {
|
||||
"COMMENT": "25: Linode's hostname validation does not allow the target domain TLD",
|
||||
"domain": "$LINODE_DOMAIN",
|
||||
"token": "$LINODE_TOKEN"
|
||||
},
|
||||
@ -109,7 +97,6 @@
|
||||
"domain": "$R53_DOMAIN"
|
||||
},
|
||||
"SOFTLAYER": {
|
||||
"COMMENT": "22-25 softlayer fails at direct internationalization, puncode works though",
|
||||
"api_key": "$SL_API_KEY",
|
||||
"domain": "$SL_DOMAIN",
|
||||
"username": "$SL_USERNAME"
|
||||
|
112
integrationTest/test-numbers.txt
Normal file
112
integrationTest/test-numbers.txt
Normal file
@ -0,0 +1,112 @@
|
||||
--- PASS: TestDNSProviders/example.com/0:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/1:_Create_an_A_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/2:_Change_it (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/3:_Add_another (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/4:_Add_another(same_name) (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/5:_Change_a_ttl (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/6:_Change_single_target_from_set (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/7:_Change_all_ttls (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/8:_Delete_one (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/9:_Add_back_and_change_ttl (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/10:_Change_targets_and_ttls (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/11:_Create_wildcard (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/12:_Delete_wildcard (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/13:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/14:_Create_a_CNAME (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/15:_Change_it (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/16:_Change_to_A_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/17:_Change_back_to_CNAME (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/18:_Record_pointing_to_@ (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/19:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/20:_NS_for_subdomain (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/21:_Dual_NS_for_subdomain (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/22:_NS_Record_pointing_to_@ (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/23:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/24:_Internationalized_name (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/25:_Change_IDN (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/26:_Internationalized_CNAME_Target (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/27:_IDN_CNAME_AND_Target (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/28:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/29:_MX_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/30:_Second_MX_record,_same_prio (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/31:_3_MX (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/32:_Delete_one (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/33:_Change_to_other_name (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/34:_Change_Preference (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/35:_Record_pointing_to_@ (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/36:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/37:_Create_PTR_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/38:_Modify_PTR_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/39:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/40:_NAPTR_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/41:_NAPTR_second_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/42:_NAPTR_delete_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/43:_NAPTR_change_target (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/44:_NAPTR_change_order (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/45:_NAPTR_change_preference (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/46:_NAPTR_change_flags (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/47:_NAPTR_change_service (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/48:_NAPTR_change_regexp (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/49:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/50:_SRV_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/51:_Second_SRV_record,_same_prio (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/52:_3_SRV (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/53:_Delete_one (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/54:_Change_Target (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/55:_Change_Priority (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/56:_Change_Weight (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/57:_Change_Port (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/58:_Null_Target (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/59:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/60:_SSHFP_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/61:_SSHFP_change_algorithm (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/62:_SSHFP_change_fingerprint_and_type (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/63:_SSHFP_Delete_one (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/64:_SSHFP_add_many_records (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/65:_SSHFP_delete_two (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/66:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/67:_CAA_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/68:_CAA_change_tag (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/69:_CAA_change_target (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/70:_CAA_change_flag (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/71:_CAA_many_records (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/72:_CAA_delete (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/73:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/74:_TLSA_record (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/75:_TLSA_change_usage (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/76:_TLSA_change_selector (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/77:_TLSA_change_matchingtype (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/78:_TLSA_change_certificate (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/79:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/80:_Create_CAPS (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/81:_Downcase_label (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/82:_Downcase_target (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/83:_Upcase_both (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/84:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/85:_99_records (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/86:_100_records (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/87:_101_records (0.03s)
|
||||
--- PASS: TestDNSProviders/example.com/88:_Empty (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/89:_Create_a_TXT (0.03s)
|
||||
--- PASS: TestDNSProviders/example.com/90:_Change_a_TXT (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/91:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/92:_Create_a_TXT_with_spaces (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/93:_Change_a_TXT_with_spaces (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/94:_Create_1_TXT_as_array (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/95:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/96:_Create_a_255-byte_TXT (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/97:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/98:_Create_TXTMulti_1 (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/99:_Create_TXTMulti_2 (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/100:_Create_TXTMulti_3 (0.02s)
|
||||
--- PASS: TestDNSProviders/example.com/101:_Create_TXTMulti_with_quotes (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/102:_Change_TXTMulti (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/103:_Empty (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/104:_3x255-byte_TXTMulti (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/105:_Empty (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/106:_Create_some_records (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/107:_Add_a_new_record_-_ignoring_foo (0.02s)
|
||||
--- PASS: TestDNSProviders/example.com/108:_Empty (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/109:_Create_some_records (0.01s)
|
||||
--- PASS: TestDNSProviders/example.com/110:_Add_a_new_record_-_ignoring_*.foo (0.00s)
|
||||
--- PASS: TestDNSProviders/example.com/111:_Empty (0.01s)
|
@ -1,6 +1,7 @@
|
||||
D("foo.com","none"
|
||||
, TXT("@","simple")
|
||||
, TXT("@",["one"])
|
||||
, TXT("@",["bonie", "clyde"])
|
||||
, TXT("@",["straw", "wood", "brick"])
|
||||
, TXT("a","simple")
|
||||
, TXT("b","ws at end ")
|
||||
, TXT("c",["one"])
|
||||
, TXT("d",["bonie", "clyde"])
|
||||
, TXT("e",["straw", "wood", "brick"])
|
||||
);
|
||||
|
@ -9,7 +9,7 @@
|
||||
"records": [
|
||||
{
|
||||
"type": "TXT",
|
||||
"name": "@",
|
||||
"name": "a",
|
||||
"target": "simple",
|
||||
"txtstrings": [
|
||||
"simple"
|
||||
@ -17,7 +17,15 @@
|
||||
},
|
||||
{
|
||||
"type": "TXT",
|
||||
"name": "@",
|
||||
"name": "b",
|
||||
"target": "ws at end ",
|
||||
"txtstrings": [
|
||||
"ws at end "
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "TXT",
|
||||
"name": "c",
|
||||
"target": "one",
|
||||
"txtstrings": [
|
||||
"one"
|
||||
@ -25,7 +33,7 @@
|
||||
},
|
||||
{
|
||||
"type": "TXT",
|
||||
"name": "@",
|
||||
"name": "d",
|
||||
"target": "bonie",
|
||||
"txtstrings": [
|
||||
"bonie",
|
||||
@ -34,7 +42,7 @@
|
||||
},
|
||||
{
|
||||
"type": "TXT",
|
||||
"name": "@",
|
||||
"name": "e",
|
||||
"target": "straw",
|
||||
"txtstrings": [
|
||||
"straw",
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
_ "github.com/StackExchange/dnscontrol/v2/providers/digitalocean"
|
||||
_ "github.com/StackExchange/dnscontrol/v2/providers/dnsimple"
|
||||
_ "github.com/StackExchange/dnscontrol/v2/providers/exoscale"
|
||||
_ "github.com/StackExchange/dnscontrol/v2/providers/gandi"
|
||||
_ "github.com/StackExchange/dnscontrol/v2/providers/gandi_v5"
|
||||
_ "github.com/StackExchange/dnscontrol/v2/providers/gcloud"
|
||||
_ "github.com/StackExchange/dnscontrol/v2/providers/hexonet"
|
||||
|
@ -75,7 +75,6 @@ func (c *CloudflareApi) getRecordsForDomain(id string, domain string) ([]*models
|
||||
}
|
||||
page++
|
||||
}
|
||||
// fmt.Printf("DEBUG REORDS=%v\n", records)
|
||||
return records, nil
|
||||
}
|
||||
|
||||
|
@ -1,215 +0,0 @@
|
||||
package gandi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
gandidomain "github.com/prasmussen/gandi-api/domain"
|
||||
gandirecord "github.com/prasmussen/gandi-api/domain/zone/record"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v2/models"
|
||||
"github.com/StackExchange/dnscontrol/v2/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v2/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v2/providers"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
Gandi API DNS provider:
|
||||
|
||||
Info required in `creds.json`:
|
||||
- apikey
|
||||
|
||||
*/
|
||||
|
||||
var deprecationWarned bool
|
||||
|
||||
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(),
|
||||
providers.CanGetZones: providers.Unimplemented(),
|
||||
}
|
||||
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("GANDI", newDsp, features)
|
||||
providers.RegisterRegistrarType("GANDI", newReg)
|
||||
}
|
||||
|
||||
// GandiApi is the API handle for this module.
|
||||
type GandiApi struct {
|
||||
ApiKey string
|
||||
domainIndex map[string]int64 // Map of domainname to index
|
||||
nameservers map[string][]*models.Nameserver
|
||||
ZoneId int64
|
||||
}
|
||||
|
||||
type gandiRecord struct {
|
||||
gandirecord.RecordInfo
|
||||
}
|
||||
|
||||
func (c *GandiApi) getDomainInfo(domain string) (*gandidomain.DomainInfo, error) {
|
||||
if err := c.fetchDomainList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, ok := c.domainIndex[domain]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("'%s' not a zone in gandi account", domain)
|
||||
}
|
||||
return c.fetchDomainInfo(domain)
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for domain.
|
||||
func (c *GandiApi) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
domaininfo, err := c.getDomainInfo(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ns := []*models.Nameserver{}
|
||||
for _, nsname := range domaininfo.Nameservers {
|
||||
ns = append(ns, &models.Nameserver{Name: nsname})
|
||||
}
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (client *GandiApi) GetZoneRecords(domain string) (models.Records, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
// This enables the get-zones subcommand.
|
||||
// Implement this by extracting the code from GetDomainCorrections into
|
||||
// a single function. For most providers this should be relatively easy.
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections recommended for this domain.
|
||||
func (c *GandiApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
domaininfo, err := c.getDomainInfo(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
foundRecords, err := c.getZoneRecords(domaininfo.ZoneId, dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
expectedRecordSets := make([]gandirecord.RecordSet, 0, len(dc.Records))
|
||||
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 {
|
||||
return nil, fmt.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
|
||||
}
|
||||
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. %s will not be added.\n", rec.GetTargetField())
|
||||
}
|
||||
continue
|
||||
}
|
||||
rs := gandirecord.RecordSet{
|
||||
"type": rec.Type,
|
||||
"name": rec.GetLabel(),
|
||||
"value": rec.GetTargetCombined(),
|
||||
"ttl": rec.TTL,
|
||||
}
|
||||
expectedRecordSets = append(expectedRecordSets, rs)
|
||||
recordsToKeep = append(recordsToKeep, rec)
|
||||
}
|
||||
dc.Records = recordsToKeep
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
|
||||
differ := diff.New(dc)
|
||||
_, create, del, mod := differ.IncrementalDiff(foundRecords)
|
||||
|
||||
// Print a list of changes. Generate an actual change that is the zone
|
||||
changes := false
|
||||
desc := ""
|
||||
for _, i := range create {
|
||||
changes = true
|
||||
desc += "\n" + i.String()
|
||||
}
|
||||
for _, i := range del {
|
||||
changes = true
|
||||
desc += "\n" + i.String()
|
||||
}
|
||||
for _, i := range mod {
|
||||
changes = true
|
||||
desc += "\n" + i.String()
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("GENERATE_ZONE: %s (%d records)%s", dc.Name, len(dc.Records), desc)
|
||||
corrections := []*models.Correction{}
|
||||
if changes {
|
||||
corrections = append(corrections,
|
||||
&models.Correction{
|
||||
Msg: msg,
|
||||
F: func() error {
|
||||
printer.Printf("CREATING ZONE: %v\n", dc.Name)
|
||||
return c.createGandiZone(dc.Name, domaininfo.ZoneId, expectedRecordSets)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return corrections, nil
|
||||
}
|
||||
|
||||
func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
return newGandi(conf, metadata)
|
||||
}
|
||||
|
||||
func newReg(conf map[string]string) (providers.Registrar, error) {
|
||||
return newGandi(conf, nil)
|
||||
}
|
||||
|
||||
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 == "" {
|
||||
return nil, fmt.Errorf("missing Gandi apikey")
|
||||
}
|
||||
|
||||
return api, nil
|
||||
}
|
||||
|
||||
// GetRegistrarCorrections returns a list of corrections for this registrar.
|
||||
func (c *GandiApi) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
domaininfo, err := c.getDomainInfo(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(domaininfo.Nameservers)
|
||||
found := strings.Join(domaininfo.Nameservers, ",")
|
||||
desiredNs := []string{}
|
||||
for _, d := range dc.Nameservers {
|
||||
desiredNs = append(desiredNs, d.Name)
|
||||
}
|
||||
sort.Strings(desiredNs)
|
||||
desired := strings.Join(desiredNs, ",")
|
||||
if found != desired {
|
||||
return []*models.Correction{
|
||||
{
|
||||
Msg: fmt.Sprintf("Change Nameservers from '%s' to '%s'", found, desired),
|
||||
F: func() (err error) {
|
||||
_, err = c.setDomainNameservers(dc.Name, desiredNs)
|
||||
return
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
@ -1,292 +0,0 @@
|
||||
package gandi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
gandiclient "github.com/prasmussen/gandi-api/client"
|
||||
gandilivedomain "github.com/prasmussen/gandi-api/live_dns/domain"
|
||||
gandiliverecord "github.com/prasmussen/gandi-api/live_dns/record"
|
||||
gandilivezone "github.com/prasmussen/gandi-api/live_dns/zone"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v2/models"
|
||||
"github.com/StackExchange/dnscontrol/v2/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v2/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v2/providers"
|
||||
)
|
||||
|
||||
var liveFeatures = providers.DocumentationNotes{
|
||||
providers.CanUseCAA: providers.Can(),
|
||||
providers.CanUsePTR: providers.Can(),
|
||||
providers.CanUseSRV: providers.Can(),
|
||||
providers.CanUseTXTMulti: providers.Can(),
|
||||
providers.CantUseNOPURGE: providers.Cannot(),
|
||||
providers.DocCreateDomains: providers.Cannot("Can only manage domains registered through their service"),
|
||||
providers.DocOfficiallySupported: providers.Cannot(),
|
||||
}
|
||||
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("GANDI-LIVEDNS", newLiveDsp, liveFeatures)
|
||||
}
|
||||
|
||||
func newLiveDsp(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
APIKey := m["apikey"]
|
||||
if APIKey == "" {
|
||||
return nil, fmt.Errorf("missing Gandi apikey")
|
||||
}
|
||||
|
||||
return newLiveClient(APIKey), nil
|
||||
}
|
||||
|
||||
type domainManager interface {
|
||||
Info(string) (*gandilivedomain.Info, error)
|
||||
Records(string) gandiliverecord.Manager
|
||||
}
|
||||
|
||||
type zoneManager interface {
|
||||
InfoByUUID(uuid.UUID) (*gandilivezone.Info, error)
|
||||
Create(gandilivezone.Info) (*gandilivezone.CreateStatus, error)
|
||||
Set(string, gandilivezone.Info) (*gandilivezone.Status, error)
|
||||
Records(gandilivezone.Info) gandiliverecord.Manager
|
||||
}
|
||||
|
||||
type liveClient struct {
|
||||
client *gandiclient.Client
|
||||
zoneManager zoneManager
|
||||
domainManager domainManager
|
||||
}
|
||||
|
||||
func newLiveClient(APIKey string) *liveClient {
|
||||
cl := gandiclient.New(APIKey, gandiclient.LiveDNS)
|
||||
return &liveClient{
|
||||
client: cl,
|
||||
zoneManager: gandilivezone.New(cl),
|
||||
domainManager: gandilivedomain.New(cl),
|
||||
}
|
||||
}
|
||||
|
||||
// GetNameservers returns the list of gandi name servers for a given domain
|
||||
func (c *liveClient) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
domains := []string{}
|
||||
response, err := c.client.Get("/nameservers/"+domain, &domains)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get nameservers for domain %s", domain)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
ns := []*models.Nameserver{}
|
||||
for _, domain := range domains {
|
||||
ns = append(ns, &models.Nameserver{Name: domain})
|
||||
}
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (client *liveClient) GetZoneRecords(domain string) (models.Records, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
// This enables the get-zones subcommand.
|
||||
// Implement this by extracting the code from GetDomainCorrections into
|
||||
// a single function. For most providers this should be relatively easy.
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections recommended for this domain.
|
||||
func (c *liveClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
records, err := c.domainManager.Records(dc.Name).List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
foundRecords := c.recordConfigFromInfo(records, dc.Name)
|
||||
recordsToKeep, records, err := c.recordsToInfo(dc.Records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dc.Records = recordsToKeep
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
|
||||
differ := diff.New(dc)
|
||||
|
||||
_, create, del, mod := differ.IncrementalDiff(foundRecords)
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
// Print a list of changes. Generate an actual change that is the zone
|
||||
changes := false
|
||||
for _, i := range create {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
for _, i := range del {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
for _, i := range mod {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
|
||||
if changes {
|
||||
message := fmt.Sprintf("Setting dns records for %s:", dc.Name)
|
||||
message += "\n" + buf.String()
|
||||
return []*models.Correction{
|
||||
{
|
||||
Msg: message,
|
||||
F: func() error {
|
||||
return c.createZone(dc.Name, records)
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return []*models.Correction{}, nil
|
||||
}
|
||||
|
||||
// createZone creates a new empty zone for the domain, populates it with the record infos and associates the domain to it
|
||||
func (c *liveClient) createZone(domainname string, records []*gandiliverecord.Info) error {
|
||||
domainInfo, err := c.domainManager.Info(domainname)
|
||||
infos, err := c.zoneManager.InfoByUUID(*domainInfo.ZoneUUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
infos.Name = fmt.Sprintf("zone created by dnscontrol for %s on %s", domainname, time.Now().Format(time.RFC3339))
|
||||
printer.Debugf("DEBUG: createZone SharingID=%v\n", infos.SharingID)
|
||||
|
||||
// duplicate zone Infos
|
||||
status, err := c.zoneManager.Create(*infos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zoneInfos, err := c.zoneManager.InfoByUUID(*status.UUID)
|
||||
if err != nil {
|
||||
// gandi might take some time to make the new zone available
|
||||
for i := 0; i < 10; i++ {
|
||||
printer.Printf("zone info not yet available. Delay and retry: %s\n", err.Error())
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
zoneInfos, err = c.zoneManager.InfoByUUID(*status.UUID)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
recordManager := c.zoneManager.Records(*zoneInfos)
|
||||
for _, record := range records {
|
||||
_, err := recordManager.Create(*record)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = c.zoneManager.Set(domainname, *zoneInfos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// recordConfigFromInfo takes a DNS record from Gandi liveDNS and returns our native RecordConfig format.
|
||||
func (c *liveClient) recordConfigFromInfo(infos []*gandiliverecord.Info, origin string) []*models.RecordConfig {
|
||||
rcs := []*models.RecordConfig{}
|
||||
for _, info := range infos {
|
||||
// TXT records might have multiple values. In that case,
|
||||
// they are all for the TXT record at that label.
|
||||
if info.Type == "TXT" {
|
||||
rc := &models.RecordConfig{
|
||||
Type: info.Type,
|
||||
Original: info,
|
||||
TTL: uint32(info.TTL),
|
||||
}
|
||||
rc.SetLabel(info.Name, origin)
|
||||
var parsed []string
|
||||
for _, txt := range info.Values {
|
||||
parsed = append(parsed, models.StripQuotes(txt))
|
||||
}
|
||||
err := rc.SetTargetTXTs(parsed)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("recordConfigFromInfo=TXT failed: %w", err))
|
||||
}
|
||||
rcs = append(rcs, rc)
|
||||
} else {
|
||||
// All other record types might have multiple values, but that means
|
||||
// we should create one Recordconfig for each one.
|
||||
for _, value := range info.Values {
|
||||
rc := &models.RecordConfig{
|
||||
Type: info.Type,
|
||||
Original: info,
|
||||
TTL: uint32(info.TTL),
|
||||
}
|
||||
rc.SetLabel(info.Name, origin)
|
||||
switch rtype := info.Type; rtype {
|
||||
default:
|
||||
err := rc.PopulateFromString(rtype, value, origin)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("recordConfigFromInfo failed: %w", err))
|
||||
}
|
||||
}
|
||||
rcs = append(rcs, rc)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rcs
|
||||
}
|
||||
|
||||
// recordsToInfo generates gandi record sets and filters incompatible entries from native records format
|
||||
func (c *liveClient) recordsToInfo(records models.Records) (models.Records, []*gandiliverecord.Info, error) {
|
||||
recordSets := map[string]map[string]*gandiliverecord.Info{}
|
||||
recordInfos := []*gandiliverecord.Info{}
|
||||
recordToKeep := models.Records{}
|
||||
|
||||
for _, rec := range records {
|
||||
if rec.TTL < 300 {
|
||||
printer.Warnf("Gandi does not support ttls < 300. %s will not be set to %d.\n", rec.GetLabelFQDN(), rec.TTL)
|
||||
rec.TTL = 300
|
||||
}
|
||||
if rec.TTL > 2592000 {
|
||||
return nil, nil, fmt.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
|
||||
}
|
||||
if rec.Type == "NS" && rec.GetLabel() == "@" {
|
||||
if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") {
|
||||
printer.Warnf("Gandi does not support changing apex NS records. %s will not be added.\n", rec.GetTargetField())
|
||||
}
|
||||
continue
|
||||
}
|
||||
r, ok := recordSets[rec.GetLabel()][rec.Type]
|
||||
if !ok {
|
||||
_, ok := recordSets[rec.GetLabel()]
|
||||
if !ok {
|
||||
recordSets[rec.GetLabel()] = map[string]*gandiliverecord.Info{}
|
||||
}
|
||||
r = &gandiliverecord.Info{
|
||||
Type: rec.Type,
|
||||
Name: rec.GetLabel(),
|
||||
TTL: int64(rec.TTL),
|
||||
}
|
||||
recordInfos = append(recordInfos, r)
|
||||
recordSets[rec.GetLabel()][rec.Type] = r
|
||||
} else {
|
||||
if r.TTL != int64(rec.TTL) {
|
||||
printer.Warnf(
|
||||
"Gandi liveDNS API does not support different TTL for the couple fqdn/type. Will use TTL of %d for %s %s\n",
|
||||
r.TTL,
|
||||
r.Type,
|
||||
r.Name,
|
||||
)
|
||||
}
|
||||
}
|
||||
recordToKeep = append(recordToKeep, rec)
|
||||
if rec.Type == "TXT" {
|
||||
for _, t := range rec.TxtStrings {
|
||||
r.Values = append(r.Values, "\""+t+"\"") // FIXME(tlim): Should do proper quoting.
|
||||
}
|
||||
} else {
|
||||
r.Values = append(r.Values, rec.GetTargetCombined())
|
||||
}
|
||||
}
|
||||
return recordToKeep, recordInfos, nil
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
package gandi
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v2/models"
|
||||
"github.com/prasmussen/gandi-api/live_dns/record"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig {
|
||||
rc.SetLabel(label, domain)
|
||||
rc.SetTarget(target)
|
||||
return &rc
|
||||
}
|
||||
func TestRecordConfigFromInfo(t *testing.T) {
|
||||
|
||||
for _, data := range []struct {
|
||||
info *record.Info
|
||||
config []*models.RecordConfig
|
||||
}{
|
||||
{
|
||||
&record.Info{
|
||||
Name: "www",
|
||||
Type: "A",
|
||||
TTL: 500,
|
||||
Values: []string{"127.0.0.1", "127.1.0.1"},
|
||||
},
|
||||
[]*models.RecordConfig{
|
||||
makeRC("www", "example.com", "127.0.0.1", models.RecordConfig{
|
||||
Type: "A",
|
||||
TTL: 500,
|
||||
}),
|
||||
makeRC("www", "example.com", "127.1.0.1", models.RecordConfig{
|
||||
Type: "A",
|
||||
TTL: 500,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
&record.Info{
|
||||
Name: "www",
|
||||
Type: "TXT",
|
||||
TTL: 500,
|
||||
Values: []string{"\"test 2\"", "\"test message test message test message\""},
|
||||
},
|
||||
[]*models.RecordConfig{
|
||||
makeRC("www", "example.com", "test 2", models.RecordConfig{
|
||||
Type: "TXT",
|
||||
TxtStrings: []string{"test 2", "test message test message test message"},
|
||||
TTL: 500,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
&record.Info{
|
||||
Name: "www",
|
||||
Type: "CAA",
|
||||
TTL: 500,
|
||||
// examples from https://sslmate.com/caa/
|
||||
Values: []string{"0 issue \"www.certinomis.com\"", "0 issuewild \"buypass.com\""},
|
||||
},
|
||||
[]*models.RecordConfig{
|
||||
makeRC("www", "example.com", "www.certinomis.com", models.RecordConfig{
|
||||
Type: "CAA",
|
||||
CaaFlag: 0,
|
||||
CaaTag: "issue",
|
||||
TTL: 500,
|
||||
}),
|
||||
makeRC("www", "example.com", "buypass.com", models.RecordConfig{
|
||||
Type: "CAA",
|
||||
CaaFlag: 0,
|
||||
CaaTag: "issuewild",
|
||||
TTL: 500,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
&record.Info{
|
||||
Name: "test",
|
||||
Type: "SRV",
|
||||
TTL: 500,
|
||||
Values: []string{"20 0 5060 backupbox.example.com."},
|
||||
},
|
||||
[]*models.RecordConfig{
|
||||
makeRC("test", "example.com", "backupbox.example.com.", models.RecordConfig{
|
||||
Type: "SRV",
|
||||
SrvPriority: 20,
|
||||
SrvWeight: 0,
|
||||
SrvPort: 5060,
|
||||
TTL: 500,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
&record.Info{
|
||||
Name: "mail",
|
||||
Type: "MX",
|
||||
TTL: 500,
|
||||
Values: []string{"50 fb.mail.gandi.net.", "10 spool.mail.gandi.net."},
|
||||
},
|
||||
[]*models.RecordConfig{
|
||||
makeRC("mail", "example.com", "fb.mail.gandi.net.", models.RecordConfig{
|
||||
Type: "MX",
|
||||
MxPreference: 50,
|
||||
TTL: 500,
|
||||
}),
|
||||
makeRC("mail", "example.com", "spool.mail.gandi.net.", models.RecordConfig{
|
||||
Type: "MX",
|
||||
MxPreference: 10,
|
||||
TTL: 500,
|
||||
}),
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run("with record type "+data.info.Type, func(t *testing.T) {
|
||||
c := liveClient{}
|
||||
for _, c := range data.config {
|
||||
c.Original = data.info
|
||||
}
|
||||
t.Run("Convert gandi info to record config", func(t *testing.T) {
|
||||
recordConfig := c.recordConfigFromInfo([]*record.Info{data.info}, "example.com")
|
||||
assert.Equal(t, data.config, recordConfig)
|
||||
})
|
||||
t.Run("Convert record config to gandi info", func(t *testing.T) {
|
||||
_, recordInfos, err := c.recordsToInfo(data.config)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []*record.Info{data.info}, recordInfos)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
package gandi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
gandiclient "github.com/prasmussen/gandi-api/client"
|
||||
gandidomain "github.com/prasmussen/gandi-api/domain"
|
||||
gandinameservers "github.com/prasmussen/gandi-api/domain/nameservers"
|
||||
gandizone "github.com/prasmussen/gandi-api/domain/zone"
|
||||
gandirecord "github.com/prasmussen/gandi-api/domain/zone/record"
|
||||
gandiversion "github.com/prasmussen/gandi-api/domain/zone/version"
|
||||
gandioperation "github.com/prasmussen/gandi-api/operation"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v2/models"
|
||||
)
|
||||
|
||||
// fetchDomainList gets list of domains for account. Cache ids for easy lookup.
|
||||
func (c *GandiApi) fetchDomainList() error {
|
||||
if c.domainIndex != nil {
|
||||
return nil
|
||||
}
|
||||
c.domainIndex = map[string]int64{}
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
domain := gandidomain.New(gc)
|
||||
domains, err := domain.List()
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
for _, d := range domains {
|
||||
c.domainIndex[d.Fqdn] = d.Id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fetchDomainInfo gets information about a domain.
|
||||
func (c *GandiApi) fetchDomainInfo(fqdn string) (*gandidomain.DomainInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
domain := gandidomain.New(gc)
|
||||
return domain.Info(fqdn)
|
||||
}
|
||||
|
||||
// setDomainNameservers updates the nameservers of a domain.
|
||||
func (c *GandiApi) setDomainNameservers(fqdn string, nameservers []string) (*gandioperation.OperationInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
nameserversapi := gandinameservers.New(gc)
|
||||
return nameserversapi.Set(fqdn, nameservers)
|
||||
}
|
||||
|
||||
// getRecordsForDomain returns a list of records for a zone.
|
||||
func (c *GandiApi) getZoneRecords(zoneid int64, origin string) ([]*models.RecordConfig, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
record := gandirecord.New(gc)
|
||||
recs, err := record.List(zoneid, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rcs := make([]*models.RecordConfig, 0, len(recs))
|
||||
for _, r := range recs {
|
||||
rcs = append(rcs, nativeToRecord(r, origin))
|
||||
}
|
||||
return rcs, nil
|
||||
}
|
||||
|
||||
// convert takes a DNS record from Gandi and returns our native RecordConfig format.
|
||||
func nativeToRecord(r *gandirecord.RecordInfo, origin string) *models.RecordConfig {
|
||||
|
||||
rc := &models.RecordConfig{
|
||||
//NameFQDN: dnsutil.AddOrigin(r.Name, origin),
|
||||
//Name: r.Name,
|
||||
//Type: r.Type,
|
||||
TTL: uint32(r.Ttl),
|
||||
Original: r,
|
||||
//Target: r.Value,
|
||||
}
|
||||
rc.SetLabel(r.Name, origin)
|
||||
switch rtype := r.Type; rtype {
|
||||
default: // "A", "AAAA", "CAA", "NS", "CNAME", "MX", "PTR", "SRV", "TXT"
|
||||
if err := rc.PopulateFromString(rtype, r.Value, origin); err != nil {
|
||||
panic(fmt.Errorf("unparsable record received from gandi: %w", err))
|
||||
}
|
||||
}
|
||||
return rc
|
||||
}
|
||||
|
||||
// listZones retrieves the list of zones.
|
||||
func (c *GandiApi) listZones() ([]*gandizone.ZoneInfoBase, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
zone := gandizone.New(gc)
|
||||
return zone.List()
|
||||
}
|
||||
|
||||
// setZone assigns a particular zone to a domain.
|
||||
func (c *GandiApi) setZones(domainname string, zoneID int64) (*gandidomain.DomainInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
zone := gandizone.New(gc)
|
||||
return zone.Set(domainname, zoneID)
|
||||
}
|
||||
|
||||
// getZoneInfo gets ZoneInfo about a zone.
|
||||
func (c *GandiApi) getZoneInfo(zoneid int64) (*gandizone.ZoneInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
zone := gandizone.New(gc)
|
||||
return zone.Info(zoneid)
|
||||
}
|
||||
|
||||
// createZone creates an entirely new zone.
|
||||
func (c *GandiApi) createZone(name string) (*gandizone.ZoneInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
zone := gandizone.New(gc)
|
||||
return zone.Create(name)
|
||||
}
|
||||
|
||||
func (c *GandiApi) getEditableZone(domainname string, zoneinfo *gandizone.ZoneInfo) (int64, error) {
|
||||
var zoneID int64
|
||||
if zoneinfo.Domains < 2 {
|
||||
// If there is only on{ domain linked to this zone, use it.
|
||||
zoneID = zoneinfo.Id
|
||||
fmt.Printf("Using zone id=%d named %#v\n", zoneID, zoneinfo.Name)
|
||||
return zoneID, nil
|
||||
}
|
||||
|
||||
// We can't use the zone_id given to us. Let's make/find a new one.
|
||||
zones, err := c.listZones()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
zonename := fmt.Sprintf("%s dnscontrol", domainname)
|
||||
for _, z := range zones {
|
||||
if z.Name == zonename {
|
||||
zoneID = z.Id
|
||||
fmt.Printf("Recycling zone id=%d named %#v\n", zoneID, z.Name)
|
||||
return zoneID, nil
|
||||
}
|
||||
}
|
||||
zoneinfo, err = c.createZone(zonename)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
zoneID = zoneinfo.Id
|
||||
fmt.Printf("Created zone id=%d named %#v\n", zoneID, zoneinfo.Name)
|
||||
return zoneID, nil
|
||||
}
|
||||
|
||||
// makeEditableZone
|
||||
func (c *GandiApi) makeEditableZone(zoneID int64) (int64, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
version := gandiversion.New(gc)
|
||||
return version.New(zoneID, 0)
|
||||
}
|
||||
|
||||
// setZoneRecords
|
||||
func (c *GandiApi) setZoneRecords(zoneID, versionID int64, records []gandirecord.RecordSet) ([]*gandirecord.RecordInfo, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
record := gandirecord.New(gc)
|
||||
return record.SetRecords(zoneID, versionID, records)
|
||||
}
|
||||
|
||||
// activateVersion
|
||||
func (c *GandiApi) activateVersion(zoneID, versionID int64) (bool, error) {
|
||||
gc := gandiclient.New(c.ApiKey, gandiclient.Production)
|
||||
version := gandiversion.New(gc)
|
||||
return version.Set(zoneID, versionID)
|
||||
}
|
||||
|
||||
func (c *GandiApi) createGandiZone(domainname string, zoneID int64, records []gandirecord.RecordSet) error {
|
||||
|
||||
// Get the zone_id of the zone we'll be updating.
|
||||
zoneinfo, err := c.getZoneInfo(zoneID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zoneID, err = c.getEditableZone(domainname, zoneinfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the versionID of the zone we're updating.
|
||||
versionID, err := c.makeEditableZone(zoneID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the new version.
|
||||
_, err = c.setZoneRecords(zoneID, versionID, records)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Activate zone version
|
||||
_, err = c.activateVersion(zoneID, versionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.setZones(domainname, zoneID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
@ -1,9 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.3
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
10
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
10
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
@ -1,10 +0,0 @@
|
||||
# How to contribute
|
||||
|
||||
We definitely welcome patches and contribution to this project!
|
||||
|
||||
### Legal requirements
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||
|
||||
You may have already signed it for other Google projects.
|
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
@ -1,9 +0,0 @@
|
||||
Paul Borman <borman@google.com>
|
||||
bmatsuo
|
||||
shawnps
|
||||
theory
|
||||
jboverfelt
|
||||
dsymonds
|
||||
cd1
|
||||
wallclockbuilder
|
||||
dansouza
|
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
||||
Copyright (c) 2009,2014 Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
vendor/github.com/google/uuid/README.md
generated
vendored
19
vendor/github.com/google/uuid/README.md
generated
vendored
@ -1,19 +0,0 @@
|
||||
# uuid 
|
||||
The uuid package generates and inspects UUIDs based on
|
||||
[RFC 4122](http://tools.ietf.org/html/rfc4122)
|
||||
and DCE 1.1: Authentication and Security Services.
|
||||
|
||||
This package is based on the github.com/pborman/uuid package (previously named
|
||||
code.google.com/p/go-uuid). It differs from these earlier packages in that
|
||||
a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||
|
||||
###### Install
|
||||
`go get github.com/google/uuid`
|
||||
|
||||
###### Documentation
|
||||
[](http://godoc.org/github.com/google/uuid)
|
||||
|
||||
Full `go doc` style documentation for the package can be viewed online without
|
||||
installing this package by using the GoDoc site here:
|
||||
http://godoc.org/github.com/google/uuid
|
80
vendor/github.com/google/uuid/dce.go
generated
vendored
80
vendor/github.com/google/uuid/dce.go
generated
vendored
@ -1,80 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A Domain represents a Version 2 domain
|
||||
type Domain byte
|
||||
|
||||
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||
const (
|
||||
Person = Domain(0)
|
||||
Group = Domain(1)
|
||||
Org = Domain(2)
|
||||
)
|
||||
|
||||
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||
//
|
||||
// The domain should be one of Person, Group or Org.
|
||||
// On a POSIX system the id should be the users UID for the Person
|
||||
// domain and the users GID for the Group. The meaning of id for
|
||||
// the domain Org or on non-POSIX systems is site defined.
|
||||
//
|
||||
// For a given domain/id pair the same token may be returned for up to
|
||||
// 7 minutes and 10 seconds.
|
||||
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err == nil {
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||
uuid[9] = byte(domain)
|
||||
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||
}
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() (UUID, error) {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() (UUID, error) {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
// Domain returns the domain for a Version 2 UUID. Domains are only defined
|
||||
// for Version 2 UUIDs.
|
||||
func (uuid UUID) Domain() Domain {
|
||||
return Domain(uuid[9])
|
||||
}
|
||||
|
||||
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
|
||||
// UUIDs.
|
||||
func (uuid UUID) ID() uint32 {
|
||||
return binary.BigEndian.Uint32(uuid[0:4])
|
||||
}
|
||||
|
||||
func (d Domain) String() string {
|
||||
switch d {
|
||||
case Person:
|
||||
return "Person"
|
||||
case Group:
|
||||
return "Group"
|
||||
case Org:
|
||||
return "Org"
|
||||
}
|
||||
return fmt.Sprintf("Domain%d", int(d))
|
||||
}
|
12
vendor/github.com/google/uuid/doc.go
generated
vendored
12
vendor/github.com/google/uuid/doc.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package uuid generates and inspects UUIDs.
|
||||
//
|
||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||
// Services.
|
||||
//
|
||||
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
|
||||
// maps or compared directly.
|
||||
package uuid
|
1
vendor/github.com/google/uuid/go.mod
generated
vendored
1
vendor/github.com/google/uuid/go.mod
generated
vendored
@ -1 +0,0 @@
|
||||
module github.com/google/uuid
|
53
vendor/github.com/google/uuid/hash.go
generated
vendored
53
vendor/github.com/google/uuid/hash.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Well known namespace IDs and UUIDs
|
||||
var (
|
||||
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||
Nil UUID // empty UUID, all zeros
|
||||
)
|
||||
|
||||
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||
// data generated by h. The hash should be at least 16 byte in length. The
|
||||
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||
// NewMD5 and NewSHA1.
|
||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
h.Reset()
|
||||
h.Write(space[:])
|
||||
h.Write(data)
|
||||
s := h.Sum(nil)
|
||||
var uuid UUID
|
||||
copy(uuid[:], s)
|
||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
37
vendor/github.com/google/uuid/marshal.go
generated
vendored
37
vendor/github.com/google/uuid/marshal.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (uuid UUID) MarshalText() ([]byte, error) {
|
||||
var js [36]byte
|
||||
encodeHex(js[:], uuid)
|
||||
return js[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||
id, err := ParseBytes(data)
|
||||
if err == nil {
|
||||
*uuid = id
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (uuid UUID) MarshalBinary() ([]byte, error) {
|
||||
return uuid[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
copy(uuid[:], data)
|
||||
return nil
|
||||
}
|
90
vendor/github.com/google/uuid/node.go
generated
vendored
90
vendor/github.com/google/uuid/node.go
generated
vendored
@ -1,90 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
nodeMu sync.Mutex
|
||||
ifname string // name of interface being used
|
||||
nodeID [6]byte // hardware for version 1 UUIDs
|
||||
zeroID [6]byte // nodeID with only 0's
|
||||
)
|
||||
|
||||
// NodeInterface returns the name of the interface from which the NodeID was
|
||||
// derived. The interface "user" is returned if the NodeID was set by
|
||||
// SetNodeID.
|
||||
func NodeInterface() string {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return ifname
|
||||
}
|
||||
|
||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||
// If name is "" then the first usable interface found will be used or a random
|
||||
// Node ID will be generated. If a named interface cannot be found then false
|
||||
// is returned.
|
||||
//
|
||||
// SetNodeInterface never fails when name is "".
|
||||
func SetNodeInterface(name string) bool {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return setNodeInterface(name)
|
||||
}
|
||||
|
||||
func setNodeInterface(name string) bool {
|
||||
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||
if iname != "" && addr != nil {
|
||||
ifname = iname
|
||||
copy(nodeID[:], addr)
|
||||
return true
|
||||
}
|
||||
|
||||
// We found no interfaces with a valid hardware address. If name
|
||||
// does not specify a specific interface generate a random Node ID
|
||||
// (section 4.1.6)
|
||||
if name == "" {
|
||||
ifname = "random"
|
||||
randomBits(nodeID[:])
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||
// if not already set.
|
||||
func NodeID() []byte {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
nid := nodeID
|
||||
return nid[:]
|
||||
}
|
||||
|
||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||
// Node ID is not set.
|
||||
func SetNodeID(id []byte) bool {
|
||||
if len(id) < 6 {
|
||||
return false
|
||||
}
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
copy(nodeID[:], id)
|
||||
ifname = "user"
|
||||
return true
|
||||
}
|
||||
|
||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) NodeID() []byte {
|
||||
var node [6]byte
|
||||
copy(node[:], uuid[10:])
|
||||
return node[:]
|
||||
}
|
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build js
|
||||
|
||||
package uuid
|
||||
|
||||
// getHardwareInterface returns nil values for the JS version of the code.
|
||||
// This remvoves the "net" dependency, because it is not used in the browser.
|
||||
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !js
|
||||
|
||||
package uuid
|
||||
|
||||
import "net"
|
||||
|
||||
var interfaces []net.Interface // cached list of interfaces
|
||||
|
||||
// getHardwareInterface returns the name and hardware address of interface name.
|
||||
// If name is "" then the name and hardware address of one of the system's
|
||||
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||
// there are no interfaces) then "", nil is returned.
|
||||
//
|
||||
// Only addresses of at least 6 bytes are returned.
|
||||
func getHardwareInterface(name string) (string, []byte) {
|
||||
if interfaces == nil {
|
||||
var err error
|
||||
interfaces, err = net.Interfaces()
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
for _, ifs := range interfaces {
|
||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||
return ifs.Name, ifs.HardwareAddr
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
59
vendor/github.com/google/uuid/sql.go
generated
vendored
59
vendor/github.com/google/uuid/sql.go
generated
vendored
@ -1,59 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
|
||||
// Currently, database types that map to string and []byte are supported. Please
|
||||
// consult database-specific driver documentation for matching types.
|
||||
func (uuid *UUID) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
|
||||
case string:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// see Parse for required string format
|
||||
u, err := Parse(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Scan: %v", err)
|
||||
}
|
||||
|
||||
*uuid = u
|
||||
|
||||
case []byte:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// assumes a simple slice of bytes if 16 bytes
|
||||
// otherwise attempts to parse
|
||||
if len(src) != 16 {
|
||||
return uuid.Scan(string(src))
|
||||
}
|
||||
copy((*uuid)[:], src)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||
// transparently. Currently, UUIDs map to strings. Please consult
|
||||
// database-specific driver documentation for matching types.
|
||||
func (uuid UUID) Value() (driver.Value, error) {
|
||||
return uuid.String(), nil
|
||||
}
|
123
vendor/github.com/google/uuid/time.go
generated
vendored
123
vendor/github.com/google/uuid/time.go
generated
vendored
@ -1,123 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||
// 1582.
|
||||
type Time int64
|
||||
|
||||
const (
|
||||
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||
unix = 2440587 // Julian day of 1 Jan 1970
|
||||
epoch = unix - lillian // Days between epochs
|
||||
g1582 = epoch * 86400 // seconds between epochs
|
||||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||
)
|
||||
|
||||
var (
|
||||
timeMu sync.Mutex
|
||||
lasttime uint64 // last time we returned
|
||||
clockSeq uint16 // clock sequence for this run
|
||||
|
||||
timeNow = time.Now // for testing
|
||||
)
|
||||
|
||||
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||
// epoch of 1 Jan 1970.
|
||||
func (t Time) UnixTime() (sec, nsec int64) {
|
||||
sec = int64(t - g1582ns100)
|
||||
nsec = (sec % 10000000) * 100
|
||||
sec /= 10000000
|
||||
return sec, nsec
|
||||
}
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||
// is returned if the current time cannot be determined.
|
||||
func GetTime() (Time, uint16, error) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return getTime()
|
||||
}
|
||||
|
||||
func getTime() (Time, uint16, error) {
|
||||
t := timeNow()
|
||||
|
||||
// If we don't have a clock sequence already, set one.
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||
|
||||
// If time has gone backwards with this clock sequence then we
|
||||
// increment the clock sequence
|
||||
if now <= lasttime {
|
||||
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
|
||||
}
|
||||
lasttime = now
|
||||
return Time(now), clockSeq, nil
|
||||
}
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
||||
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||
//
|
||||
// The uuid package does not use global static storage for the clock sequence or
|
||||
// the last time a UUID was generated. Unless SetClockSequence is used, a new
|
||||
// random clock sequence is generated the first time a clock sequence is
|
||||
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
|
||||
func ClockSequence() int {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return clockSequence()
|
||||
}
|
||||
|
||||
func clockSequence() int {
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
return int(clockSeq & 0x3fff)
|
||||
}
|
||||
|
||||
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||
// -1 causes a new sequence to be generated.
|
||||
func SetClockSequence(seq int) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
setClockSequence(seq)
|
||||
}
|
||||
|
||||
func setClockSequence(seq int) {
|
||||
if seq == -1 {
|
||||
var b [2]byte
|
||||
randomBits(b[:]) // clock sequence
|
||||
seq = int(b[0])<<8 | int(b[1])
|
||||
}
|
||||
oldSeq := clockSeq
|
||||
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||
if oldSeq != clockSeq {
|
||||
lasttime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||
// uuid. The time is only defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) Time() Time {
|
||||
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||
return Time(time)
|
||||
}
|
||||
|
||||
// ClockSequence returns the clock sequence encoded in uuid.
|
||||
// The clock sequence is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) ClockSequence() int {
|
||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
|
||||
}
|
43
vendor/github.com/google/uuid/util.go
generated
vendored
43
vendor/github.com/google/uuid/util.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// randomBits completely fills slice b with random data.
|
||||
func randomBits(b []byte) {
|
||||
if _, err := io.ReadFull(rander, b); err != nil {
|
||||
panic(err.Error()) // rand should never fail
|
||||
}
|
||||
}
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts hex characters x1 and x2 into a byte.
|
||||
func xtob(x1, x2 byte) (byte, bool) {
|
||||
b1 := xvalues[x1]
|
||||
b2 := xvalues[x2]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
245
vendor/github.com/google/uuid/uuid.go
generated
vendored
245
vendor/github.com/google/uuid/uuid.go
generated
vendored
@ -1,245 +0,0 @@
|
||||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
// 4122.
|
||||
type UUID [16]byte
|
||||
|
||||
// A Version represents a UUID's version.
|
||||
type Version byte
|
||||
|
||||
// A Variant represents a UUID's variant.
|
||||
type Variant byte
|
||||
|
||||
// Constants returned by Variant.
|
||||
const (
|
||||
Invalid = Variant(iota) // Invalid UUID
|
||||
RFC4122 // The variant specified in RFC4122
|
||||
Reserved // Reserved, NCS backward compatibility.
|
||||
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||
Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
|
||||
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
||||
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
|
||||
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
|
||||
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
|
||||
func Parse(s string) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(s) {
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36:
|
||||
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9:
|
||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
case 36 + 2:
|
||||
s = s[1:]
|
||||
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
case 32:
|
||||
var ok bool
|
||||
for i := range uuid {
|
||||
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
v, ok := xtob(s[x], s[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||
func ParseBytes(b []byte) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(b) {
|
||||
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||
}
|
||||
b = b[9:]
|
||||
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
b = b[1:]
|
||||
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
var ok bool
|
||||
for i := 0; i < 32; i += 2 {
|
||||
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
v, ok := xtob(b[x], b[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||
func MustParse(s string) UUID {
|
||||
uuid, err := Parse(s)
|
||||
if err != nil {
|
||||
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||
// does not have a length of 16. The bytes are copied from the slice.
|
||||
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||
err = uuid.UnmarshalBinary(b)
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// Must returns uuid if err is nil and panics otherwise.
|
||||
func Must(uuid UUID, err error) UUID {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// , or "" if uuid is invalid.
|
||||
func (uuid UUID) String() string {
|
||||
var buf [36]byte
|
||||
encodeHex(buf[:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// URN returns the RFC 2141 URN form of uuid,
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||
func (uuid UUID) URN() string {
|
||||
var buf [36 + 9]byte
|
||||
copy(buf[:], "urn:uuid:")
|
||||
encodeHex(buf[9:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
func encodeHex(dst []byte, uuid UUID) {
|
||||
hex.Encode(dst, uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
hex.Encode(dst[14:18], uuid[6:8])
|
||||
dst[18] = '-'
|
||||
hex.Encode(dst[19:23], uuid[8:10])
|
||||
dst[23] = '-'
|
||||
hex.Encode(dst[24:], uuid[10:])
|
||||
}
|
||||
|
||||
// Variant returns the variant encoded in uuid.
|
||||
func (uuid UUID) Variant() Variant {
|
||||
switch {
|
||||
case (uuid[8] & 0xc0) == 0x80:
|
||||
return RFC4122
|
||||
case (uuid[8] & 0xe0) == 0xc0:
|
||||
return Microsoft
|
||||
case (uuid[8] & 0xe0) == 0xe0:
|
||||
return Future
|
||||
default:
|
||||
return Reserved
|
||||
}
|
||||
}
|
||||
|
||||
// Version returns the version of uuid.
|
||||
func (uuid UUID) Version() Version {
|
||||
return Version(uuid[6] >> 4)
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v > 15 {
|
||||
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||
}
|
||||
return fmt.Sprintf("VERSION_%d", v)
|
||||
}
|
||||
|
||||
func (v Variant) String() string {
|
||||
switch v {
|
||||
case RFC4122:
|
||||
return "RFC4122"
|
||||
case Reserved:
|
||||
return "Reserved"
|
||||
case Microsoft:
|
||||
return "Microsoft"
|
||||
case Future:
|
||||
return "Future"
|
||||
case Invalid:
|
||||
return "Invalid"
|
||||
}
|
||||
return fmt.Sprintf("BadVariant%d", int(v))
|
||||
}
|
||||
|
||||
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||
// If r.Read returns an error when the package requests random data then
|
||||
// a panic will be issued.
|
||||
//
|
||||
// Calling SetRand with nil sets the random number generator to the default
|
||||
// generator.
|
||||
func SetRand(r io.Reader) {
|
||||
if r == nil {
|
||||
rander = rand.Reader
|
||||
return
|
||||
}
|
||||
rander = r
|
||||
}
|
44
vendor/github.com/google/uuid/version1.go
generated
vendored
44
vendor/github.com/google/uuid/version1.go
generated
vendored
@ -1,44 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewUUID returns nil and an error.
|
||||
//
|
||||
// In most cases, New should be used.
|
||||
func NewUUID() (UUID, error) {
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
nodeMu.Unlock()
|
||||
|
||||
var uuid UUID
|
||||
now, seq, err := GetTime()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
timeLow := uint32(now & 0xffffffff)
|
||||
timeMid := uint16((now >> 32) & 0xffff)
|
||||
timeHi := uint16((now >> 48) & 0x0fff)
|
||||
timeHi |= 0x1000 // Version 1
|
||||
|
||||
binary.BigEndian.PutUint32(uuid[0:], timeLow)
|
||||
binary.BigEndian.PutUint16(uuid[4:], timeMid)
|
||||
binary.BigEndian.PutUint16(uuid[6:], timeHi)
|
||||
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||
copy(uuid[10:], nodeID[:])
|
||||
|
||||
return uuid, nil
|
||||
}
|
43
vendor/github.com/google/uuid/version4.go
generated
vendored
43
vendor/github.com/google/uuid/version4.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "io"
|
||||
|
||||
// New creates a new random UUID or panics. New is equivalent to
|
||||
// the expression
|
||||
//
|
||||
// uuid.Must(uuid.NewRandom())
|
||||
func New() UUID {
|
||||
return Must(NewRandom())
|
||||
}
|
||||
|
||||
// NewRandom returns a Random (Version 4) UUID.
|
||||
//
|
||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() (UUID, error) {
|
||||
return NewRandomFromReader(rander)
|
||||
}
|
||||
|
||||
func NewRandomFromReader(r io.Reader) (UUID, error) {
|
||||
var uuid UUID
|
||||
_, err := io.ReadFull(r, uuid[:])
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
||||
|
19
vendor/github.com/kolo/xmlrpc/LICENSE
generated
vendored
19
vendor/github.com/kolo/xmlrpc/LICENSE
generated
vendored
@ -1,19 +0,0 @@
|
||||
Copyright (C) 2012 Dmitry Maksimov
|
||||
|
||||
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.
|
79
vendor/github.com/kolo/xmlrpc/README.md
generated
vendored
79
vendor/github.com/kolo/xmlrpc/README.md
generated
vendored
@ -1,79 +0,0 @@
|
||||
## Overview
|
||||
|
||||
xmlrpc is an implementation of client side part of XMLRPC protocol in Go language.
|
||||
|
||||
## Installation
|
||||
|
||||
To install xmlrpc package run `go get github.com/kolo/xmlrpc`. To use
|
||||
it in application add `"github.com/kolo/xmlrpc"` string to `import`
|
||||
statement.
|
||||
|
||||
## Usage
|
||||
|
||||
client, _ := xmlrpc.NewClient("https://bugzilla.mozilla.org/xmlrpc.cgi", nil)
|
||||
result := struct{
|
||||
Version string `xmlrpc:"version"`
|
||||
}{}
|
||||
client.Call("Bugzilla.version", nil, &result)
|
||||
fmt.Printf("Version: %s\n", result.Version) // Version: 4.2.7+
|
||||
|
||||
Second argument of NewClient function is an object that implements
|
||||
[http.RoundTripper](http://golang.org/pkg/net/http/#RoundTripper)
|
||||
interface, it can be used to get more control over connection options.
|
||||
By default it initialized by http.DefaultTransport object.
|
||||
|
||||
### Arguments encoding
|
||||
|
||||
xmlrpc package supports encoding of native Go data types to method
|
||||
arguments.
|
||||
|
||||
Data types encoding rules:
|
||||
* int, int8, int16, int32, int64 encoded to int;
|
||||
* float32, float64 encoded to double;
|
||||
* bool encoded to boolean;
|
||||
* string encoded to string;
|
||||
* time.Time encoded to datetime.iso8601;
|
||||
* xmlrpc.Base64 encoded to base64;
|
||||
* slice decoded to array;
|
||||
|
||||
Structs decoded to struct by following rules:
|
||||
* all public field become struct members;
|
||||
* field name become member name;
|
||||
* if field has xmlrpc tag, its value become member name.
|
||||
|
||||
Server method can accept few arguments, to handle this case there is
|
||||
special approach to handle slice of empty interfaces (`[]interface{}`).
|
||||
Each value of such slice encoded as separate argument.
|
||||
|
||||
### Result decoding
|
||||
|
||||
Result of remote function is decoded to native Go data type.
|
||||
|
||||
Data types decoding rules:
|
||||
* int, i4 decoded to int, int8, int16, int32, int64;
|
||||
* double decoded to float32, float64;
|
||||
* boolean decoded to bool;
|
||||
* string decoded to string;
|
||||
* array decoded to slice;
|
||||
* structs decoded following the rules described in previous section;
|
||||
* datetime.iso8601 decoded as time.Time data type;
|
||||
* base64 decoded to string.
|
||||
|
||||
## Implementation details
|
||||
|
||||
xmlrpc package contains clientCodec type, that implements [rpc.ClientCodec](http://golang.org/pkg/net/rpc/#ClientCodec)
|
||||
interface of [net/rpc](http://golang.org/pkg/net/rpc) package.
|
||||
|
||||
xmlrpc package works over HTTP protocol, but some internal functions
|
||||
and data type were made public to make it easier to create another
|
||||
implementation of xmlrpc that works over another protocol. To encode
|
||||
request body there is EncodeMethodCall function. To decode server
|
||||
response Response data type can be used.
|
||||
|
||||
## Contribution
|
||||
|
||||
Feel free to fork the project, submit pull requests, ask questions.
|
||||
|
||||
## Authors
|
||||
|
||||
Dmitry Maksimov (dmtmax@gmail.com)
|
144
vendor/github.com/kolo/xmlrpc/client.go
generated
vendored
144
vendor/github.com/kolo/xmlrpc/client.go
generated
vendored
@ -1,144 +0,0 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/rpc"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
*rpc.Client
|
||||
}
|
||||
|
||||
// clientCodec is rpc.ClientCodec interface implementation.
|
||||
type clientCodec struct {
|
||||
// url presents url of xmlrpc service
|
||||
url *url.URL
|
||||
|
||||
// httpClient works with HTTP protocol
|
||||
httpClient *http.Client
|
||||
|
||||
// cookies stores cookies received on last request
|
||||
cookies http.CookieJar
|
||||
|
||||
// responses presents map of active requests. It is required to return request id, that
|
||||
// rpc.Client can mark them as done.
|
||||
responses map[uint64]*http.Response
|
||||
|
||||
response *Response
|
||||
|
||||
// ready presents channel, that is used to link request and it`s response.
|
||||
ready chan uint64
|
||||
}
|
||||
|
||||
func (codec *clientCodec) WriteRequest(request *rpc.Request, args interface{}) (err error) {
|
||||
httpRequest, err := NewRequest(codec.url.String(), request.ServiceMethod, args)
|
||||
|
||||
if codec.cookies != nil {
|
||||
for _, cookie := range codec.cookies.Cookies(codec.url) {
|
||||
httpRequest.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var httpResponse *http.Response
|
||||
httpResponse, err = codec.httpClient.Do(httpRequest)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if codec.cookies != nil {
|
||||
codec.cookies.SetCookies(codec.url, httpResponse.Cookies())
|
||||
}
|
||||
|
||||
codec.responses[request.Seq] = httpResponse
|
||||
codec.ready <- request.Seq
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *clientCodec) ReadResponseHeader(response *rpc.Response) (err error) {
|
||||
seq := <-codec.ready
|
||||
httpResponse := codec.responses[seq]
|
||||
|
||||
if httpResponse.StatusCode < 200 || httpResponse.StatusCode >= 300 {
|
||||
return fmt.Errorf("request error: bad status code - %d", httpResponse.StatusCode)
|
||||
}
|
||||
|
||||
respData, err := ioutil.ReadAll(httpResponse.Body)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
httpResponse.Body.Close()
|
||||
|
||||
resp := NewResponse(respData)
|
||||
|
||||
if resp.Failed() {
|
||||
response.Error = fmt.Sprintf("%v", resp.Err())
|
||||
}
|
||||
|
||||
codec.response = resp
|
||||
|
||||
response.Seq = seq
|
||||
delete(codec.responses, seq)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *clientCodec) ReadResponseBody(v interface{}) (err error) {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = codec.response.Unmarshal(v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *clientCodec) Close() error {
|
||||
transport := codec.httpClient.Transport.(*http.Transport)
|
||||
transport.CloseIdleConnections()
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClient returns instance of rpc.Client object, that is used to send request to xmlrpc service.
|
||||
func NewClient(requrl string, transport http.RoundTripper) (*Client, error) {
|
||||
if transport == nil {
|
||||
transport = http.DefaultTransport
|
||||
}
|
||||
|
||||
httpClient := &http.Client{Transport: transport}
|
||||
|
||||
jar, err := cookiejar.New(nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := url.Parse(requrl)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
codec := clientCodec{
|
||||
url: u,
|
||||
httpClient: httpClient,
|
||||
ready: make(chan uint64),
|
||||
responses: make(map[uint64]*http.Response),
|
||||
cookies: jar,
|
||||
}
|
||||
|
||||
return &Client{rpc.NewClientWithCodec(&codec)}, nil
|
||||
}
|
449
vendor/github.com/kolo/xmlrpc/decoder.go
generated
vendored
449
vendor/github.com/kolo/xmlrpc/decoder.go
generated
vendored
@ -1,449 +0,0 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const iso8601 = "20060102T15:04:05"
|
||||
|
||||
var (
|
||||
// CharsetReader is a function to generate reader which converts a non UTF-8
|
||||
// charset into UTF-8.
|
||||
CharsetReader func(string, io.Reader) (io.Reader, error)
|
||||
|
||||
invalidXmlError = errors.New("invalid xml")
|
||||
)
|
||||
|
||||
type TypeMismatchError string
|
||||
|
||||
func (e TypeMismatchError) Error() string { return string(e) }
|
||||
|
||||
type decoder struct {
|
||||
*xml.Decoder
|
||||
}
|
||||
|
||||
func unmarshal(data []byte, v interface{}) (err error) {
|
||||
dec := &decoder{xml.NewDecoder(bytes.NewBuffer(data))}
|
||||
|
||||
if CharsetReader != nil {
|
||||
dec.CharsetReader = CharsetReader
|
||||
}
|
||||
|
||||
var tok xml.Token
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
if t.Name.Local == "value" {
|
||||
val := reflect.ValueOf(v)
|
||||
if val.Kind() != reflect.Ptr {
|
||||
return errors.New("non-pointer value passed to unmarshal")
|
||||
}
|
||||
if err = dec.decodeValue(val.Elem()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read until end of document
|
||||
err = dec.Skip()
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *decoder) decodeValue(val reflect.Value) error {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
val.Set(reflect.New(val.Type().Elem()))
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
var typeName string
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.EndElement); ok {
|
||||
if t.Name.Local == "value" {
|
||||
return nil
|
||||
} else {
|
||||
return invalidXmlError
|
||||
}
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
typeName = t.Name.Local
|
||||
break
|
||||
}
|
||||
|
||||
// Treat value data without type identifier as string
|
||||
if t, ok := tok.(xml.CharData); ok {
|
||||
if value := strings.TrimSpace(string(t)); value != "" {
|
||||
if err = checkType(val, reflect.String); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetString(value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch typeName {
|
||||
case "struct":
|
||||
ismap := false
|
||||
pmap := val
|
||||
valType := val.Type()
|
||||
|
||||
if err = checkType(val, reflect.Struct); err != nil {
|
||||
if checkType(val, reflect.Map) == nil {
|
||||
if valType.Key().Kind() != reflect.String {
|
||||
return fmt.Errorf("only maps with string key type can be unmarshalled")
|
||||
}
|
||||
ismap = true
|
||||
} else if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
var dummy map[string]interface{}
|
||||
pmap = reflect.New(reflect.TypeOf(dummy)).Elem()
|
||||
valType = pmap.Type()
|
||||
ismap = true
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var fields map[string]reflect.Value
|
||||
|
||||
if !ismap {
|
||||
fields = make(map[string]reflect.Value)
|
||||
|
||||
for i := 0; i < valType.NumField(); i++ {
|
||||
field := valType.Field(i)
|
||||
fieldVal := val.FieldByName(field.Name)
|
||||
|
||||
if fieldVal.CanSet() {
|
||||
if fn := field.Tag.Get("xmlrpc"); fn != "" {
|
||||
fields[fn] = fieldVal
|
||||
} else {
|
||||
fields[field.Name] = fieldVal
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create initial empty map
|
||||
pmap.Set(reflect.MakeMap(valType))
|
||||
}
|
||||
|
||||
// Process struct members.
|
||||
StructLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if t.Name.Local != "member" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
tagName, fieldName, err := dec.readTag()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tagName != "name" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
var fv reflect.Value
|
||||
ok := true
|
||||
|
||||
if !ismap {
|
||||
fv, ok = fields[string(fieldName)]
|
||||
} else {
|
||||
fv = reflect.New(valType.Elem())
|
||||
}
|
||||
|
||||
if ok {
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
if t, ok := tok.(xml.StartElement); ok && t.Name.Local == "value" {
|
||||
if err = dec.decodeValue(fv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// </value>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// </member>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ismap {
|
||||
pmap.SetMapIndex(reflect.ValueOf(string(fieldName)), reflect.Indirect(fv))
|
||||
val.Set(pmap)
|
||||
}
|
||||
case xml.EndElement:
|
||||
break StructLoop
|
||||
}
|
||||
}
|
||||
case "array":
|
||||
pslice := val
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
var dummy []interface{}
|
||||
pslice = reflect.New(reflect.TypeOf(dummy)).Elem()
|
||||
} else if err = checkType(val, reflect.Slice); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ArrayLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if t.Name.Local != "data" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
slice := reflect.MakeSlice(pslice.Type(), 0, 0)
|
||||
|
||||
DataLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch tt := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if tt.Name.Local != "value" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
v := reflect.New(pslice.Type().Elem())
|
||||
if err = dec.decodeValue(v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slice = reflect.Append(slice, v.Elem())
|
||||
|
||||
// </value>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
case xml.EndElement:
|
||||
pslice.Set(slice)
|
||||
val.Set(pslice)
|
||||
break DataLoop
|
||||
}
|
||||
}
|
||||
case xml.EndElement:
|
||||
break ArrayLoop
|
||||
}
|
||||
}
|
||||
default:
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data []byte
|
||||
|
||||
switch t := tok.(type) {
|
||||
case xml.EndElement:
|
||||
return nil
|
||||
case xml.CharData:
|
||||
data = []byte(t.Copy())
|
||||
default:
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
switch typeName {
|
||||
case "int", "i4", "i8":
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
i, err := strconv.ParseInt(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pi := reflect.New(reflect.TypeOf(i)).Elem()
|
||||
pi.SetInt(i)
|
||||
val.Set(pi)
|
||||
} else if err = checkType(val, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i, err := strconv.ParseInt(string(data), 10, val.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetInt(i)
|
||||
}
|
||||
case "string", "base64":
|
||||
str := string(data)
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
pstr := reflect.New(reflect.TypeOf(str)).Elem()
|
||||
pstr.SetString(str)
|
||||
val.Set(pstr)
|
||||
} else if err = checkType(val, reflect.String); err != nil {
|
||||
return err
|
||||
} else {
|
||||
val.SetString(str)
|
||||
}
|
||||
case "dateTime.iso8601":
|
||||
t, err := time.Parse(iso8601, string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
ptime := reflect.New(reflect.TypeOf(t)).Elem()
|
||||
ptime.Set(reflect.ValueOf(t))
|
||||
val.Set(ptime)
|
||||
} else if _, ok := val.Interface().(time.Time); !ok {
|
||||
return TypeMismatchError(fmt.Sprintf("error: type mismatch error - can't decode %v to time", val.Kind()))
|
||||
} else {
|
||||
val.Set(reflect.ValueOf(t))
|
||||
}
|
||||
case "boolean":
|
||||
v, err := strconv.ParseBool(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
pv := reflect.New(reflect.TypeOf(v)).Elem()
|
||||
pv.SetBool(v)
|
||||
val.Set(pv)
|
||||
} else if err = checkType(val, reflect.Bool); err != nil {
|
||||
return err
|
||||
} else {
|
||||
val.SetBool(v)
|
||||
}
|
||||
case "double":
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
i, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pdouble := reflect.New(reflect.TypeOf(i)).Elem()
|
||||
pdouble.SetFloat(i)
|
||||
val.Set(pdouble)
|
||||
} else if err = checkType(val, reflect.Float32, reflect.Float64); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i, err := strconv.ParseFloat(string(data), val.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetFloat(i)
|
||||
}
|
||||
default:
|
||||
return errors.New("unsupported type")
|
||||
}
|
||||
|
||||
// </type>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *decoder) readTag() (string, []byte, error) {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
var name string
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
name = t.Name.Local
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
value, err := dec.readCharData()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return name, value, dec.Skip()
|
||||
}
|
||||
|
||||
func (dec *decoder) readCharData() ([]byte, error) {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.CharData); ok {
|
||||
return []byte(t.Copy()), nil
|
||||
} else {
|
||||
return nil, invalidXmlError
|
||||
}
|
||||
}
|
||||
|
||||
func checkType(val reflect.Value, kinds ...reflect.Kind) error {
|
||||
if len(kinds) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
match := false
|
||||
|
||||
for _, kind := range kinds {
|
||||
if val.Kind() == kind {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
return TypeMismatchError(fmt.Sprintf("error: type mismatch - can't unmarshal %v to %v",
|
||||
val.Kind(), kinds[0]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
164
vendor/github.com/kolo/xmlrpc/encoder.go
generated
vendored
164
vendor/github.com/kolo/xmlrpc/encoder.go
generated
vendored
@ -1,164 +0,0 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type encodeFunc func(reflect.Value) ([]byte, error)
|
||||
|
||||
func marshal(v interface{}) ([]byte, error) {
|
||||
if v == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(v)
|
||||
return encodeValue(val)
|
||||
}
|
||||
|
||||
func encodeValue(val reflect.Value) ([]byte, error) {
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
if val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface {
|
||||
if val.IsNil() {
|
||||
return []byte("<value/>"), nil
|
||||
}
|
||||
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Struct:
|
||||
switch val.Interface().(type) {
|
||||
case time.Time:
|
||||
t := val.Interface().(time.Time)
|
||||
b = []byte(fmt.Sprintf("<dateTime.iso8601>%s</dateTime.iso8601>", t.Format(iso8601)))
|
||||
default:
|
||||
b, err = encodeStruct(val)
|
||||
}
|
||||
case reflect.Map:
|
||||
b, err = encodeMap(val)
|
||||
case reflect.Slice:
|
||||
b, err = encodeSlice(val)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
b = []byte(fmt.Sprintf("<int>%s</int>", strconv.FormatInt(val.Int(), 10)))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
b = []byte(fmt.Sprintf("<i4>%s</i4>", strconv.FormatUint(val.Uint(), 10)))
|
||||
case reflect.Float32, reflect.Float64:
|
||||
b = []byte(fmt.Sprintf("<double>%s</double>",
|
||||
strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits())))
|
||||
case reflect.Bool:
|
||||
if val.Bool() {
|
||||
b = []byte("<boolean>1</boolean>")
|
||||
} else {
|
||||
b = []byte("<boolean>0</boolean>")
|
||||
}
|
||||
case reflect.String:
|
||||
var buf bytes.Buffer
|
||||
|
||||
xml.Escape(&buf, []byte(val.String()))
|
||||
|
||||
if _, ok := val.Interface().(Base64); ok {
|
||||
b = []byte(fmt.Sprintf("<base64>%s</base64>", buf.String()))
|
||||
} else {
|
||||
b = []byte(fmt.Sprintf("<string>%s</string>", buf.String()))
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("xmlrpc encode error: unsupported type")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []byte(fmt.Sprintf("<value>%s</value>", string(b))), nil
|
||||
}
|
||||
|
||||
func encodeStruct(val reflect.Value) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<struct>")
|
||||
|
||||
t := val.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
b.WriteString("<member>")
|
||||
f := t.Field(i)
|
||||
|
||||
name := f.Tag.Get("xmlrpc")
|
||||
if name == "" {
|
||||
name = f.Name
|
||||
}
|
||||
b.WriteString(fmt.Sprintf("<name>%s</name>", name))
|
||||
|
||||
p, err := encodeValue(val.FieldByName(f.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Write(p)
|
||||
|
||||
b.WriteString("</member>")
|
||||
}
|
||||
|
||||
b.WriteString("</struct>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func encodeMap(val reflect.Value) ([]byte, error) {
|
||||
var t = val.Type()
|
||||
|
||||
if t.Key().Kind() != reflect.String {
|
||||
return nil, fmt.Errorf("xmlrpc encode error: only maps with string keys are supported")
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<struct>")
|
||||
|
||||
keys := val.MapKeys()
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
key := keys[i]
|
||||
kval := val.MapIndex(key)
|
||||
|
||||
b.WriteString("<member>")
|
||||
b.WriteString(fmt.Sprintf("<name>%s</name>", key.String()))
|
||||
|
||||
p, err := encodeValue(kval)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.Write(p)
|
||||
b.WriteString("</member>")
|
||||
}
|
||||
|
||||
b.WriteString("</struct>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func encodeSlice(val reflect.Value) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<array><data>")
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
p, err := encodeValue(val.Index(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.Write(p)
|
||||
}
|
||||
|
||||
b.WriteString("</data></array>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
57
vendor/github.com/kolo/xmlrpc/request.go
generated
vendored
57
vendor/github.com/kolo/xmlrpc/request.go
generated
vendored
@ -1,57 +0,0 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func NewRequest(url string, method string, args interface{}) (*http.Request, error) {
|
||||
var t []interface{}
|
||||
var ok bool
|
||||
if t, ok = args.([]interface{}); !ok {
|
||||
if args != nil {
|
||||
t = []interface{}{args}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := EncodeMethodCall(method, t...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request.Header.Set("Content-Type", "text/xml")
|
||||
request.Header.Set("Content-Length", fmt.Sprintf("%d", len(body)))
|
||||
|
||||
return request, nil
|
||||
}
|
||||
|
||||
func EncodeMethodCall(method string, args ...interface{}) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
b.WriteString(`<?xml version="1.0" encoding="UTF-8"?>`)
|
||||
b.WriteString(fmt.Sprintf("<methodCall><methodName>%s</methodName>", method))
|
||||
|
||||
if args != nil {
|
||||
b.WriteString("<params>")
|
||||
|
||||
for _, arg := range args {
|
||||
p, err := marshal(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.WriteString(fmt.Sprintf("<param>%s</param>", string(p)))
|
||||
}
|
||||
|
||||
b.WriteString("</params>")
|
||||
}
|
||||
|
||||
b.WriteString("</methodCall>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
52
vendor/github.com/kolo/xmlrpc/response.go
generated
vendored
52
vendor/github.com/kolo/xmlrpc/response.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
faultRx = regexp.MustCompile(`<fault>(\s|\S)+</fault>`)
|
||||
)
|
||||
|
||||
type failedResponse struct {
|
||||
Code int `xmlrpc:"faultCode"`
|
||||
Error string `xmlrpc:"faultString"`
|
||||
}
|
||||
|
||||
func (r *failedResponse) err() error {
|
||||
return &xmlrpcError{
|
||||
code: r.Code,
|
||||
err: r.Error,
|
||||
}
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
func NewResponse(data []byte) *Response {
|
||||
return &Response{
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Response) Failed() bool {
|
||||
return faultRx.Match(r.data)
|
||||
}
|
||||
|
||||
func (r *Response) Err() error {
|
||||
failedResp := new(failedResponse)
|
||||
if err := unmarshal(r.data, failedResp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return failedResp.err()
|
||||
}
|
||||
|
||||
func (r *Response) Unmarshal(v interface{}) error {
|
||||
if err := unmarshal(r.data, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
25
vendor/github.com/kolo/xmlrpc/test_server.rb
generated
vendored
25
vendor/github.com/kolo/xmlrpc/test_server.rb
generated
vendored
@ -1,25 +0,0 @@
|
||||
# encoding: utf-8
|
||||
|
||||
require "xmlrpc/server"
|
||||
|
||||
class Service
|
||||
def time
|
||||
Time.now
|
||||
end
|
||||
|
||||
def upcase(s)
|
||||
s.upcase
|
||||
end
|
||||
|
||||
def sum(x, y)
|
||||
x + y
|
||||
end
|
||||
|
||||
def error
|
||||
raise XMLRPC::FaultException.new(500, "Server error")
|
||||
end
|
||||
end
|
||||
|
||||
server = XMLRPC::Server.new 5001, 'localhost'
|
||||
server.add_handler "service", Service.new
|
||||
server.serve
|
19
vendor/github.com/kolo/xmlrpc/xmlrpc.go
generated
vendored
19
vendor/github.com/kolo/xmlrpc/xmlrpc.go
generated
vendored
@ -1,19 +0,0 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// xmlrpcError represents errors returned on xmlrpc request.
|
||||
type xmlrpcError struct {
|
||||
code int
|
||||
err string
|
||||
}
|
||||
|
||||
// Error() method implements Error interface
|
||||
func (e *xmlrpcError) Error() string {
|
||||
return fmt.Sprintf("error: \"%s\" code: %d", e.err, e.code)
|
||||
}
|
||||
|
||||
// Base64 represents value in base64 encoding
|
||||
type Base64 string
|
22
vendor/github.com/prasmussen/gandi-api/LICENSE
generated
vendored
22
vendor/github.com/prasmussen/gandi-api/LICENSE
generated
vendored
@ -1,22 +0,0 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2013 Petter Rasmussen
|
||||
|
||||
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.
|
||||
|
208
vendor/github.com/prasmussen/gandi-api/client/client.go
generated
vendored
208
vendor/github.com/prasmussen/gandi-api/client/client.go
generated
vendored
@ -1,208 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/kolo/xmlrpc"
|
||||
)
|
||||
|
||||
const (
|
||||
// Production is the SystemType to provide to New to use the production XML API
|
||||
Production SystemType = iota
|
||||
// Testing is the SystemType to provide to New to use the test XML API
|
||||
Testing
|
||||
// LiveDNS is the SystemType to provide to New to use the Live DNS REST API
|
||||
// Full documentation of the API is available here: http://doc.livedns.gandi.net/
|
||||
LiveDNS
|
||||
)
|
||||
|
||||
// Enable/disable debug output:
|
||||
const debug = false
|
||||
|
||||
// SystemType is the type used to resolve gandi API address
|
||||
type SystemType int
|
||||
|
||||
// Url returns the actual gandi API base URL
|
||||
func (s SystemType) Url() string {
|
||||
if s == Production {
|
||||
return "https://rpc.gandi.net/xmlrpc/"
|
||||
}
|
||||
if s == LiveDNS {
|
||||
return "https://dns.api.gandi.net/api/v5/"
|
||||
}
|
||||
return "https://rpc.ote.gandi.net/xmlrpc/"
|
||||
}
|
||||
|
||||
// Client holds the configuration of a gandi client
|
||||
type Client struct {
|
||||
// Key is the API key to provide to gandi
|
||||
Key string
|
||||
// Url is the base URL of the gandi API
|
||||
Url string
|
||||
}
|
||||
|
||||
// New creates a new gandi client for the given system
|
||||
func New(apiKey string, system SystemType) *Client {
|
||||
return &Client{
|
||||
Key: apiKey,
|
||||
Url: system.Url(),
|
||||
}
|
||||
}
|
||||
|
||||
// Call performs an acual XML RPC call to the gandi API
|
||||
func (c *Client) Call(serviceMethod string, args []interface{}, reply interface{}) error {
|
||||
rpc, err := xmlrpc.NewClient(c.Url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return rpc.Call(serviceMethod, args, reply)
|
||||
}
|
||||
|
||||
// DoRest performs a request to gandi LiveDNS api and optionnally decodes the reply
|
||||
func (c *Client) DoRest(req *http.Request, decoded interface{}) (*http.Response, error) {
|
||||
if decoded != nil {
|
||||
req.Header.Set("Accept", "application/json")
|
||||
}
|
||||
client := http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode == http.StatusUnauthorized {
|
||||
return nil, fmt.Errorf("the server returned unauthorized code. Your API key might be invalid or have expired")
|
||||
}
|
||||
//
|
||||
defer func() { err = resp.Body.Close() }()
|
||||
if decoded != nil {
|
||||
b, e := ioutil.ReadAll(resp.Body)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if len(b) > 0 {
|
||||
e = json.Unmarshal(b, decoded)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
return nil, fmt.Errorf("the server returned 400 bad request (%v)", string(b))
|
||||
}
|
||||
}
|
||||
resp.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// NewJSONRequest creates a new authenticated to gandi live DNS REST API.
|
||||
// If data is not null, it will be encoded as json and prodived in the request body
|
||||
func (c *Client) NewJSONRequest(method string, url string, data interface{}) (*http.Request, error) {
|
||||
var reader io.Reader
|
||||
if data != nil {
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reader = bytes.NewReader(b)
|
||||
}
|
||||
req, err := http.NewRequest(method, fmt.Sprintf("%s/%s", strings.TrimRight(c.Url, "/"), strings.TrimLeft(url, "/")), reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if data != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
req.Header.Set("X-Api-Key", c.Key)
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Get performs a Get request to gandi Live DNS api and decodes the returned data if a not null decoded pointer is provided
|
||||
func (c *Client) Get(URI string, decoded interface{}) (*http.Response, error) {
|
||||
req, err := c.NewJSONRequest("GET", URI, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.DoRest(req, decoded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Unexpected http code %d on URL %v. expecting %d", resp.StatusCode, resp.Request.URL, http.StatusOK)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Delete performs a Delete request to gandi Live DNS api and decodes the returned data if a not null decoded pointer is provided
|
||||
func (c *Client) Delete(URI string, decoded interface{}) (*http.Response, error) {
|
||||
req, err := c.NewJSONRequest("DELETE", URI, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.DoRest(req, decoded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return nil, fmt.Errorf("Unexpected http code %d on URL %v. expecting %d", resp.StatusCode, resp.Request.URL, http.StatusNoContent)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Post performs a Post request request to gandi Live DNS api
|
||||
// - with data encoded as JSON if a not null data pointer is provided
|
||||
// - decodes the returned data if a not null decoded pointer is provided
|
||||
// - ensures the status code is an HTTP accepted
|
||||
func (c *Client) Post(URI string, data interface{}, decoded interface{}) (*http.Response, error) {
|
||||
if debug {
|
||||
fmt.Printf("DEBUG: POST URI=%s\n", URI)
|
||||
}
|
||||
req, err := c.NewJSONRequest("POST", URI, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("DEBUG: POST req=%v decoded=%v\n", req, decoded)
|
||||
}
|
||||
resp, err := c.DoRest(req, decoded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return nil, fmt.Errorf("Unexpected http code %d on URL %v. expecting %d", resp.StatusCode, resp.Request.URL, http.StatusCreated)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// Put performs a Put request to gandi Live DNS api
|
||||
// - with data encoded as JSON if a not null data pointer is provided
|
||||
// - decodes the returned data if a not null decoded pointer is provided
|
||||
func (c *Client) Put(URI string, data interface{}, decoded interface{}) (*http.Response, error) {
|
||||
req, err := c.NewJSONRequest("PUT", URI, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.DoRest(req, decoded)
|
||||
}
|
||||
|
||||
// Patch performs a Patch request to gandi Live DNS api
|
||||
// - with data encoded as JSON if a not null data pointer is provided
|
||||
// - decodes the returned data if a not null decoded pointer is provided
|
||||
// - ensures the status code is an HTTP accepted
|
||||
func (c *Client) Patch(URI string, data interface{}, decoded interface{}) (*http.Response, error) {
|
||||
req, err := c.NewJSONRequest("PATCH", URI, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.DoRest(req, decoded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusAccepted {
|
||||
return nil, fmt.Errorf("Unexpected http code %d on URL %v. expecting %d", resp.StatusCode, resp.Request.URL, http.StatusAccepted)
|
||||
}
|
||||
return resp, err
|
||||
}
|
87
vendor/github.com/prasmussen/gandi-api/domain/domain.go
generated
vendored
87
vendor/github.com/prasmussen/gandi-api/domain/domain.go
generated
vendored
@ -1,87 +0,0 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/client"
|
||||
"github.com/prasmussen/gandi-api/operation"
|
||||
)
|
||||
|
||||
type Domain struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
func New(c *client.Client) *Domain {
|
||||
return &Domain{c}
|
||||
}
|
||||
|
||||
// Check the availability of some domain
|
||||
func (self *Domain) Available(name string) (string, error) {
|
||||
var result map[string]interface{}
|
||||
domain := []string{name}
|
||||
params := []interface{}{self.Key, domain}
|
||||
if err := self.Call("domain.available", params, &result); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return result[name].(string), nil
|
||||
}
|
||||
|
||||
// Get domain information
|
||||
func (self *Domain) Info(name string) (*DomainInfo, error) {
|
||||
var res map[string]interface{}
|
||||
params := []interface{}{self.Key, name}
|
||||
if err := self.Call("domain.info", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToDomainInfo(res), nil
|
||||
}
|
||||
|
||||
// List domains associated to the contact represented by apikey
|
||||
func (self *Domain) List() ([]*DomainInfoBase, error) {
|
||||
opts := &struct {
|
||||
Page int `xmlrpc:"page"`
|
||||
}{0}
|
||||
const perPage = 100
|
||||
params := []interface{}{self.Key, opts}
|
||||
domains := make([]*DomainInfoBase, 0)
|
||||
for {
|
||||
var res []interface{}
|
||||
if err := self.Call("domain.list", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, r := range res {
|
||||
domain := ToDomainInfoBase(r.(map[string]interface{}))
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
if len(res) < perPage {
|
||||
break
|
||||
}
|
||||
opts.Page++
|
||||
}
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
// Count domains associated to the contact represented by apikey
|
||||
func (self *Domain) Count() (int64, error) {
|
||||
var result int64
|
||||
params := []interface{}{self.Key}
|
||||
if err := self.Call("domain.count", params, &result); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Create a domain
|
||||
func (self *Domain) Create(name, contactHandle string, years int64) (*operation.OperationInfo, error) {
|
||||
var res map[string]interface{}
|
||||
createArgs := map[string]interface{}{
|
||||
"admin": contactHandle,
|
||||
"bill": contactHandle,
|
||||
"owner": contactHandle,
|
||||
"tech": contactHandle,
|
||||
"duration": years,
|
||||
}
|
||||
params := []interface{}{self.Key, name, createArgs}
|
||||
if err := self.Call("domain.create", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return operation.ToOperationInfo(res), nil
|
||||
}
|
24
vendor/github.com/prasmussen/gandi-api/domain/nameservers/nameservers.go
generated
vendored
24
vendor/github.com/prasmussen/gandi-api/domain/nameservers/nameservers.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
package zone
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/client"
|
||||
"github.com/prasmussen/gandi-api/operation"
|
||||
)
|
||||
|
||||
type Nameservers struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
func New(c *client.Client) *Nameservers {
|
||||
return &Nameservers{c}
|
||||
}
|
||||
|
||||
// Set the current zone of a domain
|
||||
func (self *Nameservers) Set(domainName string, nameservers []string) (*operation.OperationInfo, error) {
|
||||
var res map[string]interface{}
|
||||
params := []interface{}{self.Key, domainName, nameservers}
|
||||
if err := self.Call("domain.nameservers.set", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return operation.ToOperationInfo(res), nil
|
||||
}
|
57
vendor/github.com/prasmussen/gandi-api/domain/structs.go
generated
vendored
57
vendor/github.com/prasmussen/gandi-api/domain/structs.go
generated
vendored
@ -1,57 +0,0 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type DomainInfoBase struct {
|
||||
AuthInfo string
|
||||
DateCreated time.Time
|
||||
DateRegistryCreation time.Time
|
||||
DateRegistryEnd time.Time
|
||||
DateUpdated time.Time
|
||||
Fqdn string
|
||||
Id int64
|
||||
Status []string
|
||||
Tld string
|
||||
}
|
||||
|
||||
type DomainInfoExtra struct {
|
||||
DateDelete time.Time
|
||||
DateHoldBegin time.Time
|
||||
DateHoldEnd time.Time
|
||||
DatePendingDeleteEnd time.Time
|
||||
DateRenewBegin time.Time
|
||||
DateRestoreEnd time.Time
|
||||
Nameservers []string
|
||||
Services []string
|
||||
ZoneId int64
|
||||
Autorenew *AutorenewInfo
|
||||
Contacts *ContactInfo
|
||||
}
|
||||
|
||||
type DomainInfo struct {
|
||||
*DomainInfoBase
|
||||
*DomainInfoExtra
|
||||
}
|
||||
|
||||
type AutorenewInfo struct {
|
||||
Active bool
|
||||
Contact string
|
||||
Id int64
|
||||
ProductId int64
|
||||
ProductTypeId int64
|
||||
}
|
||||
|
||||
type ContactInfo struct {
|
||||
Admin *ContactDetails
|
||||
Bill *ContactDetails
|
||||
Owner *ContactDetails
|
||||
Reseller *ContactDetails
|
||||
Tech *ContactDetails
|
||||
}
|
||||
|
||||
type ContactDetails struct {
|
||||
Handle string
|
||||
Id int64
|
||||
}
|
69
vendor/github.com/prasmussen/gandi-api/domain/util.go
generated
vendored
69
vendor/github.com/prasmussen/gandi-api/domain/util.go
generated
vendored
@ -1,69 +0,0 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/util"
|
||||
)
|
||||
|
||||
func ToDomainInfoBase(res map[string]interface{}) *DomainInfoBase {
|
||||
return &DomainInfoBase{
|
||||
AuthInfo: util.ToString(res["authinfo"]),
|
||||
DateCreated: util.ToTime(res["date_created"]),
|
||||
DateRegistryCreation: util.ToTime(res["date_registry_creation"]),
|
||||
DateRegistryEnd: util.ToTime(res["date_registry_end"]),
|
||||
DateUpdated: util.ToTime(res["date_updated"]),
|
||||
Fqdn: util.ToString(res["fqdn"]),
|
||||
Id: util.ToInt64(res["id"]),
|
||||
Status: util.ToStringSlice(util.ToInterfaceSlice(res["status"])),
|
||||
Tld: util.ToString(res["tld"]),
|
||||
}
|
||||
}
|
||||
|
||||
func ToDomainInfoExtra(res map[string]interface{}) *DomainInfoExtra {
|
||||
return &DomainInfoExtra{
|
||||
DateDelete: util.ToTime(res["date_delete"]),
|
||||
DateHoldBegin: util.ToTime(res["date_hold_begin"]),
|
||||
DateHoldEnd: util.ToTime(res["date_hold_end"]),
|
||||
DatePendingDeleteEnd: util.ToTime(res["date_pending_delete_end"]),
|
||||
DateRenewBegin: util.ToTime(res["date_renew_begin"]),
|
||||
DateRestoreEnd: util.ToTime(res["date_restore_end"]),
|
||||
Nameservers: util.ToStringSlice(util.ToInterfaceSlice(res["nameservers"])),
|
||||
Services: util.ToStringSlice(util.ToInterfaceSlice(res["services"])),
|
||||
ZoneId: util.ToInt64(res["zone_id"]),
|
||||
Autorenew: toAutorenewInfo(util.ToXmlrpcStruct(res["autorenew"])),
|
||||
Contacts: toContactInfo(util.ToXmlrpcStruct(res["contacts"])),
|
||||
}
|
||||
}
|
||||
|
||||
func ToDomainInfo(res map[string]interface{}) *DomainInfo {
|
||||
return &DomainInfo{
|
||||
ToDomainInfoBase(res),
|
||||
ToDomainInfoExtra(res),
|
||||
}
|
||||
}
|
||||
|
||||
func toAutorenewInfo(res map[string]interface{}) *AutorenewInfo {
|
||||
return &AutorenewInfo{
|
||||
Active: util.ToBool(res["active"]),
|
||||
Contact: util.ToString(res["contact"]),
|
||||
Id: util.ToInt64(res["id"]),
|
||||
ProductId: util.ToInt64(res["product_id"]),
|
||||
ProductTypeId: util.ToInt64(res["product_type_id"]),
|
||||
}
|
||||
}
|
||||
|
||||
func toContactInfo(res map[string]interface{}) *ContactInfo {
|
||||
return &ContactInfo{
|
||||
Admin: toContactDetails(util.ToXmlrpcStruct(res["admin"])),
|
||||
Bill: toContactDetails(util.ToXmlrpcStruct(res["bill"])),
|
||||
Owner: toContactDetails(util.ToXmlrpcStruct(res["owner"])),
|
||||
Reseller: toContactDetails(util.ToXmlrpcStruct(res["reseller"])),
|
||||
Tech: toContactDetails(util.ToXmlrpcStruct(res["tech"])),
|
||||
}
|
||||
}
|
||||
|
||||
func toContactDetails(res map[string]interface{}) *ContactDetails {
|
||||
return &ContactDetails{
|
||||
Handle: util.ToString(res["handle"]),
|
||||
Id: util.ToInt64(res["id"]),
|
||||
}
|
||||
}
|
129
vendor/github.com/prasmussen/gandi-api/domain/zone/record/record.go
generated
vendored
129
vendor/github.com/prasmussen/gandi-api/domain/zone/record/record.go
generated
vendored
@ -1,129 +0,0 @@
|
||||
package record
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/client"
|
||||
)
|
||||
|
||||
type Record struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
func New(c *client.Client) *Record {
|
||||
return &Record{c}
|
||||
}
|
||||
|
||||
// Count number of records for a given zone/version
|
||||
func (self *Record) Count(zoneId, version int64) (int64, error) {
|
||||
var result int64
|
||||
params := []interface{}{self.Key, zoneId, version}
|
||||
if err := self.Call("domain.zone.record.count", params, &result); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// List records of a version of a DNS zone
|
||||
func (self *Record) List(zoneId, version int64) ([]*RecordInfo, error) {
|
||||
opts := &struct {
|
||||
Page int `xmlrpc:"page"`
|
||||
}{0}
|
||||
const perPage = 100
|
||||
params := []interface{}{self.Key, zoneId, version, opts}
|
||||
records := make([]*RecordInfo, 0)
|
||||
for {
|
||||
var res []interface{}
|
||||
if err := self.Call("domain.zone.record.list", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, r := range res {
|
||||
record := ToRecordInfo(r.(map[string]interface{}))
|
||||
records = append(records, record)
|
||||
}
|
||||
if len(res) < perPage {
|
||||
break
|
||||
}
|
||||
opts.Page++
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// Add a new record to zone
|
||||
func (self *Record) Add(args RecordAdd) (*RecordInfo, error) {
|
||||
var res map[string]interface{}
|
||||
createArgs := map[string]interface{}{
|
||||
"name": args.Name,
|
||||
"type": args.Type,
|
||||
"value": args.Value,
|
||||
"ttl": args.Ttl,
|
||||
}
|
||||
|
||||
params := []interface{}{self.Key, args.Zone, args.Version, createArgs}
|
||||
if err := self.Call("domain.zone.record.add", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToRecordInfo(res), nil
|
||||
}
|
||||
|
||||
// Remove a record from a zone/version
|
||||
func (self *Record) Delete(zoneId, version int64, recordId string) (bool, error) {
|
||||
var res int64
|
||||
deleteArgs := map[string]interface{}{"id": recordId}
|
||||
params := []interface{}{self.Key, zoneId, version, deleteArgs}
|
||||
if err := self.Call("domain.zone.record.delete", params, &res); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return (res == 1), nil
|
||||
}
|
||||
|
||||
// Update a record from zone/version
|
||||
func (self *Record) Update(args RecordUpdate) ([]*RecordInfo, error) {
|
||||
var res []interface{}
|
||||
updateArgs := map[string]interface{}{
|
||||
"name": args.Name,
|
||||
"type": args.Type,
|
||||
"value": args.Value,
|
||||
"ttl": args.Ttl,
|
||||
}
|
||||
updateOpts := map[string]string{
|
||||
"id": args.Id,
|
||||
}
|
||||
|
||||
params := []interface{}{self.Key, args.Zone, args.Version, updateOpts, updateArgs}
|
||||
if err := self.Call("domain.zone.record.update", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := make([]*RecordInfo, 0)
|
||||
for _, r := range res {
|
||||
record := ToRecordInfo(r.(map[string]interface{}))
|
||||
records = append(records, record)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// SetRecords replaces the entire zone with new records.
|
||||
func (self *Record) SetRecords(zone_id, version_id int64, args []RecordSet) ([]*RecordInfo, error) {
|
||||
var res []interface{}
|
||||
|
||||
params := []interface{}{self.Key, zone_id, version_id, args}
|
||||
if err := self.Call("domain.zone.record.set", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := make([]*RecordInfo, 0)
|
||||
for _, r := range res {
|
||||
record := ToRecordInfo(r.(map[string]interface{}))
|
||||
records = append(records, record)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
//// Set the current zone of a domain
|
||||
//func (self *Record) Set(domainName string, id int64) (*domain.DomainInfo, error) {
|
||||
// var res map[string]interface{}
|
||||
// params := []interface{}{self.Key, domainName, id}
|
||||
// if err := self.zone.set", params, &res); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return domain.ToDomainInfo(res), nil
|
||||
//}
|
30
vendor/github.com/prasmussen/gandi-api/domain/zone/record/structs.go
generated
vendored
30
vendor/github.com/prasmussen/gandi-api/domain/zone/record/structs.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
package record
|
||||
|
||||
type RecordInfo struct {
|
||||
Id string
|
||||
Name string
|
||||
Ttl int64
|
||||
Type string
|
||||
Value string
|
||||
}
|
||||
|
||||
type RecordAdd struct {
|
||||
Zone int64 `goptions:"-z, --zone, obligatory, description='Zone id'"`
|
||||
Version int64 `goptions:"-v, --version, obligatory, description='Zone version'"`
|
||||
Name string `goptions:"-n, --name, obligatory, description='Record name. Relative name, may contain leading wildcard. @ for empty name'"`
|
||||
Type string `goptions:"-t, --type, obligatory, description='Record type'"`
|
||||
Value string `goptions:"-V, --value, obligatory, description='Value for record. Semantics depends on the record type.'"`
|
||||
Ttl int64 `goptions:"-T, --ttl, description='Time to live, in seconds, between 5 minutes and 30 days'"`
|
||||
}
|
||||
|
||||
type RecordUpdate struct {
|
||||
Zone int64 `goptions:"-z, --zone, obligatory, description='Zone id'"`
|
||||
Version int64 `goptions:"-v, --version, obligatory, description='Zone version'"`
|
||||
Name string `goptions:"-n, --name, obligatory, description='Record name. Relative name, may contain leading wildcard. @ for empty name'"`
|
||||
Type string `goptions:"-t, --type, obligatory, description='Record type'"`
|
||||
Value string `goptions:"-V, --value, obligatory, description='Value for record. Semantics depends on the record type.'"`
|
||||
Ttl int64 `goptions:"-T, --ttl, description='Time to live, in seconds, between 5 minutes and 30 days'"`
|
||||
Id string `goptions:"-r, --record, obligatory, description='Record id'"`
|
||||
}
|
||||
|
||||
type RecordSet map[string]interface{}
|
15
vendor/github.com/prasmussen/gandi-api/domain/zone/record/util.go
generated
vendored
15
vendor/github.com/prasmussen/gandi-api/domain/zone/record/util.go
generated
vendored
@ -1,15 +0,0 @@
|
||||
package record
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/util"
|
||||
)
|
||||
|
||||
func ToRecordInfo(res map[string]interface{}) *RecordInfo {
|
||||
return &RecordInfo{
|
||||
Id: util.ToString(res["id"]),
|
||||
Name: util.ToString(res["name"]),
|
||||
Ttl: util.ToInt64(res["ttl"]),
|
||||
Type: util.ToString(res["type"]),
|
||||
Value: util.ToString(res["value"]),
|
||||
}
|
||||
}
|
24
vendor/github.com/prasmussen/gandi-api/domain/zone/structs.go
generated
vendored
24
vendor/github.com/prasmussen/gandi-api/domain/zone/structs.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
package zone
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ZoneInfoBase struct {
|
||||
DateUpdated time.Time
|
||||
Id int64
|
||||
Name string
|
||||
Public bool
|
||||
Version int64
|
||||
}
|
||||
|
||||
type ZoneInfoExtra struct {
|
||||
Domains int64
|
||||
Owner string
|
||||
Versions []int64
|
||||
}
|
||||
|
||||
type ZoneInfo struct {
|
||||
*ZoneInfoBase
|
||||
*ZoneInfoExtra
|
||||
}
|
30
vendor/github.com/prasmussen/gandi-api/domain/zone/util.go
generated
vendored
30
vendor/github.com/prasmussen/gandi-api/domain/zone/util.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
package zone
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/util"
|
||||
)
|
||||
|
||||
func ToZoneInfoBase(res map[string]interface{}) *ZoneInfoBase {
|
||||
return &ZoneInfoBase{
|
||||
DateUpdated: util.ToTime(res["date_updated"]),
|
||||
Id: util.ToInt64(res["id"]),
|
||||
Name: util.ToString(res["name"]),
|
||||
Public: util.ToBool(res["public"]),
|
||||
Version: util.ToInt64(res["version"]),
|
||||
}
|
||||
}
|
||||
|
||||
func ToZoneInfoExtra(res map[string]interface{}) *ZoneInfoExtra {
|
||||
return &ZoneInfoExtra{
|
||||
Domains: util.ToInt64(res["domains"]),
|
||||
Owner: util.ToString(res["owner"]),
|
||||
Versions: util.ToIntSlice(util.ToInterfaceSlice(res["versions"])),
|
||||
}
|
||||
}
|
||||
|
||||
func ToZoneInfo(res map[string]interface{}) *ZoneInfo {
|
||||
return &ZoneInfo{
|
||||
ToZoneInfoBase(res),
|
||||
ToZoneInfoExtra(res),
|
||||
}
|
||||
}
|
10
vendor/github.com/prasmussen/gandi-api/domain/zone/version/structs.go
generated
vendored
10
vendor/github.com/prasmussen/gandi-api/domain/zone/version/structs.go
generated
vendored
@ -1,10 +0,0 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type VersionInfo struct {
|
||||
Id int64
|
||||
DateCreated time.Time
|
||||
}
|
13
vendor/github.com/prasmussen/gandi-api/domain/zone/version/util.go
generated
vendored
13
vendor/github.com/prasmussen/gandi-api/domain/zone/version/util.go
generated
vendored
@ -1,13 +0,0 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/util"
|
||||
)
|
||||
|
||||
|
||||
func ToVersionInfo(res map[string]interface{}) *VersionInfo {
|
||||
return &VersionInfo{
|
||||
Id: util.ToInt64(res["id"]),
|
||||
DateCreated: util.ToTime(res["date_created"]),
|
||||
}
|
||||
}
|
68
vendor/github.com/prasmussen/gandi-api/domain/zone/version/version.go
generated
vendored
68
vendor/github.com/prasmussen/gandi-api/domain/zone/version/version.go
generated
vendored
@ -1,68 +0,0 @@
|
||||
package version
|
||||
|
||||
import "github.com/prasmussen/gandi-api/client"
|
||||
|
||||
type Version struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
func New(c *client.Client) *Version {
|
||||
return &Version{c}
|
||||
}
|
||||
|
||||
// Count this zone versions
|
||||
func (self *Version) Count(zoneId int64) (int64, error) {
|
||||
var result int64
|
||||
params := []interface{}{self.Key, zoneId}
|
||||
if err := self.Call("domain.zone.version.count", params, &result); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// List this zone versions, with their creation date
|
||||
func (self *Version) List(zoneId int64) ([]*VersionInfo, error) {
|
||||
var res []interface{}
|
||||
params := []interface{}{self.Key, zoneId}
|
||||
if err := self.Call("domain.zone.version.list", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
versions := make([]*VersionInfo, 0)
|
||||
for _, r := range res {
|
||||
version := ToVersionInfo(r.(map[string]interface{}))
|
||||
versions = append(versions, version)
|
||||
}
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
// Create a new version from another version. This will duplicate the version’s records
|
||||
func (self *Version) New(zoneId, version int64) (int64, error) {
|
||||
var res int64
|
||||
|
||||
params := []interface{}{self.Key, zoneId, version}
|
||||
if err := self.Call("domain.zone.version.new", params, &res); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Delete a specific version
|
||||
func (self *Version) Delete(zoneId, version int64) (bool, error) {
|
||||
var res bool
|
||||
params := []interface{}{self.Key, zoneId, version}
|
||||
if err := self.Call("domain.zone.version.delete", params, &res); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Set the active version of a zone
|
||||
func (self *Version) Set(zoneId, version int64) (bool, error) {
|
||||
var res bool
|
||||
params := []interface{}{self.Key, zoneId, version}
|
||||
if err := self.Call("domain.zone.version.set", params, &res); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
81
vendor/github.com/prasmussen/gandi-api/domain/zone/zone.go
generated
vendored
81
vendor/github.com/prasmussen/gandi-api/domain/zone/zone.go
generated
vendored
@ -1,81 +0,0 @@
|
||||
package zone
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/client"
|
||||
"github.com/prasmussen/gandi-api/domain"
|
||||
)
|
||||
|
||||
type Zone struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
func New(c *client.Client) *Zone {
|
||||
return &Zone{c}
|
||||
}
|
||||
|
||||
// Counts accessible zones
|
||||
func (self *Zone) Count() (int64, error) {
|
||||
var result int64
|
||||
params := []interface{}{self.Key}
|
||||
if err := self.Call("domain.zone.count", params, &result); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Get zone information
|
||||
func (self *Zone) Info(id int64) (*ZoneInfo, error) {
|
||||
var res map[string]interface{}
|
||||
params := []interface{}{self.Key, id}
|
||||
if err := self.Call("domain.zone.info", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToZoneInfo(res), nil
|
||||
}
|
||||
|
||||
// List accessible DNS zones.
|
||||
func (self *Zone) List() ([]*ZoneInfoBase, error) {
|
||||
var res []interface{}
|
||||
params := []interface{}{self.Key}
|
||||
if err := self.Call("domain.zone.list", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zones := make([]*ZoneInfoBase, 0)
|
||||
for _, r := range res {
|
||||
zone := ToZoneInfoBase(r.(map[string]interface{}))
|
||||
zones = append(zones, zone)
|
||||
}
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
// Create a zone
|
||||
func (self *Zone) Create(name string) (*ZoneInfo, error) {
|
||||
var res map[string]interface{}
|
||||
createArgs := map[string]interface{}{"name": name}
|
||||
params := []interface{}{self.Key, createArgs}
|
||||
if err := self.Call("domain.zone.create", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToZoneInfo(res), nil
|
||||
}
|
||||
|
||||
// Delete a zone
|
||||
func (self *Zone) Delete(id int64) (bool, error) {
|
||||
var res bool
|
||||
params := []interface{}{self.Key, id}
|
||||
if err := self.Call("domain.zone.delete", params, &res); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Set the current zone of a domain
|
||||
func (self *Zone) Set(domainName string, id int64) (*domain.DomainInfo, error) {
|
||||
var res map[string]interface{}
|
||||
params := []interface{}{self.Key, domainName, id}
|
||||
if err := self.Call("domain.zone.set", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return domain.ToDomainInfo(res), nil
|
||||
}
|
35
vendor/github.com/prasmussen/gandi-api/live_dns/domain/domain.go
generated
vendored
35
vendor/github.com/prasmussen/gandi-api/live_dns/domain/domain.go
generated
vendored
@ -1,35 +0,0 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prasmussen/gandi-api/client"
|
||||
"github.com/prasmussen/gandi-api/live_dns/record"
|
||||
)
|
||||
|
||||
// Domain holds the domain client stucture
|
||||
type Domain struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New instanciates a new Domain client
|
||||
func New(c *client.Client) *Domain {
|
||||
return &Domain{c}
|
||||
}
|
||||
|
||||
// List domains associated to the contact represented by apikey
|
||||
func (d *Domain) List() (domains []*InfoBase, err error) {
|
||||
_, err = d.Get("/domains", &domains)
|
||||
return
|
||||
}
|
||||
|
||||
// Info Gets domain information
|
||||
func (d *Domain) Info(name string) (infos *Info, err error) {
|
||||
_, err = d.Get(fmt.Sprintf("/domains/%s", name), &infos)
|
||||
return
|
||||
}
|
||||
|
||||
// Records gets a record client for the current domain
|
||||
func (d *Domain) Records(name string) record.Manager {
|
||||
return record.New(d.Client, fmt.Sprintf("/domains/%s", name))
|
||||
}
|
32
vendor/github.com/prasmussen/gandi-api/live_dns/domain/structs.go
generated
vendored
32
vendor/github.com/prasmussen/gandi-api/live_dns/domain/structs.go
generated
vendored
@ -1,32 +0,0 @@
|
||||
package domain
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
// InfoBase holds the basic domain informations returned by the domain listing
|
||||
type InfoBase struct {
|
||||
// Fqdn stands for Fully Qualified Domain Name. It is the domain name managed by gandi (<domain>.<tld>)
|
||||
Fqdn string `json:"fqdn,omitempty"`
|
||||
// DomainRecordsHref contains the API URL to retrieve all records registered for the domain
|
||||
DomainRecordsHref string `json:"domain_records_href,omitempty"`
|
||||
// DomainHref contains the API URL to retrieve full DomainInfo for this domain
|
||||
DomainHref string `json:"domain_href,omitempty"`
|
||||
}
|
||||
|
||||
// InfoExtra holds the extra domain informations returned by domain details
|
||||
type InfoExtra struct {
|
||||
// ZomeUUID is the id of the zone currently configured on this domain
|
||||
ZoneUUID *uuid.UUID `json:"zone_uuid,omitempty"`
|
||||
// DomainKeysHref contains the API URL to list DNSSEC keys for this domain
|
||||
// note: DNSSEC is currently not supported by this library.
|
||||
DomainKeysHref string `json:"domain_keys_href,omitempty"`
|
||||
// ZoneHref contains the API URL to retrieve informations about the zone
|
||||
ZoneHref string `json:"zone_href,omitempty"`
|
||||
// ZoneRecordsHref contains the API URL to retrieve all records registered for the zone linked to this domain
|
||||
ZoneRecordsHref string `json:"zone_records_href,omitempty"`
|
||||
}
|
||||
|
||||
// Info holds all domain information
|
||||
type Info struct {
|
||||
*InfoBase
|
||||
*InfoExtra
|
||||
}
|
185
vendor/github.com/prasmussen/gandi-api/live_dns/record/record.go
generated
vendored
185
vendor/github.com/prasmussen/gandi-api/live_dns/record/record.go
generated
vendored
@ -1,185 +0,0 @@
|
||||
package record
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/prasmussen/gandi-api/client"
|
||||
)
|
||||
|
||||
// Record holds the zone client structure
|
||||
type Record struct {
|
||||
*client.Client
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// Creator is an interface to create new record entries
|
||||
type Creator interface {
|
||||
// Create creates a new record entry
|
||||
// possible calls are:
|
||||
// Create(recordInfo)
|
||||
// Create(recordInfo, "entry")
|
||||
// Create(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
Create(recordInfo Info, args ...string) (status *Status, err error)
|
||||
}
|
||||
|
||||
// Updater is an interface to update existing record entries
|
||||
type Updater interface {
|
||||
// Update creates a new record entry
|
||||
// possible calls are:
|
||||
// Update(recordInfo)
|
||||
// Update(recordInfo, "entry")
|
||||
// Update(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
Update(recordInfo Info, args ...string) (status *Status, err error)
|
||||
}
|
||||
|
||||
// Lister is an interface to list existing record entries
|
||||
type Lister interface {
|
||||
// List creates a new record entry
|
||||
// possible calls are:
|
||||
// List(recordInfo)
|
||||
// List(recordInfo, "entry")
|
||||
// List(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
List(args ...string) (list []*Info, err error)
|
||||
}
|
||||
|
||||
// Deleter is an interface to delete existing record entries
|
||||
type Deleter interface {
|
||||
// Delete creates a new record entry
|
||||
// possible calls are:
|
||||
// Delete(recordInfo)
|
||||
// Delete(recordInfo, "entry")
|
||||
// Delete(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
Delete(args ...string) (err error)
|
||||
}
|
||||
|
||||
// Manager is an interface to manage records (for a zone or domain)
|
||||
type Manager interface {
|
||||
Creator
|
||||
Updater
|
||||
Lister
|
||||
Deleter
|
||||
}
|
||||
|
||||
// New instanciates a new instance of a Zone client
|
||||
func New(c *client.Client, prefix string) *Record {
|
||||
return &Record{c, prefix}
|
||||
}
|
||||
|
||||
func (r *Record) uri(pattern string, paths ...string) string {
|
||||
args := make([]interface{}, len(paths))
|
||||
for i, v := range paths {
|
||||
args[i] = v
|
||||
}
|
||||
return fmt.Sprintf("%s/%s",
|
||||
strings.TrimRight(r.Prefix, "/"),
|
||||
strings.TrimLeft(fmt.Sprintf(pattern, args...), "/"))
|
||||
}
|
||||
|
||||
func (r *Record) formatCallError(function string, args ...string) error {
|
||||
format := "unexpected arguments for function %s." +
|
||||
" supported calls are: %s(), %s(<Name>), %s(<Name>, <Type>)" +
|
||||
" %s called with"
|
||||
a := []interface{}{
|
||||
function,
|
||||
function, function, function,
|
||||
function,
|
||||
}
|
||||
for _, v := range args {
|
||||
format = format + " %s"
|
||||
a = append(a, v)
|
||||
}
|
||||
return fmt.Errorf(format, a...)
|
||||
}
|
||||
|
||||
// Create creates a new record entry
|
||||
// possible calls are:
|
||||
// Create(recordInfo)
|
||||
// Create(recordInfo, "entry")
|
||||
// Create(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
func (r *Record) Create(recordInfo Info, args ...string) (status *Status, err error) {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
_, err = r.Post(r.uri("/records"), recordInfo, &status)
|
||||
case 1:
|
||||
_, err = r.Post(r.uri("/records/%s", args...), recordInfo, &status)
|
||||
case 2:
|
||||
_, err = r.Post(r.uri("/records/%s/%s", args...), recordInfo, &status)
|
||||
default:
|
||||
err = r.formatCallError("Create", args...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Update creates a new record entry
|
||||
// possible calls are:
|
||||
// Update(recordInfo)
|
||||
// Update(recordInfo, "entry")
|
||||
// Update(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
func (r *Record) Update(recordInfo Info, args ...string) (status *Status, err error) {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
_, err = r.Put(r.uri("/records"), recordInfo, &status)
|
||||
case 1:
|
||||
_, err = r.Put(r.uri("/records/%s", args...), recordInfo, &status)
|
||||
case 2:
|
||||
_, err = r.Put(r.uri("/records/%s/%s", args...), recordInfo, &status)
|
||||
default:
|
||||
err = r.formatCallError("Update", args...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// List creates a new record entry
|
||||
// possible calls are:
|
||||
// List(recordInfo)
|
||||
// List(recordInfo, "entry")
|
||||
// List(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
func (r *Record) List(args ...string) (list []*Info, err error) {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
_, err = r.Get(r.uri("/records"), &list)
|
||||
case 1:
|
||||
_, err = r.Get(r.uri("/records/%s", args...), &list)
|
||||
case 2:
|
||||
_, err = r.Get(r.uri("/records/%s/%s", args...), &list)
|
||||
default:
|
||||
err = r.formatCallError("List", args...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Delete creates a new record entry
|
||||
// possible calls are:
|
||||
// Delete(recordInfo)
|
||||
// Delete(recordInfo, "entry")
|
||||
// Delete(recordInfo, "entry", "type")
|
||||
// where "entry" matches entry.example.com
|
||||
// and "type" is the record type (A, CNAME, ...)
|
||||
func (r *Record) Delete(args ...string) (err error) {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
_, err = r.Client.Delete(r.uri("/records"), nil)
|
||||
case 1:
|
||||
_, err = r.Client.Delete(r.uri("/records/%s", args...), nil)
|
||||
case 2:
|
||||
_, err = r.Client.Delete(r.uri("/records/%s/%s", args...), nil)
|
||||
default:
|
||||
err = r.formatCallError("Delete", args...)
|
||||
}
|
||||
return
|
||||
}
|
68
vendor/github.com/prasmussen/gandi-api/live_dns/record/structs.go
generated
vendored
68
vendor/github.com/prasmussen/gandi-api/live_dns/record/structs.go
generated
vendored
@ -1,68 +0,0 @@
|
||||
package record
|
||||
|
||||
const (
|
||||
// A is the type of record that hold a 32-bit IPv4 address, most commonly used to map hostnames to an IP address of the host
|
||||
A = "A"
|
||||
// AAAA is the type of record that hold a Returns a 128-bit IPv6 address, most commonly used to map hostnames to an IP address of the host
|
||||
AAAA = "AAAA"
|
||||
// CAA is the type of record that hold the DNS Certification Authority Authorization, constraining acceptable CAs for a host/domain
|
||||
CAA = "CAA"
|
||||
// CDS is the type of record that hold the child copy of DS record, for transfer to parent
|
||||
CDS = "CDS"
|
||||
// CNAME is the type of record that hold the alias of one name to another: the DNS lookup will continue by retrying the lookup with the new name
|
||||
CNAME = "CNAME"
|
||||
// DNAME is the type of record that hold the alias for a name and all its subnames, unlike CNAME, which is an alias for only the exact name.
|
||||
// Like a CNAME record, the DNS lookup will continue by retrying the lookup with the new name
|
||||
DNAME = "DNAME"
|
||||
// DS is the type of record that hold the record used to identify the DNSSEC signing key of a delegated zone
|
||||
DS = "DS"
|
||||
// LOC is the type of record that specifies a geographical location associated with a domain name
|
||||
LOC = "LOC"
|
||||
// MX is the type of record that maps a domain name to a list of message transfer agents for that domain
|
||||
MX = "MX"
|
||||
// NS is the type of record that delegates a DNS zone to use the given authoritative name servers
|
||||
NS = "NS"
|
||||
// PTR is the type of record that hold a pointer to a canonical name. Unlike a CNAME, DNS processing stops and just the name is returned.
|
||||
// The most common use is for implementing reverse DNS lookups, but other uses include such things as DNS-SD.
|
||||
PTR = "PTR"
|
||||
// SPF (99) (from RFC 4408) was specified as part of the Sender Policy Framework protocol as an alternative to storing SPF data in TXT records,
|
||||
// using the same format. It was later found that the majority of SPF deployments lack proper support for this record type, and support for it was discontinued in RFC 7208
|
||||
SPF = "SPF"
|
||||
// SRV is the type of record that hold the generalized service location record, used for newer protocols instead of creating protocol-specific records such as MX.
|
||||
SRV = "SRV"
|
||||
// SSHFP is the type of record that hold resource record for publishing SSH public host key fingerprints in the DNS System,
|
||||
// in order to aid in verifying the authenticity of the host. RFC 6594 defines ECC SSH keys and SHA-256 hashes
|
||||
SSHFP = "SSHFP"
|
||||
// TLSA is the type of record that hold a record for DANE.
|
||||
// record for DANE. RFC 6698 defines "The TLSA DNS resource record is used to associate a TLS server
|
||||
// certificate or public key with the domain name where the record is found, thus forming a 'TLSA certificate association'".
|
||||
TLSA = "TLSA"
|
||||
// TXT is the type of record that hold human readable text.
|
||||
// Since the early 1990s, however, this record more often carries machine-readable data,
|
||||
// such as specified by RFC 1464, opportunistic encryption, Sender Policy Framework, DKIM, DMARC, DNS-SD, etc.
|
||||
TXT = "TXT"
|
||||
// WKS is the type of record that describe well-known services supported by a host. Not used in practice.
|
||||
// The current recommendation and practice is to determine whether a service is supported on an IP address by trying to connect to it.
|
||||
// SMTP is even prohibited from using WKS records in MX processing
|
||||
WKS = "WKS"
|
||||
)
|
||||
|
||||
// Info holds the record informations for a single record entry
|
||||
type Info struct {
|
||||
// Href contains the API URL to get the record informations
|
||||
Href string `json:"rrset_href,omitempty"`
|
||||
// Name contains name of the subdomain for this record
|
||||
Name string `json:"rrset_name,omitempty"`
|
||||
// TTL contains the life time of the record.
|
||||
TTL int64 `json:"rrset_ttl,omitempty"`
|
||||
// Type contains the DNS record type
|
||||
Type string `json:"rrset_type,omitempty"`
|
||||
// Values contains the DNS values resolved by the record
|
||||
Values []string `json:"rrset_values,omitempty"`
|
||||
}
|
||||
|
||||
// Status holds the data returned by the API in case of record creation or update
|
||||
type Status struct {
|
||||
// Message is the status message returned by the gandi api
|
||||
Message string `json:"message"`
|
||||
}
|
56
vendor/github.com/prasmussen/gandi-api/live_dns/zone/structs.go
generated
vendored
56
vendor/github.com/prasmussen/gandi-api/live_dns/zone/structs.go
generated
vendored
@ -1,56 +0,0 @@
|
||||
package zone
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
// Source: http://knowledgelayer.softlayer.com/faq/what-does-serial-refresh-retry-expire-minimum-and-ttl-mean
|
||||
|
||||
// Info holds the DNS zone informations
|
||||
type Info struct {
|
||||
// Retry is the amount of time in seconds that a domain's primary name server (or servers)
|
||||
// should wait if an attempt to refresh by a secondary name server failed before
|
||||
// attempting to refresh a domain's zone with that secondary name server again.
|
||||
Retry int `json:"retry,omitempty"`
|
||||
// UUID is the zone id
|
||||
UUID *uuid.UUID `json:"uuid,omitempty"`
|
||||
// Minimum is the amount of time in seconds that a domain's resource records are valid.
|
||||
// This is also known as a minimum TTL, and can be overridden by an individual resource record's TTL
|
||||
Minimum int `json:"minimum,omitempty"`
|
||||
// Refresh is the amount of time in seconds that a secondary name server should wait to check for
|
||||
// a new copy of a DNS zone from the domain's primary name server. If a zone file has changed then
|
||||
// the secondary DNS server will update it's copy of the zone to match the primary DNS server's zone
|
||||
Refresh int `json:"refresh,omitempty"`
|
||||
// Expire is the amount of time in seconds that a secondary name server (or servers) will
|
||||
// hold a zone before it is no longer considered authoritative
|
||||
Expire int64 `json:"expire,omitempty"`
|
||||
// SharingID is currently undocumented in http://doc.livedns.gandi.net/
|
||||
// But seems to be the ID used to https://admin.gandi.net/domain/<...>
|
||||
SharingID *uuid.UUID `json:"sharing_id,omitempty"`
|
||||
// Serial is the revision number of this zone file. Increment this number each time the zone
|
||||
// file is changed so that the changes will be distributed to any secondary DNS servers
|
||||
Serial int `json:"serial,omitempty"`
|
||||
// Email is listed but undocumented in http://doc.livedns.gandi.net/
|
||||
Email string `json:"email,omitempty"`
|
||||
// PrimaryNS is the name of the nameserver to be used for this zone
|
||||
PrimaryNS string `json:"primary_ns,omitempty"`
|
||||
// Name is the name of the zone
|
||||
Name string `json:"name,omitempty"`
|
||||
// DomainsHref contains the API URL to retrieve all domains using this zone
|
||||
DomainsHref string `json:"domains_href,omitempty"`
|
||||
// ZoneHref contains the API URL to retrieve full DomainInfo for this domain
|
||||
ZoneHref string `json:"zone_href,omitempty"`
|
||||
// ZoneRecordsHref contains the API URL to retrieve all records registered for the zone linked to this zone
|
||||
ZoneRecordsHref string `json:"zone_records_href,omitempty"`
|
||||
}
|
||||
|
||||
// Status holds the data returned by the API in case of zone update or association to a domain
|
||||
type Status struct {
|
||||
// Message is the status message returned by the gandi api
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// CreateStatus holds the data for returned by the API zone creation
|
||||
type CreateStatus struct {
|
||||
*Status
|
||||
// UUID is the created zone ID
|
||||
UUID *uuid.UUID `json:"uuid"`
|
||||
}
|
100
vendor/github.com/prasmussen/gandi-api/live_dns/zone/zone.go
generated
vendored
100
vendor/github.com/prasmussen/gandi-api/live_dns/zone/zone.go
generated
vendored
@ -1,100 +0,0 @@
|
||||
package zone
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/prasmussen/gandi-api/client"
|
||||
"github.com/prasmussen/gandi-api/live_dns/domain"
|
||||
"github.com/prasmussen/gandi-api/live_dns/record"
|
||||
)
|
||||
|
||||
// Enable/disable debug output:
|
||||
const debug = false
|
||||
|
||||
// Zone holds the zone client structure
|
||||
type Zone struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New instanciates a new instance of a Zone client
|
||||
func New(c *client.Client) *Zone {
|
||||
return &Zone{c}
|
||||
}
|
||||
|
||||
// List accessible DNS zones.
|
||||
func (z *Zone) List() (zones []*Info, err error) {
|
||||
_, err = z.Get("/zones", &zones)
|
||||
return
|
||||
}
|
||||
|
||||
// InfoByUUID Gets zone information from its UUID
|
||||
func (z *Zone) InfoByUUID(uuid uuid.UUID) (info *Info, err error) {
|
||||
_, err = z.Get(fmt.Sprintf("/zones/%s", uuid), &info)
|
||||
if debug {
|
||||
fmt.Printf("DEBUG: InfoByUUID returned SharingID=%v domain=%v\n", info.SharingID, info.Name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Info Gets zone information
|
||||
func (z *Zone) Info(zoneInfo Info) (info *Info, err error) {
|
||||
if zoneInfo.UUID == nil {
|
||||
return nil, fmt.Errorf("can not get zone info %s without an id", zoneInfo.Name)
|
||||
}
|
||||
return z.InfoByUUID(*zoneInfo.UUID)
|
||||
}
|
||||
|
||||
// Create creates a new zone
|
||||
func (z *Zone) Create(zoneInfo Info) (status *CreateStatus, err error) {
|
||||
if debug {
|
||||
fmt.Printf("DEBUG: Create WILL SET SharingID=%v domain=%v\n", zoneInfo.SharingID, zoneInfo.Name)
|
||||
}
|
||||
_, err = z.Post(fmt.Sprintf("/zones?sharing_id=%s", zoneInfo.SharingID), zoneInfo, &status)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates an existing zone
|
||||
func (z *Zone) Update(zoneInfo Info) (status *Status, err error) {
|
||||
if zoneInfo.UUID == nil {
|
||||
return nil, fmt.Errorf("can not update zone %s without an id", zoneInfo.Name)
|
||||
}
|
||||
_, err = z.Patch(fmt.Sprintf("/zones/%s", zoneInfo.UUID), zoneInfo, &status)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete Deletes an existing zone
|
||||
func (z *Zone) Delete(zoneInfo Info) (err error) {
|
||||
if zoneInfo.UUID == nil {
|
||||
return fmt.Errorf("can not update zone %s without an id", zoneInfo.Name)
|
||||
}
|
||||
_, err = z.Client.Delete(fmt.Sprintf("/zones/%s", zoneInfo.UUID), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Domains lists all domains using a zone
|
||||
func (z *Zone) Domains(zoneInfo Info) (domains []*domain.InfoBase, err error) {
|
||||
if zoneInfo.UUID == nil {
|
||||
return nil, fmt.Errorf("can not get domains on a zone %s without an id", zoneInfo.Name)
|
||||
}
|
||||
_, err = z.Get(fmt.Sprintf("/zones/%s/domains", zoneInfo.UUID), &domains)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// Set the current zone of a domain
|
||||
func (z *Zone) Set(domainName string, zoneInfo Info) (status *Status, err error) {
|
||||
if zoneInfo.UUID == nil {
|
||||
return nil, fmt.Errorf("can not attach a domain %s to a zone %s without an id", domainName, zoneInfo.Name)
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("DEBUG: Set WILL SET SharingID=%v domain=%s dn=%v\n", zoneInfo.SharingID, domainName, zoneInfo.Name)
|
||||
}
|
||||
_, err = z.Post(fmt.Sprintf("/zones/%s/domains/%s", zoneInfo.UUID, domainName), nil, &status)
|
||||
return
|
||||
}
|
||||
|
||||
// Records gets a record client for the current zone
|
||||
func (z *Zone) Records(zoneInfo Info) record.Manager {
|
||||
return record.New(z.Client, fmt.Sprintf("/zones/%s", zoneInfo.UUID))
|
||||
}
|
60
vendor/github.com/prasmussen/gandi-api/operation/operation.go
generated
vendored
60
vendor/github.com/prasmussen/gandi-api/operation/operation.go
generated
vendored
@ -1,60 +0,0 @@
|
||||
package operation
|
||||
|
||||
import "github.com/prasmussen/gandi-api/client"
|
||||
|
||||
type Operation struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
func New(c *client.Client) *Operation {
|
||||
return &Operation{c}
|
||||
}
|
||||
|
||||
// Count operations created by this contact
|
||||
func (self *Operation) Count() (int64, error) {
|
||||
var result int64
|
||||
// params := Params{Params: []interface{}{self.Key}}
|
||||
params := []interface{}{self.Key}
|
||||
if err := self.Call("operation.count", params, &result); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Get operation information
|
||||
func (self *Operation) Info(id int64) (*OperationInfo, error) {
|
||||
var res map[string]interface{}
|
||||
// params := Params{Params: []interface{}{self.Key, id}}
|
||||
params := []interface{}{self.Key, id}
|
||||
if err := self.Call("operation.info", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ToOperationInfo(res), nil
|
||||
}
|
||||
|
||||
// Cancel an operation
|
||||
func (self *Operation) Cancel(id int64) (bool, error) {
|
||||
var res bool
|
||||
// params := Params{Params: []interface{}{self.Key, id}}
|
||||
params := []interface{}{self.Key, id}
|
||||
if err := self.Call("operation.cancel", params, &res); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// List operations created by this contact
|
||||
func (self *Operation) List() ([]*OperationInfo, error) {
|
||||
var res []interface{}
|
||||
// params := Params{Params: []interface{}{self.Key}}
|
||||
params := []interface{}{self.Key}
|
||||
if err := self.Call("operation.list", params, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
operations := make([]*OperationInfo, len(res), len(res))
|
||||
for i, r := range res {
|
||||
operations[i] = ToOperationInfo(r.(map[string]interface{}))
|
||||
}
|
||||
return operations, nil
|
||||
}
|
29
vendor/github.com/prasmussen/gandi-api/operation/structs.go
generated
vendored
29
vendor/github.com/prasmussen/gandi-api/operation/structs.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type OperationInfo struct {
|
||||
DateCreated time.Time
|
||||
DateStart time.Time
|
||||
DateUpdated time.Time
|
||||
Eta string
|
||||
Id int64
|
||||
LastError string
|
||||
SessionId int64
|
||||
Source string
|
||||
Step string
|
||||
Type string
|
||||
Params map[string]interface{}
|
||||
OperationDetails *OperationDetails
|
||||
}
|
||||
|
||||
type OperationDetails struct {
|
||||
Id string
|
||||
Label string
|
||||
ProductAction string
|
||||
ProductName string
|
||||
ProductType string
|
||||
Quantity int64
|
||||
}
|
33
vendor/github.com/prasmussen/gandi-api/operation/util.go
generated
vendored
33
vendor/github.com/prasmussen/gandi-api/operation/util.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"github.com/prasmussen/gandi-api/util"
|
||||
)
|
||||
|
||||
func ToOperationInfo(res map[string]interface{}) *OperationInfo {
|
||||
return &OperationInfo{
|
||||
DateCreated: util.ToTime(res["date_created"]),
|
||||
DateStart: util.ToTime(res["date_start"]),
|
||||
DateUpdated: util.ToTime(res["date_updated"]),
|
||||
Eta: util.ToString(res["eta"]),
|
||||
Id: util.ToInt64(res["id"]),
|
||||
LastError: util.ToString(res["last_error"]),
|
||||
SessionId: util.ToInt64(res["session_id"]),
|
||||
Source: util.ToString(res["source"]),
|
||||
Step: util.ToString(res["step"]),
|
||||
Type: util.ToString(res["type"]),
|
||||
OperationDetails: ToOperationDetails(util.ToXmlrpcStruct(res["infos"])),
|
||||
Params: util.ToXmlrpcStruct(res["params"]),
|
||||
}
|
||||
}
|
||||
|
||||
func ToOperationDetails(res map[string]interface{}) *OperationDetails {
|
||||
return &OperationDetails{
|
||||
Id: util.ToString(res["id"]),
|
||||
Label: util.ToString(res["label"]),
|
||||
ProductAction: util.ToString(res["product_action"]),
|
||||
ProductName: util.ToString(res["product_name"]),
|
||||
ProductType: util.ToString(res["product_type"]),
|
||||
Quantity: util.ToInt64(res["quantity"]),
|
||||
}
|
||||
}
|
76
vendor/github.com/prasmussen/gandi-api/util/util.go
generated
vendored
76
vendor/github.com/prasmussen/gandi-api/util/util.go
generated
vendored
@ -1,76 +0,0 @@
|
||||
package util
|
||||
|
||||
import "time"
|
||||
|
||||
func ToStringSlice(is []interface{}) []string {
|
||||
ss := make([]string, len(is), len(is))
|
||||
|
||||
for i, _ := range is {
|
||||
ss[i] = is[i].(string)
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
func ToString(i interface{}) string {
|
||||
if v, ok := i.(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ToTime(i interface{}) time.Time {
|
||||
if v, ok := i.(time.Time); ok {
|
||||
return v
|
||||
}
|
||||
var t time.Time
|
||||
return t
|
||||
}
|
||||
|
||||
func ToInterfaceSlice(i interface{}) []interface{} {
|
||||
if v, ok := i.([]interface{}); ok {
|
||||
return v
|
||||
}
|
||||
var s []interface{}
|
||||
return s
|
||||
}
|
||||
|
||||
func ToInt64(i interface{}) int64 {
|
||||
if v, ok := i.(int64); ok {
|
||||
return v
|
||||
}
|
||||
var n int64
|
||||
return n
|
||||
}
|
||||
|
||||
func ToFloat64(i interface{}) float64 {
|
||||
if v, ok := i.(float64); ok {
|
||||
return v
|
||||
}
|
||||
var n float64
|
||||
return n
|
||||
}
|
||||
|
||||
func ToXmlrpcStruct(i interface{}) map[string]interface{} {
|
||||
if v, ok := i.(map[string]interface{}); ok {
|
||||
return v
|
||||
}
|
||||
var s map[string]interface{}
|
||||
return s
|
||||
}
|
||||
|
||||
func ToBool(i interface{}) bool {
|
||||
if v, ok := i.(bool); ok {
|
||||
return v
|
||||
}
|
||||
var b bool
|
||||
return b
|
||||
}
|
||||
|
||||
func ToIntSlice(is []interface{}) []int64 {
|
||||
numbers := make([]int64, len(is), len(is))
|
||||
|
||||
for i, _ := range is {
|
||||
numbers[i] = ToInt64(is[i])
|
||||
}
|
||||
return numbers
|
||||
}
|
19
vendor/modules.txt
vendored
19
vendor/modules.txt
vendored
@ -147,9 +147,6 @@ github.com/google/go-github/github
|
||||
# github.com/google/go-querystring v1.0.1-0.20190318165438-c8c88dbee036
|
||||
## explicit
|
||||
github.com/google/go-querystring/query
|
||||
# github.com/google/uuid v1.1.2-0.20190416172445-c2e93f3ae59f
|
||||
## explicit
|
||||
github.com/google/uuid
|
||||
# github.com/googleapis/gax-go/v2 v2.0.5
|
||||
github.com/googleapis/gax-go/v2
|
||||
# github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1
|
||||
@ -208,9 +205,6 @@ github.com/hexonet/go-sdk/socketconfig
|
||||
# github.com/jmespath/go-jmespath v0.0.0-20200310193758-2437e8417af5
|
||||
## explicit
|
||||
github.com/jmespath/go-jmespath
|
||||
# github.com/kolo/xmlrpc v0.0.0-20150413191830-0826b98aaa29
|
||||
## explicit
|
||||
github.com/kolo/xmlrpc
|
||||
# github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8
|
||||
## explicit
|
||||
# github.com/miekg/dns v1.1.27
|
||||
@ -240,19 +234,6 @@ github.com/pierrec/lz4/internal/xxh32
|
||||
github.com/pkg/errors
|
||||
# github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/pmezard/go-difflib/difflib
|
||||
# github.com/prasmussen/gandi-api v0.0.0-20180224132202-58d3d4205661
|
||||
## explicit
|
||||
github.com/prasmussen/gandi-api/client
|
||||
github.com/prasmussen/gandi-api/domain
|
||||
github.com/prasmussen/gandi-api/domain/nameservers
|
||||
github.com/prasmussen/gandi-api/domain/zone
|
||||
github.com/prasmussen/gandi-api/domain/zone/record
|
||||
github.com/prasmussen/gandi-api/domain/zone/version
|
||||
github.com/prasmussen/gandi-api/live_dns/domain
|
||||
github.com/prasmussen/gandi-api/live_dns/record
|
||||
github.com/prasmussen/gandi-api/live_dns/zone
|
||||
github.com/prasmussen/gandi-api/operation
|
||||
github.com/prasmussen/gandi-api/util
|
||||
# github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03
|
||||
## explicit
|
||||
github.com/renier/xmlrpc
|
||||
|
Reference in New Issue
Block a user