forked from Shopify/record_store
/
dynect.rb
113 lines (92 loc) · 3.13 KB
/
dynect.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
require 'fog/dynect'
require 'limiter'
Fog::Dynect::DNS::Real.extend(Limiter::Mixin)
Fog::Dynect::DNS::Real.limit_method(:request, rate: 5, interval: 1) # 5 RPS == 300 RPM
module RecordStore
class Provider::DynECT < Provider
class << self
def freeze_zone(zone)
session.put_zone(zone, freeze: true)
end
def thaw_zone(zone)
session.put_zone(zone, thaw: true)
end
def publish(zone)
session.put_zone(zone, publish: true)
end
# Applies changeset to provider
def apply_changeset(changeset, stdout = $stdout)
thaw_zone(changeset.zone)
super
publish(changeset.zone)
rescue StandardError
puts "An exception occurred while applying DNS changes, deleting changeset"
discard_change_set(changeset.zone)
raise
ensure
freeze_zone(changeset.zone)
end
# returns an array of Record objects that match the records which exist in the provider
def retrieve_current_records(zone:, stdout: $stdout)
session.get_all_records(zone).body.fetch('data').flat_map do |_type, records|
records.map do |record_body|
build_from_api(record_body)
rescue StandardError
stdout.puts "Cannot build record: #{record_body}"
end
end.compact
end
# Returns an array of the zones managed by provider as strings
def zones
session.zones.map(&:domain)
end
private
def add(record, zone)
session.post_record(record.type, zone, record.fqdn, api_rdata(record), 'ttl' => record.ttl)
end
def remove(record, zone)
session.delete_record(record.type, zone, record.fqdn, record.id)
end
def update(id, record, zone)
session.put_record(record.type, zone, record.fqdn, api_rdata(record), 'ttl' => record.ttl, 'record_id' => id)
end
def discard_change_set(zone)
session.request(expects: 200, method: :delete, path: "ZoneChanges/#{zone}")
end
def session
Thread.current[:dns] ||= Fog::DNS.new(session_params)
end
def session_params
{
provider: 'Dynect',
dynect_customer: secrets.fetch('customer'),
dynect_username: secrets.fetch('username'),
dynect_password: secrets.fetch('password'),
job_poll_timeout: 20,
}
end
def secrets
super.fetch('dynect')
end
def api_rdata(record)
case record.type
when 'SPF', 'TXT'
{ txtdata: Record.long_quote(record.rdata_txt) }
else
record.rdata
end
end
def build_from_api(api_record)
rdata = api_record.fetch('rdata')
record = api_record.merge(rdata).slice!('rdata').symbolize_keys
type = record.fetch(:record_type)
return if type == 'SOA'
record[:txtdata] = Record.unlong_quote(Record.unescape(record[:txtdata])) if %w[SPF TXT].include?(type)
fqdn = record.fetch(:fqdn)
fqdn = "#{fqdn}." unless fqdn.ends_with?('.')
record[:fqdn] = fqdn.downcase
Record.const_get(type).new(record)
end
end
end
end