gandi_v5 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class GandiV5
|
4
|
+
class LiveDNS
|
5
|
+
class Domain
|
6
|
+
# A DNSSEC key for a domain's DNS records.
|
7
|
+
# @!attribyte [r] uuid
|
8
|
+
# @return [String]
|
9
|
+
# @!attribyte [r] status
|
10
|
+
# @return [String]
|
11
|
+
# @!attribyte [r] fqdn
|
12
|
+
# @return [String]
|
13
|
+
# @!attribyte [r] algorithm_id
|
14
|
+
# @return [Integer]
|
15
|
+
# @!attribyte [r] algorithm_name
|
16
|
+
# @return [String]
|
17
|
+
# @!attribyte [r] deleted
|
18
|
+
# @return [Boolean]
|
19
|
+
# @!attribyte [r] ds
|
20
|
+
# @return [String]
|
21
|
+
# @!attribyte [r] flags
|
22
|
+
# @return [Integer]
|
23
|
+
# @!attribyte [r] fingerprint
|
24
|
+
# @return [String]
|
25
|
+
# @!attribyte [r] public_key
|
26
|
+
# @return [String]
|
27
|
+
# @!attribyte [r] tag
|
28
|
+
# @return [String]
|
29
|
+
class DnssecKey
|
30
|
+
include GandiV5::Data
|
31
|
+
|
32
|
+
members :status, :fqdn, :deleted, :ds, :flags, :fingerprint, :public_key,
|
33
|
+
:tag, :algorithm_name
|
34
|
+
|
35
|
+
member :uuid, gandi_key: 'id'
|
36
|
+
member :algorithm_id, gandi_key: 'algorithm'
|
37
|
+
|
38
|
+
# Delete this key.
|
39
|
+
# @return [String] The confirmation message from Gandi.
|
40
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
41
|
+
def delete
|
42
|
+
_response, data = GandiV5.delete url
|
43
|
+
self.deleted = true
|
44
|
+
data['message']
|
45
|
+
end
|
46
|
+
|
47
|
+
# Undelete this key.
|
48
|
+
# @return [String] The confirmation message from Gandi.
|
49
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
50
|
+
def undelete
|
51
|
+
_response, data = GandiV5.patch url, { deleted: false }.to_json
|
52
|
+
self.deleted = false
|
53
|
+
data['message']
|
54
|
+
end
|
55
|
+
|
56
|
+
# Check if this is a zone signing key
|
57
|
+
# @return [Boolean]
|
58
|
+
def zone_signing_key?
|
59
|
+
flags == 256
|
60
|
+
end
|
61
|
+
|
62
|
+
# Check if this is a key signing key
|
63
|
+
# @return [Boolean]
|
64
|
+
def key_signing_key?
|
65
|
+
flags == 257
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create a new DNSSEC key for a zone.
|
69
|
+
# @param fqdn [String, #to_s] the fully qualified domain to create the key for.
|
70
|
+
# @param flags [Integer, :key_signing_key, :zone_signing_key] the key's flags.
|
71
|
+
# @return [GandiV5::LiveDNS::Domain::DnssecKey]
|
72
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
73
|
+
def self.create(fqdn, flags)
|
74
|
+
flags = 256 if flags == :zone_signing_key
|
75
|
+
flags = 257 if flags == :key_signing_key
|
76
|
+
fail ArgumentError, 'flags is invalid' unless flags.is_a?(Integer)
|
77
|
+
|
78
|
+
response, _data = GandiV5.post url(fqdn), { flags: flags }.to_json
|
79
|
+
fetch fqdn, response.headers[:location].split('/').last
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get keys for a FQDN from Gandi.
|
83
|
+
# @param fqdn [String, #to_s] The fully qualified domain name to get the keys for.
|
84
|
+
# @return [Array<GandiV5::LiveDNS::Domain::DnssecKey>]
|
85
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
86
|
+
def self.list(fqdn)
|
87
|
+
_response, data = GandiV5.get url(fqdn)
|
88
|
+
data.map { |item| from_gandi item }
|
89
|
+
end
|
90
|
+
|
91
|
+
# Get DNSSEC key from Gandi.
|
92
|
+
# @param fqdn [String, #to_s] The fully qualified domain name the key was made for.
|
93
|
+
# @param uuid [String, #to_s] the UUID of the key to fetch.
|
94
|
+
# @return [GandiV5::LiveDNS::Domain::DnssecKey]
|
95
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
96
|
+
def self.fetch(fqdn, uuid)
|
97
|
+
_response, data = GandiV5.get url(fqdn, uuid)
|
98
|
+
from_gandi data
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def url
|
104
|
+
"#{BASE}livedns/domains/#{CGI.escape fqdn}/keys/#{CGI.escape uuid}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.url(fqdn, uuid = nil)
|
108
|
+
"#{BASE}livedns/domains/#{CGI.escape fqdn}/keys" +
|
109
|
+
(uuid ? "/#{CGI.escape uuid}" : '')
|
110
|
+
end
|
111
|
+
private_class_method :url
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class GandiV5
|
4
|
+
class LiveDNS
|
5
|
+
class Domain
|
6
|
+
# A record set which comes from either a domain or zone.
|
7
|
+
# @!attribute [r] type
|
8
|
+
# @return [String]
|
9
|
+
# @!attribute [r] ttl
|
10
|
+
# @return [Integer]
|
11
|
+
# @!attribute [r] name
|
12
|
+
# @return [String]
|
13
|
+
# @!attribute [r] values
|
14
|
+
# @return [Array<String>]
|
15
|
+
class Record
|
16
|
+
include GandiV5::Data
|
17
|
+
|
18
|
+
member :type, gandi_key: 'rrset_type'
|
19
|
+
member :ttl, gandi_key: 'rrset_ttl', converter: GandiV5::Data::Converter::Integer
|
20
|
+
member :name, gandi_key: 'rrset_name'
|
21
|
+
member :values, gandi_key: 'rrset_values'
|
22
|
+
|
23
|
+
# Generate zone file lines for the record.
|
24
|
+
# @return [String]
|
25
|
+
def to_s
|
26
|
+
values.map do |value|
|
27
|
+
"#{name}\t#{ttl}\tIN\t#{type}\t#{value}"
|
28
|
+
end.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
GandiV5::LiveDNS::RECORD_TYPES.each do |t|
|
32
|
+
# Check the record type.
|
33
|
+
# @return [Boolean]
|
34
|
+
define_method "#{t.downcase}?" do
|
35
|
+
type.eql?(t)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check the TTL's value in seconds.
|
40
|
+
# @param number [Integer] the number of second(s) to check against.
|
41
|
+
# @return [Boolean]
|
42
|
+
def second?(number = 1)
|
43
|
+
ttl == number
|
44
|
+
end
|
45
|
+
alias seconds? second?
|
46
|
+
|
47
|
+
# Check the TTL's value in minutes.
|
48
|
+
# @param number [Integer] the number of minute(s) to check against.
|
49
|
+
# @return [Boolean]
|
50
|
+
def minute?(number = 1)
|
51
|
+
ttl == number * 60
|
52
|
+
end
|
53
|
+
alias minutes? minute?
|
54
|
+
|
55
|
+
# Check the TTL's value in hours.
|
56
|
+
# @param number [Integer] the number of hour(s) to check against.
|
57
|
+
# @return [Boolean]
|
58
|
+
def hour?(number = 1)
|
59
|
+
ttl == number * 3_600
|
60
|
+
end
|
61
|
+
alias hours? hour?
|
62
|
+
|
63
|
+
# Check the TTL's value in days.
|
64
|
+
# @param number [Integer] the number of day(s) to check against.
|
65
|
+
# @return [Boolean]
|
66
|
+
def day?(number = 1)
|
67
|
+
ttl == number * 86_400
|
68
|
+
end
|
69
|
+
alias days? day?
|
70
|
+
|
71
|
+
# Check the TTL's value in weeks.
|
72
|
+
# @param number [Integer] the number of week(s) to check against.
|
73
|
+
# @return [Boolean]
|
74
|
+
def week?(number = 1)
|
75
|
+
ttl == number * 604_800
|
76
|
+
end
|
77
|
+
alias weeks? day?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class GandiV5
|
4
|
+
class LiveDNS
|
5
|
+
class Domain
|
6
|
+
# A snapshot (backup) of a domain's DNS records.
|
7
|
+
# @!attribute [r] fqdn
|
8
|
+
# @return [String]
|
9
|
+
# @!attribute [r] uuid
|
10
|
+
# @return [String]
|
11
|
+
# @!attribute [r] name
|
12
|
+
# @return [String]
|
13
|
+
# @!attribute [r] created_at
|
14
|
+
# @return [Time]
|
15
|
+
# @!attribute [r] automatic
|
16
|
+
# @return [Boolean]
|
17
|
+
class Snapshot
|
18
|
+
include GandiV5::Data
|
19
|
+
|
20
|
+
members :name, :automatic, :fqdn
|
21
|
+
member :created_at, converter: GandiV5::Data::Converter::Time
|
22
|
+
member :uuid, gandi_key: 'id'
|
23
|
+
member(
|
24
|
+
:records,
|
25
|
+
gandi_key: 'zone_data',
|
26
|
+
converter: GandiV5::LiveDNS::Domain::Record,
|
27
|
+
array: true
|
28
|
+
)
|
29
|
+
|
30
|
+
alias snapshot_uuid uuid
|
31
|
+
|
32
|
+
# Delete this snapshot.
|
33
|
+
# @return [String] The confirmation message from Gandi.
|
34
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
35
|
+
def delete
|
36
|
+
_response, data = GandiV5.delete url
|
37
|
+
data['message']
|
38
|
+
end
|
39
|
+
|
40
|
+
# Update this snapshot.
|
41
|
+
# @param name [String, #to_s] new name for the snapshot.
|
42
|
+
# @return [String] The confirmation message from Gandi.
|
43
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
44
|
+
def update(name:)
|
45
|
+
_response, data = GandiV5.patch url, { name: name }.to_json
|
46
|
+
self.name = name
|
47
|
+
data['message']
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get snapshot details for this FQDN from Gandi.
|
51
|
+
# @param fqdn [String, #to_s] The fully qualified domain name to get the snapshots for.
|
52
|
+
# @param page [#each<Integer, #to_s>] the page(s) of results to retrieve.
|
53
|
+
# If page is not provided keep querying until an empty list is returned.
|
54
|
+
# If page responds to .each then iterate until an empty list is returned.
|
55
|
+
# @param per_page [Integer, #to_s] (optional default 100) how many results to get per page.
|
56
|
+
# @param automatic [nil, Boolean] (optional) filter by automatic or manual snapshot.
|
57
|
+
# @return [Array<GandiV5::LiveDNS::Domain::Snapshot>]
|
58
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
59
|
+
def self.list(fqdn, page: (1..), per_page: 100, **params)
|
60
|
+
params.reject! { |_k, v| v.nil? }
|
61
|
+
|
62
|
+
snapshots = []
|
63
|
+
GandiV5.paginated_get(url(fqdn), page, per_page, params: params) do |data|
|
64
|
+
snapshots += data.map { |item| from_gandi item.merge(fqdn: fqdn) }
|
65
|
+
end
|
66
|
+
snapshots
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get snapshot from Gandi.
|
70
|
+
# @param fqdn [String, #to_s] The fully qualified domain name the snapshot was made for.
|
71
|
+
# @param uuid [String, #to_s] the UUID of the snapshot to fetch.
|
72
|
+
# @return [GandiV5::LiveDNS::Domain::Snapshot]
|
73
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
74
|
+
def self.fetch(fqdn, uuid)
|
75
|
+
_response, data = GandiV5.get url(fqdn, uuid)
|
76
|
+
from_gandi data.merge(fqdn: fqdn)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Get the records which makeup this snapshot (fetching from Gandi if required).
|
80
|
+
# @return [Array<GandiV5::LiveDNS::Domain::Record>]
|
81
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
82
|
+
def records
|
83
|
+
return @records unless @records.nil?
|
84
|
+
|
85
|
+
@records = fetch_records
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def fetch_records
|
91
|
+
_response, data = GandiV5.get url
|
92
|
+
data.fetch('zone_data').map { |item| GandiV5::LiveDNS::Domain::Record.from_gandi item }
|
93
|
+
end
|
94
|
+
|
95
|
+
def url
|
96
|
+
"#{BASE}livedns/domains/#{CGI.escape fqdn}/snapshots/#{CGI.escape uuid}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.url(fqdn, snapshot_uuid = nil)
|
100
|
+
"#{BASE}livedns/domains/#{CGI.escape fqdn}/snapshots" +
|
101
|
+
(snapshot_uuid ? "/#{CGI.escape snapshot_uuid}" : '')
|
102
|
+
end
|
103
|
+
private_class_method :url
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class GandiV5
|
4
|
+
class LiveDNS
|
5
|
+
class Domain
|
6
|
+
# A Tsig key.
|
7
|
+
# @!attribyte [r] uuid
|
8
|
+
# @return [String]
|
9
|
+
# @!attribyte [r] name
|
10
|
+
# @return [String]
|
11
|
+
# @!attribyte [r] secret
|
12
|
+
# @return [String]
|
13
|
+
# @!attribyte [r] config_examples
|
14
|
+
# @return [Hash<Symbol -> String>]
|
15
|
+
class TsigKey
|
16
|
+
include GandiV5::Data
|
17
|
+
|
18
|
+
member :secret
|
19
|
+
member :uuid, gandi_key: 'id'
|
20
|
+
member :name, gandi_key: 'key_name'
|
21
|
+
member(
|
22
|
+
:config_examples,
|
23
|
+
gandi_key: 'config_samples',
|
24
|
+
converter: GandiV5::Data::Converter.new(
|
25
|
+
from_gandi: ->(value) { value.transform_keys(&:to_sym) },
|
26
|
+
to_gandi: ->(_value) { nil }
|
27
|
+
)
|
28
|
+
)
|
29
|
+
|
30
|
+
# Create a new DNSSEC key for a zone.
|
31
|
+
# @param sharing_id [nil, String, #to_s]
|
32
|
+
# @return [GandiV5::LiveDNS::Domain::DnssecKey]
|
33
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
34
|
+
def self.create(sharing_id = nil)
|
35
|
+
url_ = url
|
36
|
+
url_ += "?sharing_id=#{CGI.escape sharing_id}" if sharing_id
|
37
|
+
|
38
|
+
_response, data = GandiV5.post url_
|
39
|
+
fetch data.fetch('id')
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get keys from Gandi.
|
43
|
+
# If you need the secret, fingerprint, public_key or tag attributes you'll need
|
44
|
+
# to use GandiV5::LiveDNS::Domain::DnssecKey.fetch on each item.
|
45
|
+
# @return [Array<GandiV5::LiveDNS::Domain::TsigKey>]
|
46
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
47
|
+
def self.list
|
48
|
+
_response, data = GandiV5.get url
|
49
|
+
data.map { |item| from_gandi item }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get Tsig key from Gandi.
|
53
|
+
# @param uuid [String, #to_s] the UUID of the key to fetch.
|
54
|
+
# @return [GandiV5::LiveDNS::Domain::TsigKey]
|
55
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
56
|
+
def self.fetch(uuid)
|
57
|
+
_response, data = GandiV5.get url(uuid)
|
58
|
+
from_gandi data
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def self.url(uuid = nil)
|
64
|
+
"#{BASE}livedns/axfr/tsig" +
|
65
|
+
(uuid ? "/#{CGI.escape uuid}" : '')
|
66
|
+
end
|
67
|
+
private_class_method :url
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/gandi_v5/version.rb
CHANGED