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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/README.md +3 -2
  4. data/lib/gandi_v5.rb +34 -13
  5. data/lib/gandi_v5/domain.rb +2 -8
  6. data/lib/gandi_v5/email/forward.rb +2 -8
  7. data/lib/gandi_v5/email/mailbox.rb +2 -8
  8. data/lib/gandi_v5/live_dns.rb +0 -12
  9. data/lib/gandi_v5/live_dns/domain.rb +313 -29
  10. data/lib/gandi_v5/live_dns/domain/dnssec_key.rb +115 -0
  11. data/lib/gandi_v5/live_dns/domain/record.rb +81 -0
  12. data/lib/gandi_v5/live_dns/domain/snapshot.rb +107 -0
  13. data/lib/gandi_v5/live_dns/domain/tsig_key.rb +71 -0
  14. data/lib/gandi_v5/version.rb +1 -1
  15. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/fetch.yml +1 -2
  16. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list_tsig.yml +3 -0
  17. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/nameservers.yml +3 -0
  18. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/fetch.yml +12 -0
  19. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/list.yml +9 -0
  20. data/spec/fixtures/bodies/{GandiV5_LiveDNS_Zone_Snapshot → GandiV5_LiveDNS_Domain_Snapshot}/fetch.yml +4 -3
  21. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_Snapshot/list.yml +5 -0
  22. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/fetch.yml +9 -0
  23. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/list.yml +4 -0
  24. data/spec/units/gandi_v5/domain_spec.rb +6 -37
  25. data/spec/units/gandi_v5/email/forward_spec.rb +5 -34
  26. data/spec/units/gandi_v5/email/mailbox_spec.rb +4 -34
  27. data/spec/units/gandi_v5/live_dns/domain/dnssec_key_spec.rb +128 -0
  28. data/spec/units/gandi_v5/live_dns/{record_set_spec.rb → domain/record_spec.rb} +1 -1
  29. data/spec/units/gandi_v5/live_dns/domain/snapshot_spec.rb +101 -0
  30. data/spec/units/gandi_v5/live_dns/domain/tsig_key_spec.rb +78 -0
  31. data/spec/units/gandi_v5/live_dns/domain_spec.rb +297 -118
  32. data/spec/units/gandi_v5/live_dns_spec.rb +0 -12
  33. data/spec/units/gandi_v5_spec.rb +111 -14
  34. metadata +18 -24
  35. data/lib/gandi_v5/live_dns/has_zone_records.rb +0 -153
  36. data/lib/gandi_v5/live_dns/record_set.rb +0 -79
  37. data/lib/gandi_v5/live_dns/zone.rb +0 -160
  38. data/lib/gandi_v5/live_dns/zone/snapshot.rb +0 -81
  39. data/spec/features/domain_spec.rb +0 -45
  40. data/spec/features/livedns_domain_spec.rb +0 -8
  41. data/spec/features/livedns_zone_spec.rb +0 -44
  42. data/spec/features/mailbox_spec.rb +0 -18
  43. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/fetch.yml +0 -11
  44. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/list.yml +0 -11
  45. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/list.yml +0 -3
  46. data/spec/fixtures/vcr/Domain_features/List_domains.yml +0 -55
  47. data/spec/fixtures/vcr/Domain_features/Renew_domain.yml +0 -133
  48. data/spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml +0 -32
  49. data/spec/fixtures/vcr/LiveDNS_Zone_features/List_zones.yml +0 -42
  50. data/spec/fixtures/vcr/LiveDNS_Zone_features/Make_and_save_snapshot.yml +0 -72
  51. data/spec/fixtures/vcr/LiveDNS_Zone_features/Save_zone_to_file.yml +0 -28
  52. data/spec/fixtures/vcr/Mailbox_features/List_mailboxes.yml +0 -39
  53. data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +0 -66
  54. 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class GandiV5
4
- VERSION = '0.6.0'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -1,4 +1,3 @@
1
1
  ---
2
- zonedata: /zones/zone-uuid/recprds
3
2
  fqdn: example.com
4
- zone: /zones/zone-uuid
3
+ automatic_snapshots: true
@@ -0,0 +1,3 @@
1
+ ---
2
+ - id: key-uuid
3
+ key_name: key-name
@@ -0,0 +1,3 @@
1
+ ---
2
+ - a.example.com
3
+ - b.example.com
@@ -0,0 +1,12 @@
1
+ ---
2
+ id: key-uuid
3
+ status: status
4
+ fqdn: example.com
5
+ algorithm: 2
6
+ algorithm_name: Diffie-Hellman
7
+ deleted: false
8
+ ds: ds-record
9
+ flags: 256
10
+ fingerprint: fp
11
+ public_key: pub-key
12
+ tag: tag
@@ -0,0 +1,9 @@
1
+ ---
2
+ - id: key-uuid
3
+ status: status
4
+ fqdn: example.com
5
+ algorithm: 2
6
+ algorithm_name: Diffie-Hellman
7
+ deleted: false
8
+ ds: ds-record
9
+ flags: 256
@@ -1,7 +1,8 @@
1
1
  ---
2
- date_created: '2016-12-16T16:51:26Z'
3
- uuid: snapshot-uuid
4
- zone_uuid: zone-uuid
2
+ created_at: '2016-12-16T16:51:26Z'
3
+ id: snapshot-uuid
4
+ name: snapshot-name
5
+ automatic: true
5
6
  zone_data:
6
7
  - rrset_type: A
7
8
  rrset_ttl: 10800
@@ -0,0 +1,5 @@
1
+ ---
2
+ - id: snapshot-uuid
3
+ name: snapshot-name
4
+ automatic: true
5
+ created_at: '2016-12-16T16:51:26Z'
@@ -0,0 +1,9 @@
1
+ ---
2
+ id: key-uuid
3
+ key_name: key-name
4
+ secret: key-secret
5
+ config_samples:
6
+ bind: bind-sample
7
+ knot: knot-sample
8
+ nsd: nsd-sample
9
+ powerdns: powerdns-sample