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.
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