gandi_v5 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/README.md +3 -2
- data/lib/gandi_v5.rb +34 -13
- data/lib/gandi_v5/domain.rb +2 -8
- data/lib/gandi_v5/email/forward.rb +2 -8
- data/lib/gandi_v5/email/mailbox.rb +2 -8
- data/lib/gandi_v5/live_dns.rb +0 -12
- data/lib/gandi_v5/live_dns/domain.rb +313 -29
- data/lib/gandi_v5/live_dns/domain/dnssec_key.rb +115 -0
- data/lib/gandi_v5/live_dns/domain/record.rb +81 -0
- data/lib/gandi_v5/live_dns/domain/snapshot.rb +107 -0
- data/lib/gandi_v5/live_dns/domain/tsig_key.rb +71 -0
- data/lib/gandi_v5/version.rb +1 -1
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/fetch.yml +1 -2
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list_tsig.yml +3 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/nameservers.yml +3 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/fetch.yml +12 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/list.yml +9 -0
- data/spec/fixtures/bodies/{GandiV5_LiveDNS_Zone_Snapshot → GandiV5_LiveDNS_Domain_Snapshot}/fetch.yml +4 -3
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_Snapshot/list.yml +5 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/fetch.yml +9 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/list.yml +4 -0
- data/spec/units/gandi_v5/domain_spec.rb +6 -37
- data/spec/units/gandi_v5/email/forward_spec.rb +5 -34
- data/spec/units/gandi_v5/email/mailbox_spec.rb +4 -34
- data/spec/units/gandi_v5/live_dns/domain/dnssec_key_spec.rb +128 -0
- data/spec/units/gandi_v5/live_dns/{record_set_spec.rb → domain/record_spec.rb} +1 -1
- data/spec/units/gandi_v5/live_dns/domain/snapshot_spec.rb +101 -0
- data/spec/units/gandi_v5/live_dns/domain/tsig_key_spec.rb +78 -0
- data/spec/units/gandi_v5/live_dns/domain_spec.rb +297 -118
- data/spec/units/gandi_v5/live_dns_spec.rb +0 -12
- data/spec/units/gandi_v5_spec.rb +111 -14
- metadata +18 -24
- data/lib/gandi_v5/live_dns/has_zone_records.rb +0 -153
- data/lib/gandi_v5/live_dns/record_set.rb +0 -79
- data/lib/gandi_v5/live_dns/zone.rb +0 -160
- data/lib/gandi_v5/live_dns/zone/snapshot.rb +0 -81
- data/spec/features/domain_spec.rb +0 -45
- data/spec/features/livedns_domain_spec.rb +0 -8
- data/spec/features/livedns_zone_spec.rb +0 -44
- data/spec/features/mailbox_spec.rb +0 -18
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/fetch.yml +0 -11
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/list.yml +0 -11
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/list.yml +0 -3
- data/spec/fixtures/vcr/Domain_features/List_domains.yml +0 -55
- data/spec/fixtures/vcr/Domain_features/Renew_domain.yml +0 -133
- data/spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml +0 -32
- data/spec/fixtures/vcr/LiveDNS_Zone_features/List_zones.yml +0 -42
- data/spec/fixtures/vcr/LiveDNS_Zone_features/Make_and_save_snapshot.yml +0 -72
- data/spec/fixtures/vcr/LiveDNS_Zone_features/Save_zone_to_file.yml +0 -28
- data/spec/fixtures/vcr/Mailbox_features/List_mailboxes.yml +0 -39
- data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +0 -66
- data/spec/units/gandi_v5/live_dns/zone_spec.rb +0 -347
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6873be5c700e1ef88075c90b71361bb9568b11661661dd0bc4f7d77cfdefd6f0
|
4
|
+
data.tar.gz: 13aac04c42357193607cff0f55c0502253fb6b527475e40ad5cb5d53011268ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46afb560fe574db5bf9d47e3e5bbce0843acef12edd132e26cba685608e4b1fa2dc1579dc30e287128ef6462924d56c14856168bcc2d277dededbf9360c45d0b
|
7
|
+
data.tar.gz: 9e35714cdb2ad68d57d11f4bdd689a6fc0103d155827682bb6a2f66340e8054af328761827f13e7af857c5c41263568daed84805e20b90e5b580917dea502eab
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# Gandi V5 API Gem Changelog
|
2
2
|
|
3
|
+
## Version 0.7.0
|
4
|
+
|
5
|
+
* LiveDNS:
|
6
|
+
* Rename LiveDNS::RecordSet to LiveDNS::Domain::Record
|
7
|
+
* Domains:
|
8
|
+
* .list now returns an array of strings
|
9
|
+
* Can no longer change the zone used by a domain
|
10
|
+
* Added automatic_snapshots attribute for whether snapshots are automatically created when a modification is made to this domain's records
|
11
|
+
* #replace_records and #replace_records_for merged into #replace_records
|
12
|
+
* If replacing with a zone file use the new #replace_zone_lines
|
13
|
+
* Added:
|
14
|
+
* .create
|
15
|
+
* .record_types
|
16
|
+
* .generic_name_servers(fqdn)
|
17
|
+
* #name_servers and #fetch_name_servers
|
18
|
+
* #tsig_keys, #fetch_tsig_keys, #add_tsig_key, #remove_tsig_key
|
19
|
+
* #axfr_clients, #fetch_axfr_clients, #add_axfr_client, #remove_axfr_client
|
20
|
+
* ::DnssecKeys, #dnssec_keys, #fetch_dnssec_keys
|
21
|
+
* Snapshots:
|
22
|
+
* Moved to live under LiveDNS::Domain not LiveDNS::Zone
|
23
|
+
* Are now accessed via the fully qualified domain name NOT the zone's UUID
|
24
|
+
* Ability to access the zone from a snapshot is removed
|
25
|
+
* Taking a snapshot now allows for named snapshots
|
26
|
+
* Added automatic attribute for when a snapshot was taken due to a zone change
|
27
|
+
* .list now returns an array of snapshots (records are fetched in a seperate request when first needed)
|
28
|
+
* Zone removed.
|
29
|
+
|
3
30
|
## Version 0.6.0
|
4
31
|
|
5
32
|
* GandiV5::Email::Slot.create now supports sharing_id
|
data/README.md
CHANGED
@@ -36,12 +36,12 @@ Details of the API can be found at:
|
|
36
36
|
If you're using bundler then add it to your Gemfile and run the bundle command.
|
37
37
|
|
38
38
|
```ruby
|
39
|
-
gem 'gandi_v5', '~> 0.
|
39
|
+
gem 'gandi_v5', '~> 0.7'
|
40
40
|
```
|
41
41
|
|
42
42
|
If you're not using bundler then install it from the command line.
|
43
43
|
```bash
|
44
|
-
gem install gandi_v5 -v '~> 0.
|
44
|
+
gem install gandi_v5 -v '~> 0.7'
|
45
45
|
```
|
46
46
|
|
47
47
|
## Usage
|
@@ -77,6 +77,7 @@ We follow the [Semantic Versioning](http://semver.org/) concept.
|
|
77
77
|
|
78
78
|
| Gem Version | Gandi API Release Date |
|
79
79
|
| --------------- | ------------------------ |
|
80
|
+
| 0.7.0 | 2020-05-07 |
|
80
81
|
| 0.6.0 | 2020-05-07 (not LiveDNS) |
|
81
82
|
| 0.5.0 | 2019-10-01 |
|
82
83
|
| 0.4.0 | 2019-10-01 |
|
data/lib/gandi_v5.rb
CHANGED
@@ -82,6 +82,36 @@ class GandiV5
|
|
82
82
|
handle_bad_request(e)
|
83
83
|
end
|
84
84
|
|
85
|
+
# Might raise:
|
86
|
+
# * RestClient::NotFound
|
87
|
+
# * RestClient::Unauthorized
|
88
|
+
# Bad authentication attempt because of a wrong API Key.
|
89
|
+
# * RestClient::Forbidden
|
90
|
+
# Access to the resource is denied.
|
91
|
+
# Mainly due to a lack of permissions to access it.
|
92
|
+
# * GandiV5::Error
|
93
|
+
# * JSON::ParserError
|
94
|
+
def paginated_get(url, page = (1..), per_page = 100, **headers)
|
95
|
+
unless page.respond_to?(:each)
|
96
|
+
fail ArgumentError, 'page must be positive' unless page.positive?
|
97
|
+
|
98
|
+
page = [page]
|
99
|
+
end
|
100
|
+
|
101
|
+
headers[:params] ||= {}
|
102
|
+
headers[:params].transform_keys!(&:to_s)
|
103
|
+
headers[:params]['per_page'] = per_page
|
104
|
+
|
105
|
+
page.each do |page_number|
|
106
|
+
headers[:params]['page'] = page_number
|
107
|
+
_resp, this_data = get(url, **headers)
|
108
|
+
break if this_data.empty?
|
109
|
+
|
110
|
+
yield this_data
|
111
|
+
break if this_data.count < per_page
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
85
115
|
# Might raise:
|
86
116
|
# * RestClient::NotFound
|
87
117
|
# * RestClient::Unauthorized
|
@@ -169,16 +199,6 @@ class GandiV5
|
|
169
199
|
@api_key ||= ENV.fetch('GANDI_API_KEY')
|
170
200
|
end
|
171
201
|
|
172
|
-
def authorisation_header(url)
|
173
|
-
if url.start_with?(BASE)
|
174
|
-
{ Authorization: "Apikey #{api_key}" }
|
175
|
-
elsif url.start_with?(GandiV5::LiveDNS::BASE)
|
176
|
-
{ 'X-Api-Key': api_key }
|
177
|
-
else
|
178
|
-
fail ArgumentError, "Don't know how to authorise for url: #{url}"
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
202
|
def parse_response(response)
|
183
203
|
type = response.headers.fetch(:content_type).split(';').first.chomp
|
184
204
|
case type
|
@@ -196,10 +216,11 @@ class GandiV5
|
|
196
216
|
end
|
197
217
|
end
|
198
218
|
|
199
|
-
def prepare_headers(headers,
|
200
|
-
headers.transform_keys!
|
219
|
+
def prepare_headers(headers, _url)
|
220
|
+
headers.transform_keys! { |key| key.to_s.downcase.to_sym }
|
201
221
|
headers[:accept] ||= 'application/json'
|
202
|
-
headers
|
222
|
+
headers[:authorization] = "Apikey #{api_key}"
|
223
|
+
headers
|
203
224
|
end
|
204
225
|
|
205
226
|
def handle_bad_request(exception)
|
data/lib/gandi_v5/domain.rb
CHANGED
@@ -492,7 +492,7 @@ class GandiV5
|
|
492
492
|
# @param page [#each<Integer, #to_s>] the page(s) of results to retrieve.
|
493
493
|
# If page is not provided keep querying until an empty list is returned.
|
494
494
|
# If page responds to .each then iterate until an empty list is returned.
|
495
|
-
# @param per_page [Integer, #to_s] (optional default 100) how many results
|
495
|
+
# @param per_page [Integer, #to_s] (optional default 100) how many results to get per page.
|
496
496
|
# @param fqdn [String, #to_s] (optional)
|
497
497
|
# filters the list by domain name, with optional patterns.
|
498
498
|
# e.g. "example.net", "example.*", "*ample.com"
|
@@ -501,15 +501,9 @@ class GandiV5
|
|
501
501
|
# @return [Array<GandiV5::Domain>]
|
502
502
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
503
503
|
def self.list(page: (1..), per_page: 100, **params)
|
504
|
-
page = [page.to_i] unless page.respond_to?(:each)
|
505
|
-
|
506
504
|
domains = []
|
507
|
-
|
508
|
-
_resp, data = GandiV5.get url, params: params.merge(page: page_number, per_page: per_page)
|
509
|
-
break if data.empty?
|
510
|
-
|
505
|
+
GandiV5.paginated_get(url, page, per_page, params: params) do |data|
|
511
506
|
domains += data.map { |domain| from_gandi domain }
|
512
|
-
break if data.count < per_page
|
513
507
|
end
|
514
508
|
domains
|
515
509
|
end
|
@@ -76,18 +76,12 @@ class GandiV5
|
|
76
76
|
# e.g. ("alice" "*lice", "alic*").
|
77
77
|
# @return [Array<GandiV5::Email::Forward>]
|
78
78
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
79
|
-
def self.list(fqdn, page: (1..), **params)
|
80
|
-
page = [page.to_i] unless page.respond_to?(:each)
|
81
|
-
|
79
|
+
def self.list(fqdn, page: (1..), per_page: 100, **params)
|
82
80
|
params.reject! { |_k, v| v.nil? }
|
83
81
|
|
84
82
|
mailboxes = []
|
85
|
-
|
86
|
-
_response, data = GandiV5.get url(fqdn), params: params.merge(page: page_number)
|
87
|
-
break if data.empty?
|
88
|
-
|
83
|
+
GandiV5.paginated_get(url(fqdn), page, per_page, params: params) do |data|
|
89
84
|
mailboxes += data.map { |mailbox| from_gandi mailbox.merge(fqdn: fqdn) }
|
90
|
-
break if data.count < params.fetch(:per_page, 100)
|
91
85
|
end
|
92
86
|
mailboxes
|
93
87
|
end
|
@@ -197,19 +197,13 @@ class GandiV5
|
|
197
197
|
# e.g. ("alice" "*lice", "alic*").
|
198
198
|
# @return [Array<GandiV5::Email::Mailbox>]
|
199
199
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
200
|
-
def self.list(fqdn, page: (1..), **params)
|
201
|
-
page = [page.to_i] unless page.respond_to?(:each)
|
202
|
-
|
200
|
+
def self.list(fqdn, page: (1..), per_page: 100, **params)
|
203
201
|
params['~login'] = params.delete(:login)
|
204
202
|
params.reject! { |_k, v| v.nil? }
|
205
203
|
|
206
204
|
mailboxes = []
|
207
|
-
|
208
|
-
_response, data = GandiV5.get url(fqdn), params: params.merge(page: page_number)
|
209
|
-
break if data.empty?
|
210
|
-
|
205
|
+
GandiV5.paginated_get(url(fqdn), page, per_page, params: params) do |data|
|
211
206
|
mailboxes += data.map { |mailbox| from_gandi mailbox }
|
212
|
-
break if data.count < params.fetch(:per_page, 100)
|
213
207
|
end
|
214
208
|
mailboxes
|
215
209
|
end
|
data/lib/gandi_v5/live_dns.rb
CHANGED
@@ -4,8 +4,6 @@
|
|
4
4
|
class GandiV5
|
5
5
|
# Gandi LiveDNS Management API.
|
6
6
|
class LiveDNS
|
7
|
-
BASE = 'https://dns.api.gandi.net/api/v5/'
|
8
|
-
|
9
7
|
RECORD_TYPES = %w[
|
10
8
|
A AAAA CNAME MX NS TXT ALIAS
|
11
9
|
WKS SRV LOC SPF CAA DS SSHFP PTR KEY DNAME TLSA OPENPGPKEY CDS
|
@@ -21,16 +19,6 @@ class GandiV5
|
|
21
19
|
GandiV5::LiveDNS::Domain.list
|
22
20
|
end
|
23
21
|
|
24
|
-
# @see GandiV5::LiveDNS::Zone.fetch
|
25
|
-
def self.zone(uuid)
|
26
|
-
GandiV5::LiveDNS::Zone.fetch(uuid)
|
27
|
-
end
|
28
|
-
|
29
|
-
# @see GandiV5::LiveDNS::Zone.list
|
30
|
-
def self.zones
|
31
|
-
GandiV5::LiveDNS::Zone.list
|
32
|
-
end
|
33
|
-
|
34
22
|
# Raise an error if passed type is invalid.
|
35
23
|
# @param type [String] the record type to check.
|
36
24
|
# @return [nil]
|
@@ -5,19 +5,12 @@ class GandiV5
|
|
5
5
|
# A domain name within the LiveDNS system.
|
6
6
|
# @!attribute [r] fqdn
|
7
7
|
# @return [String]
|
8
|
-
# @!attribute [r]
|
9
|
-
# @return [
|
8
|
+
# @!attribute [r] automatic_snapshots
|
9
|
+
# @return [Boolean]
|
10
10
|
class Domain
|
11
11
|
include GandiV5::Data
|
12
|
-
include GandiV5::LiveDNS::HasZoneRecords
|
13
|
-
|
14
|
-
members :fqdn
|
15
12
|
|
16
|
-
|
17
|
-
:zone_uuid,
|
18
|
-
gandi_key: 'zone',
|
19
|
-
converter: GandiV5::Data::Converter.new(from_gandi: ->(zone) { zone&.split('/')&.last })
|
20
|
-
)
|
13
|
+
members :fqdn, :automatic_snapshots
|
21
14
|
|
22
15
|
# Refetch the information for this domain from Gandi.
|
23
16
|
# @return [GandiV5::LiveDNS::Domain]
|
@@ -27,35 +20,283 @@ class GandiV5
|
|
27
20
|
from_gandi data
|
28
21
|
end
|
29
22
|
|
30
|
-
#
|
31
|
-
# @param
|
23
|
+
# Update this domain's settings.
|
24
|
+
# @param automatic_snapshots [String, #to_s]
|
25
|
+
# Enable or disable the automatic creation of new snapshots when records are changed.
|
32
26
|
# @return [String] The confirmation message from Gandi.
|
33
27
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
self.zone_uuid = uuid
|
28
|
+
def update(automatic_snapshots:)
|
29
|
+
_response, data = GandiV5.patch url, { automatic_snapshots: automatic_snapshots }.to_json
|
30
|
+
self.automatic_snapshots = automatic_snapshots
|
38
31
|
data['message']
|
39
32
|
end
|
40
33
|
|
41
|
-
# @
|
42
|
-
|
43
|
-
|
34
|
+
# @overload fetch_records()
|
35
|
+
# Fetch all records for this domain.
|
36
|
+
# @param page [Integer, #each<Integer>] which page(s) of results to get.
|
37
|
+
# If page is not provided keep querying until an empty list is returned.
|
38
|
+
# If page responds to .each then iterate until an empty list is returned.
|
39
|
+
# @param per_page [Integer, #to_s] (optional default 100) how many results ot get per page.
|
40
|
+
# @overload fetch_records(name)
|
41
|
+
# Fetch records for a name.
|
42
|
+
# @param name [String] the name to fetch records for.
|
43
|
+
# @param page [Integer, #each<Integer>] which page(s) of results to get.
|
44
|
+
# If page is not provided keep querying until an empty list is returned.
|
45
|
+
# If page responds to .each then iterate until an empty list is returned.
|
46
|
+
# @param per_page [Integer, #to_s] (optional default 100) how many results ot get per page.
|
47
|
+
# @overload fetch_records(name, type)
|
48
|
+
# Fetch records of a type for a name.
|
49
|
+
# @param name [String] the name to fetch records for.
|
50
|
+
# @param type [String] the record type to fetch.
|
51
|
+
# @param page [Integer, #each<Integer>] which page(s) of results to get.
|
52
|
+
# If page is not provided keep querying until an empty list is returned.
|
53
|
+
# If page responds to .each then iterate until an empty list is returned.
|
54
|
+
# @param per_page [Integer, #to_s] (optional default 100) how many results ot get per page.
|
55
|
+
# @return [Array<GandiV5::LiveDNS::Domain::Record>]
|
56
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
57
|
+
def fetch_records(name = nil, type = nil, page: (1..), per_page: 100)
|
58
|
+
GandiV5::LiveDNS.require_valid_record_type type if type
|
59
|
+
|
60
|
+
url_ = "#{url}/records"
|
61
|
+
url_ += "/#{CGI.escape name}" if name
|
62
|
+
url_ += "/#{CGI.escape type}" if type
|
63
|
+
|
64
|
+
all = []
|
65
|
+
GandiV5.paginated_get(url_, page, per_page) do |data|
|
66
|
+
all += [*data].map { |item| GandiV5::LiveDNS::Domain::Record.from_gandi item }
|
67
|
+
end
|
68
|
+
all
|
44
69
|
end
|
45
70
|
|
46
|
-
#
|
47
|
-
#
|
71
|
+
# @overload fetch_zone_lines()
|
72
|
+
# Fetch all records for this domain.
|
73
|
+
# @overload fetch_zone_lines(name)
|
74
|
+
# Fetch records for a name.
|
75
|
+
# @param name [String] the name to fetch records for.
|
76
|
+
# @overload fetch_zone_lines(name, type)
|
77
|
+
# Fetch records of a type for a name.
|
78
|
+
# @param name [String] the name to fetch records for.
|
79
|
+
# @param type [String] the record type to fetch.
|
80
|
+
# @return [String]
|
48
81
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
49
|
-
def
|
50
|
-
|
82
|
+
def fetch_zone_lines(name = nil, type = nil)
|
83
|
+
GandiV5::LiveDNS.require_valid_record_type type if type
|
84
|
+
|
85
|
+
url_ = "#{url}/records"
|
86
|
+
url_ += "/#{CGI.escape name}" if name
|
87
|
+
url_ += "/#{CGI.escape type}" if type
|
88
|
+
|
89
|
+
GandiV5.get(url_, accept: 'text/plain').last
|
90
|
+
end
|
91
|
+
|
92
|
+
# Add record to this domain.
|
93
|
+
# @param name [String]
|
94
|
+
# @param type [String]
|
95
|
+
# @param ttl [Integer]
|
96
|
+
# @param values [Array<String>]
|
97
|
+
# @return [String] The confirmation message from Gandi.
|
98
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
99
|
+
def add_record(name, type, ttl, *values)
|
100
|
+
GandiV5::LiveDNS.require_valid_record_type type
|
101
|
+
fail ArgumentError, 'ttl must be positive and non-zero' unless ttl.positive?
|
102
|
+
fail ArgumentError, 'there must be at least one value' if values.none?
|
103
|
+
|
104
|
+
body = {
|
105
|
+
rrset_name: name,
|
106
|
+
rrset_type: type,
|
107
|
+
rrset_ttl: ttl,
|
108
|
+
rrset_values: values
|
109
|
+
}.to_json
|
110
|
+
_response, data = GandiV5.post "#{url}/records", body
|
111
|
+
data['message']
|
112
|
+
end
|
113
|
+
|
114
|
+
# @overload delete_records()
|
115
|
+
# Delete all records for this domain.
|
116
|
+
# @overload delete_records(name)
|
117
|
+
# Delete records for a name.
|
118
|
+
# @param name [String] the name to delete records for.
|
119
|
+
# @overload delete_records(name, type)
|
120
|
+
# Delete records of a type for a name.
|
121
|
+
# @param name [String] the name to delete records for.
|
122
|
+
# @param type [String] the record type to delete.
|
123
|
+
# @return [nil]
|
124
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
125
|
+
def delete_records(name = nil, type = nil)
|
126
|
+
GandiV5::LiveDNS.require_valid_record_type(type) if type
|
127
|
+
|
128
|
+
url_ = "#{url}/records"
|
129
|
+
url_ += "/#{CGI.escape name}" if name
|
130
|
+
url_ += "/#{CGI.escape type}" if type
|
131
|
+
GandiV5.delete(url_).last
|
132
|
+
end
|
133
|
+
|
134
|
+
# Replace records for the domain.
|
135
|
+
# @param name [String, nil] only replaces records for this name.
|
136
|
+
# @param type [String, nil] only replaces record of this type (requires name).
|
137
|
+
# @param values [Array<String>] the values to set for the record.
|
138
|
+
# @raise [ArgumentError] if ttl is present and type is absent.
|
139
|
+
# @return [String] The confirmation message from Gandi.
|
140
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
141
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
142
|
+
def replace_records(records, name: nil, type: nil)
|
143
|
+
if type
|
144
|
+
GandiV5::LiveDNS.require_valid_record_type(type) if type
|
145
|
+
fail ArgumentError, 'missing keyword: name' if name.nil?
|
146
|
+
end
|
147
|
+
|
148
|
+
url_ = "#{url}/records"
|
149
|
+
url_ += "/#{CGI.escape name}" if name
|
150
|
+
url_ += "/#{CGI.escape type}" if type
|
151
|
+
|
152
|
+
body = if type && name
|
153
|
+
{ rrset_values: records }
|
154
|
+
else
|
155
|
+
{ items: records.map { |r| r.transform_keys { |k| "rrset_#{k}" } } }
|
156
|
+
end
|
157
|
+
|
158
|
+
_response, data = GandiV5.put url_, body.to_json
|
159
|
+
data['message']
|
160
|
+
end
|
161
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
162
|
+
|
163
|
+
# Replace all records for this domain.
|
164
|
+
# @param text [String] zone file lines to replace the records with.
|
165
|
+
# @return [String] The confirmation message from Gandi.
|
166
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
167
|
+
def replace_zone_lines(text)
|
168
|
+
_response, data = GandiV5.put "#{url}/records", text, 'content-type': 'text/plain'
|
169
|
+
data['message']
|
170
|
+
end
|
171
|
+
|
172
|
+
# The list of nameservers that this domain is using according to LiveDNS' systems.
|
173
|
+
# * Either there are no NS records on @ and the 3 hashed nameservers are returned
|
174
|
+
# (ns-{123}-{abc}.gandi.net)
|
175
|
+
# * Or some NS records exist on @ and it will return those
|
176
|
+
# @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-name$
|
177
|
+
# @return [Array<String>]
|
178
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
179
|
+
def name_servers
|
180
|
+
@name_servers ||= fetch_name_servers
|
181
|
+
end
|
182
|
+
|
183
|
+
# Requery Gandi for the domain's name servers.
|
184
|
+
# @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-name$
|
185
|
+
# @return [Array<String>]
|
186
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
187
|
+
def fetch_name_servers
|
188
|
+
_response, data = GandiV5.get "#{url}/nameservers"
|
189
|
+
@name_servers = data
|
190
|
+
end
|
191
|
+
|
192
|
+
# The list of DNSSEC keys for the domain.
|
193
|
+
# If you need the fingerprint, public_key or tag attributes you'll need
|
194
|
+
# use GandiV5::LiveDNS::Domain::DnssecKey.fetch on each item.
|
195
|
+
# @return [Array<GandiV5::LiveDNS::Domain::DnssecKey>]
|
196
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
197
|
+
def dnssec_keys
|
198
|
+
@dnssec_keys ||= fetch_dnssec_keys
|
199
|
+
end
|
200
|
+
|
201
|
+
# Requery Gandi for the domain's DNSSEC keys.
|
202
|
+
# @return [Array<GandiV5::LiveDNS::Domain::DnssecKey>]
|
203
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
204
|
+
def fetch_dnssec_keys
|
205
|
+
@dnssec_keys = GandiV5::LiveDNS::Domain::DnssecKey.list(fqdn)
|
206
|
+
end
|
207
|
+
|
208
|
+
# The list of TSIG keys for the domain.
|
209
|
+
# If you need the secret, fingerprint, public_key or tag attributes you'll need
|
210
|
+
# to use GandiV5::LiveDNS::Domain::DnssecKey.fetch on each item.
|
211
|
+
# @return [Array<GandiV5::LiveDNS::Domain::TsigKey>]
|
212
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
213
|
+
def tsig_keys
|
214
|
+
@tsig_keys ||= fetch_tsig_keys
|
215
|
+
end
|
216
|
+
|
217
|
+
# Requery Gandi for the domain's TSIG keys.
|
218
|
+
# @return [Array<GandiV5::LiveDNS::Domain::TsigKey>]
|
219
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
220
|
+
def fetch_tsig_keys
|
221
|
+
_response, data = GandiV5.get "#{url}/axfr/tsig"
|
222
|
+
data.map { |item| GandiV5::LiveDNS::Domain::TsigKey.from_gandi item }
|
223
|
+
end
|
224
|
+
|
225
|
+
# Add a Tsig key to this domain.
|
226
|
+
# @param key [GandiV5::LiveDNS::Domain::TsigKey, #uuid, String, #to_s]
|
227
|
+
# the key to add.
|
228
|
+
# @param sharing_id [nil, String, #to_s]
|
229
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
230
|
+
def add_tsig_key(key, sharing_id: nil)
|
231
|
+
key = key.uuid if key.respond_to?(:uuid)
|
232
|
+
url_ = "#{url}/axfr/tsig/#{key}"
|
233
|
+
url_ += "?sharing_id=#{CGI.escape sharing_id}" if sharing_id
|
234
|
+
_response, _data = GandiV5.put url_
|
235
|
+
end
|
236
|
+
|
237
|
+
# Remove a Tsig key from this domain.
|
238
|
+
# @param key [GandiV5::LiveDNS::Domain::TsigKey, #uuid, String, #to_s]
|
239
|
+
# the key to remove.
|
240
|
+
# @param sharing_id [nil, String, #to_s]
|
241
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
242
|
+
def remove_tsig_key(key, sharing_id: nil)
|
243
|
+
key = key.uuid if key.respond_to?(:uuid)
|
244
|
+
url_ = "#{url}/axfr/tsig/#{key}"
|
245
|
+
url_ += "?sharing_id=#{CGI.escape sharing_id}" if sharing_id
|
246
|
+
_response, _data = GandiV5.delete url_
|
247
|
+
end
|
248
|
+
|
249
|
+
# The list of AXFR clients for the domain.
|
250
|
+
# @return [Array<String>] list of IP addresses.
|
251
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
252
|
+
def axfr_clients
|
253
|
+
@axfr_clients ||= fetch_axfr_clients
|
254
|
+
end
|
255
|
+
|
256
|
+
# Requery Gandi for the domain's AXFR clients.
|
257
|
+
# @return [Array<String>] list of IP addresses.
|
258
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
259
|
+
def fetch_axfr_clients
|
260
|
+
_response, data = GandiV5.get "#{url}/axfr/slaves"
|
261
|
+
data
|
262
|
+
end
|
263
|
+
|
264
|
+
# Add an AXFR client to this domain.
|
265
|
+
# @param ip [String, #to_s] the IP address to add.
|
266
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
267
|
+
def add_axfr_client(ip)
|
268
|
+
_response, _data = GandiV5.put "#{url}/axfr/slaves/#{ip}"
|
269
|
+
end
|
270
|
+
|
271
|
+
# Remove and AXFR client from this domain.
|
272
|
+
# @param ip [String, #to_s] the IP address to remove.
|
273
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
274
|
+
def remove_axfr_client(ip)
|
275
|
+
_response, _data = GandiV5.delete "#{url}/axfr/slaves/#{ip}"
|
51
276
|
end
|
52
277
|
|
53
278
|
# List the domains.
|
54
|
-
# @
|
279
|
+
# @param page [#each<Integer, #to_s>] the page(s) of results to retrieve.
|
280
|
+
# If page is not provided keep querying until an empty list is returned.
|
281
|
+
# If page responds to .each then iterate until an empty list is returned.
|
282
|
+
# @param per_page [Integer, #to_s] (optional default 100) how many results to get per page.
|
283
|
+
# @param sharing_id [String, #to_s] (optional) filter by domains assigned to a given user.
|
284
|
+
# @return [Array<String>]
|
55
285
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
56
|
-
def self.list
|
57
|
-
|
58
|
-
|
286
|
+
def self.list(page: (1..), per_page: 100, sharing_id: nil)
|
287
|
+
page = [page.to_i] unless page.respond_to?(:each)
|
288
|
+
params = { per_page: per_page }
|
289
|
+
params[:sharing_id] = sharing_id unless sharing_id.nil?
|
290
|
+
|
291
|
+
domains = []
|
292
|
+
page.each do |page_number|
|
293
|
+
_resp, data = GandiV5.get url, params: params.merge(page: page_number)
|
294
|
+
break if data.empty?
|
295
|
+
|
296
|
+
domains += data.map { |item| item['fqdn'] }
|
297
|
+
break if data.count < per_page
|
298
|
+
end
|
299
|
+
domains
|
59
300
|
end
|
60
301
|
|
61
302
|
# Get a domain.
|
@@ -67,14 +308,57 @@ class GandiV5
|
|
67
308
|
from_gandi data
|
68
309
|
end
|
69
310
|
|
311
|
+
# Create a new domain in the LiveDNS system.
|
312
|
+
# You must have sufficent permission to manage the domain to do this.
|
313
|
+
# @param fqdn [String, #to_s] the fully qualified domain to add to LiveDNS.
|
314
|
+
# @param records [Array<Hash, GandiV5::LiveDNS::Domain::Record, #to_h, nil>]
|
315
|
+
# @param ttl [Integer, #to_s, nil] the TTL of the SOA record.
|
316
|
+
# Note that this is not a default TTL that will be used for the records in the zone.
|
317
|
+
# the records (if any) to add to the created zone.
|
318
|
+
# @param sharing_id [nil, String, #to_s]
|
319
|
+
# @return [GandiV5::LiveDNS::Domain]
|
320
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
321
|
+
def self.create(fqdn, records = nil, soa_ttl: nil, sharing_id: nil)
|
322
|
+
body = { fqdn: fqdn, zone: {} }
|
323
|
+
body[:zone][:ttl] = soa_ttl if soa_ttl
|
324
|
+
if records
|
325
|
+
body[:zone][:items] = records.map do |r|
|
326
|
+
r.to_h.transform_keys { |k| "rrset_#{k}" }
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
url_ = url
|
331
|
+
url_ += "?sharing_id=#{CGI.escape sharing_id}" if sharing_id
|
332
|
+
|
333
|
+
GandiV5.post url_, body.to_json
|
334
|
+
fetch(fqdn)
|
335
|
+
end
|
336
|
+
|
337
|
+
# Fetch the list of known record types (A, CNAME, etc.)
|
338
|
+
# @return [Array<String>]
|
339
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
340
|
+
def self.record_types
|
341
|
+
GandiV5.get("#{BASE}livedns/dns/rrtypes").last
|
342
|
+
end
|
343
|
+
|
344
|
+
# Get the LiveDNS servers to use for a domain.
|
345
|
+
# Does not take into account any NS records that exist in the zone.
|
346
|
+
# @param fqdn [String, #to_s] the fully qualified domain to hash in
|
347
|
+
# in order to get the LiveDNS servers to use.
|
348
|
+
# @return [Array<String>]
|
349
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
350
|
+
def self.generic_name_servers(fqdn)
|
351
|
+
GandiV5.get("#{BASE}livedns/nameservers/#{CGI.escape fqdn}").last
|
352
|
+
end
|
353
|
+
|
70
354
|
private
|
71
355
|
|
72
356
|
def url
|
73
|
-
"#{BASE}domains/#{CGI.escape
|
357
|
+
"#{BASE}livedns/domains/#{CGI.escape fqdn}"
|
74
358
|
end
|
75
359
|
|
76
360
|
def self.url(fqdn = nil)
|
77
|
-
"#{BASE}domains" + (fqdn ? "/#{CGI.escape
|
361
|
+
"#{BASE}livedns/domains" + (fqdn ? "/#{CGI.escape fqdn}" : '')
|
78
362
|
end
|
79
363
|
private_class_method :url
|
80
364
|
end
|