/
dnsimple.rb
170 lines (147 loc) · 5.06 KB
/
dnsimple.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
require 'dnsimple'
require_relative 'dnsimple/patch_api_header'
require_relative 'dnsimple/patch_request_error_to_include_errors'
module RecordStore
class Provider::DNSimple < Provider
class << self
def record_types
super | Set.new(%w(PTR SSHFP))
end
def supports_alias?
true
end
def empty_non_terminal_over_wildcard?
false
end
# returns an array of Record objects that match the records which exist in the provider
def retrieve_current_records(zone:, stdout: $stdout)
retry_on_connection_errors do
session.zones.all_zone_records(account_id, zone).data.map do |record|
build_from_api(record, zone)
rescue StandardError
stdout.puts "Cannot build record: #{record}"
raise
end.compact
end
end
# Returns an array of the zones managed by provider as strings
def zones
retry_on_connection_errors do
session.zones.all_zones(account_id).data.map(&:name)
end
end
private
def add(record, zone)
record_hash = api_hash(record, zone)
res = session.zones.create_zone_record(account_id, zone, record_hash)
if record.type == 'ALIAS'
txt_alias = retrieve_current_records(zone: zone).detect do |rr|
rr.type == 'TXT' && rr.fqdn == record.fqdn && rr.txtdata == "ALIAS for #{record.alias.chomp('.')}"
end
remove(txt_alias, zone)
end
res
end
def remove(record, zone)
session.zones.delete_zone_record(account_id, zone, record.id)
end
def update(id, record, zone)
session.zones.update_zone_record(account_id, zone, id, api_hash(record, zone))
end
def session
@dns ||= Dnsimple::Client.new(
base_url: secrets.fetch('base_url'),
access_token: secrets.fetch('api_token'),
)
end
def account_id
@account_id ||= secrets.fetch('account_id')
end
def secrets
super.fetch('dnsimple')
end
def build_from_api(api_record, zone)
fqdn = api_record.name.present? ? "#{api_record.name}.#{zone}" : zone
fqdn = "#{fqdn}." unless fqdn.ends_with?('.')
record_type = api_record.type
record = {
record_id: api_record.id,
ttl: api_record.ttl,
fqdn: fqdn.downcase,
}
return if record_type == 'SOA'
case record_type
when 'A', 'AAAA'
record.merge!(address: api_record.content)
when 'ALIAS'
record.merge!(alias: api_record.content)
when 'CAA'
flags, tag, value = api_record.content.split(' ')
record.merge!(
flags: flags.to_i,
tag: tag,
value: Record.unquote(value),
)
when 'CNAME'
record.merge!(cname: api_record.content)
when 'MX'
record.merge!(preference: api_record.priority, exchange: api_record.content)
when 'NS'
record.merge!(nsdname: api_record.content)
when 'PTR'
record.merge!(ptrdname: api_record.content)
when 'SSHFP'
algorithm, fptype, fingerprint = api_record.content.split(' ')
record.merge!(
algorithm: algorithm.to_i,
fptype: fptype.to_i,
fingerprint: fingerprint,
)
when 'SPF', 'TXT'
record.merge!(txtdata: Record.unescape(api_record.content).gsub(';', '\;'))
when 'SRV'
weight, port, host = api_record.content.split(' ')
record.merge!(
priority: api_record.priority,
weight: weight.to_i,
port: port.to_i,
target: Record.ensure_ends_with_dot(host),
)
end
Record.const_get(record_type).new(record)
end
def api_hash(record, zone)
record_hash = {
name: record.fqdn.gsub(Record.ensure_ends_with_dot(zone).to_s, '').chomp('.'),
ttl: record.ttl,
type: record.type,
}
case record.type
when 'A', 'AAAA'
record_hash[:content] = record.address
when 'ALIAS'
record_hash[:content] = record.alias.chomp('.')
when 'CAA'
record_hash[:content] = "#{record.flags} #{record.tag} \"#{record.value.chomp('.')}\""
when 'CNAME'
record_hash[:content] = record.cname.chomp('.')
when 'MX'
record_hash[:priority] = record.preference
record_hash[:content] = record.exchange.chomp('.')
when 'NS'
record_hash[:content] = record.nsdname.chomp('.')
when 'PTR'
record_hash[:content] = record.ptrdname.chomp('.')
when 'SSHFP'
record_hash[:content] = record.rdata_txt
when 'SPF', 'TXT'
record_hash[:content] = Record.escape(record.txtdata).gsub('\;', ';')
when 'SRV'
record_hash[:content] = "#{record.weight} #{record.port} #{record.target.chomp('.')}"
record_hash[:priority] = record.priority
end
record_hash
end
end
end
end