zonesync 0.6.1 → 0.8.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.
@@ -0,0 +1,586 @@
1
+ grammar Zonefile
2
+ rule zone
3
+ (variable / space_or_break / comment)* soa (resource_record / variable / comment / space / linebreak)* {
4
+ def variables
5
+ @variables ||= begin
6
+ raw = elements[0].elements.select { |e| e.to_s =~ /^\$/ }
7
+ variables = {}
8
+ raw.each do |e|
9
+ variables[e.name.text_value.to_s] = e.value.text_value.to_s
10
+ end
11
+ variables
12
+ end
13
+ end
14
+
15
+ def origin
16
+ soa.origin.host.to_s
17
+ end
18
+
19
+ def to_s
20
+ text_value
21
+ end
22
+
23
+ def rr
24
+ elements[-1].elements.select { |e| e.to_s !~ /\A\s*([;$].*)?\z|\A\z/; }
25
+ end
26
+
27
+ def entries
28
+ elements[0].elements.select { |e| e.to_s !~ /\A\s*(;.*)?\z|\A\z/; } +
29
+ [soa] +
30
+ elements[-1].elements.select { |e| e.to_s !~ /\A\s*(;.*)?\z|\A\z/; }
31
+ end
32
+ }
33
+ end
34
+
35
+ rule variable
36
+ "$" name:([a-zA-Z0-9]+) space value:([a-zA-Z0-9\.\-_]+) space? comment? {
37
+ def to_s
38
+ "$#{name.text_value.to_s} #{value.text_value.to_s}"
39
+ end
40
+
41
+ def parse_type ; :variable ; end
42
+ }
43
+ end
44
+
45
+ rule soa
46
+ (
47
+ origin space ttl klass "SOA" space ns space "("? multiline_comment* space_or_break* rp multiline_comment* space_or_break* "("? multiline_comment* space_or_break* serial multiline_comment* space_or_break refresh multiline_comment* space_or_break reretry multiline_comment* space_or_break expiry multiline_comment* space_or_break nxttl multiline_comment* space_or_break* ")"? /
48
+ origin space klass ttl "SOA" space ns space "("? multiline_comment* space_or_break* rp multiline_comment* space_or_break* "("? multiline_comment* space_or_break* serial multiline_comment* space_or_break refresh multiline_comment* space_or_break reretry multiline_comment* space_or_break expiry multiline_comment* space_or_break nxttl multiline_comment* space_or_break* ")"?
49
+ ) {
50
+ def to_s
51
+ "#{origin} #{ttl} #{klass} SOA #{ns} #{rp} (#{serial} #{refresh} #{reretry} #{expiry} #{nxttl})"
52
+ end
53
+
54
+ def parse_type ; :soa ; end
55
+ }
56
+ end
57
+
58
+ rule resource_record
59
+ record:(a_record / aaaa_record / caa_record / cname_record / mx_record / naptr_record / ns_record / ptr_record / srv_record / spf_record / sshfp_record / txt_record / soa_record) space* comment:comment? linebreak {
60
+ def zone
61
+ p = parent
62
+ while p.respond_to?(:parent) && p.parent
63
+ p = p.parent
64
+ end
65
+ p
66
+ end
67
+
68
+ def to_s
69
+ text_value
70
+ end
71
+
72
+ def record_type
73
+ record.record_type
74
+ end
75
+
76
+ def ttl
77
+ record.ttl || zone.variables['TTL'].to_i
78
+ end
79
+
80
+ def comment
81
+ return if super.empty?
82
+ super
83
+ end
84
+
85
+ def method_missing(method_name, *args)
86
+ if record.respond_to?(method_name)
87
+ record.send(method_name, *args)
88
+ end
89
+ end
90
+
91
+ def respond_to?(method_name)
92
+ super || record.respond_to?(method_name)
93
+ end
94
+
95
+ def parse_type ; :record ; end
96
+ }
97
+ end
98
+
99
+ rule a_record
100
+ (
101
+ host space ms_age ttl klass "A" space ip_address /
102
+ host space ms_age klass ttl "A" space ip_address
103
+ ) {
104
+ def to_s
105
+ "#{host} #{ms_age} #{ttl} #{klass} A #{ip_address}"
106
+ end
107
+
108
+ def record_type
109
+ "A"
110
+ end
111
+ }
112
+ end
113
+
114
+ rule ip_address
115
+ [\d]+ "." [\d]+ "." [\d]+ "." [\d]+ {
116
+ def to_s
117
+ text_value
118
+ end
119
+ }
120
+ end
121
+
122
+ rule aaaa_record
123
+ (
124
+ host space ms_age ttl klass "AAAA" space ip_address:ip6_address /
125
+ host space ms_age klass ttl "AAAA" space ip_address:ip6_address
126
+ ) {
127
+ def to_s
128
+ "#{host} #{ttl} #{klass} AAAA #{ip_address}"
129
+ end
130
+
131
+ def record_type
132
+ "AAAA"
133
+ end
134
+ }
135
+ end
136
+
137
+ rule ip6_address
138
+ [\da-fA-F:.] 2..39 {
139
+ def to_s
140
+ text_value.downcase
141
+ end
142
+ }
143
+ end
144
+
145
+ rule caa_record
146
+ (
147
+ host space ms_age ttl klass "CAA" space flags:integer space tag:unquoted_string space value:caa_value /
148
+ host space ms_age klass ttl "CAA" space flags:integer space tag:unquoted_string space value:caa_value
149
+ ) {
150
+ def to_s
151
+ "#{host} #{ttl} #{klass} CAA #{flags} #{tag} #{value}"
152
+ end
153
+
154
+ def record_type
155
+ "CAA"
156
+ end
157
+ }
158
+ end
159
+
160
+ rule caa_value
161
+ (quoted_string / unquoted_string) {
162
+ def to_s
163
+ text_value
164
+ end
165
+ }
166
+ end
167
+
168
+ rule cname_record
169
+ (
170
+ host space ms_age ttl klass "CNAME" space target:host /
171
+ host space klass ms_age ttl "CNAME" space target:host /
172
+ host space ms_age ttl "CNAME" space target:host /
173
+ host space klass "CNAME" space target:host
174
+ ) {
175
+ def to_s
176
+ "#{host} #{ttl} #{klass} CNAME #{target}"
177
+ end
178
+
179
+ def record_type
180
+ "CNAME"
181
+ end
182
+ }
183
+ end
184
+
185
+ rule mx_record
186
+ (
187
+ host space ttl klass "MX" space priority:integer space exchanger:host /
188
+ host space klass ttl "MX" space priority:integer space exchanger:host
189
+ ) {
190
+ def to_s
191
+ "#{host} #{ttl} #{klass} MX #{priority} #{exchanger}"
192
+ end
193
+
194
+ def record_type
195
+ "MX"
196
+ end
197
+ }
198
+ end
199
+
200
+ rule naptr_record
201
+ (
202
+ host space ms_age ttl klass "NAPTR" space data /
203
+ host space ms_age klass ttl "NAPTR" space data
204
+ ) {
205
+ def to_s
206
+ "#{host} #{ttl} #{klass} NAPTR #{data}"
207
+ end
208
+
209
+ def record_type
210
+ "NAPTR"
211
+ end
212
+ }
213
+ end
214
+
215
+ rule ns_record
216
+ (
217
+ host space ms_age ttl klass "NS" space nameserver:host /
218
+ host space ms_age klass ttl "NS" space nameserver:host
219
+ ) {
220
+ def to_s
221
+ "#{host} #{ttl} #{klass} NS #{nameserver}"
222
+ end
223
+
224
+ def record_type
225
+ "NS"
226
+ end
227
+ }
228
+ end
229
+
230
+ rule ptr_record
231
+ (
232
+ host space ms_age ttl klass "PTR" space target:host /
233
+ host space ms_age klass ttl "PTR" space target:host
234
+ ) {
235
+ def to_s
236
+ "#{host} #{ttl} #{klass} PTR #{target}"
237
+ end
238
+
239
+ def record_type
240
+ "PTR"
241
+ end
242
+ }
243
+ end
244
+
245
+ rule soa_record
246
+ (
247
+ origin space ms_age ttl klass "SOA" space ns space rp space data /
248
+ origin space ms_age klass ttl "SOA" space ns space rp space data
249
+ ) {
250
+ def to_s
251
+ "#{origin} #{ttl} #{klass} SOA #{ns} #{rp} (#{space})"
252
+ end
253
+
254
+ def record_type
255
+ "SOA"
256
+ end
257
+ }
258
+ end
259
+
260
+ rule srv_record
261
+ (
262
+ host space ms_age ttl klass "SRV" space priority:integer space weight:integer space port:integer space target:host /
263
+ host space klass ms_age ttl "SRV" space priority:integer space weight:integer space port:integer space target:host /
264
+ host space ms_age ttl "SRV" space priority:integer space weight:integer space port:integer space target:host /
265
+ host space klass "SRV" space priority:integer space weight:integer space port:integer space target:host
266
+ ) {
267
+ def to_s
268
+ "#{host} #{ttl} #{klass} SRV #{priority} #{weight} #{port} #{target}"
269
+ end
270
+
271
+ def record_type
272
+ "SRV"
273
+ end
274
+ }
275
+ end
276
+
277
+ rule spf_record
278
+ (
279
+ host space ms_age ttl klass "SPF" space data:txt_data /
280
+ host space ms_age klass ttl "SPF" space data:txt_data
281
+ ) {
282
+ def to_s
283
+ "#{host} #{ttl} #{klass} SPF #{data}"
284
+ end
285
+
286
+ def record_type
287
+ "SPF"
288
+ end
289
+ }
290
+ end
291
+
292
+ rule sshfp_record
293
+ (
294
+ host space ms_age ttl klass "SSHFP" space alg:integer space fptype:integer space fp:fingerprint /
295
+ host space ms_age klass ttl "SSHFP" space alg:integer space fptype:integer space fp:fingerprint
296
+ ) {
297
+ def to_s
298
+ "#{host} #{ttl} #{klass} SSHFP #{alg} #{fptype} #{fp}"
299
+ end
300
+
301
+ def record_type
302
+ "SSHFP"
303
+ end
304
+ }
305
+ end
306
+
307
+ rule txt_record
308
+ (
309
+ host space ms_age ttl klass "TXT" space data:ms_txt_data /
310
+ host space ms_age klass ttl "TXT" space data:ms_txt_data
311
+ ) {
312
+ def to_s
313
+ "#{host} #{ttl} #{klass} TXT #{data}"
314
+ end
315
+
316
+ def record_type
317
+ "TXT"
318
+ end
319
+ }
320
+ end
321
+
322
+ rule origin
323
+ host comment* {
324
+ def to_s
325
+ "#{host}"
326
+ end
327
+ }
328
+ end
329
+
330
+ rule multiline_comment
331
+ linebreak+ comment* {
332
+ def to_s
333
+ text_value.strip
334
+ end
335
+ }
336
+ end
337
+
338
+ rule space
339
+ [ \t]+ {
340
+ def to_s
341
+ text_value
342
+ end
343
+ }
344
+ end
345
+
346
+ rule linebreak
347
+ [\n\r]+ {
348
+ def to_s
349
+ ''
350
+ end
351
+ }
352
+ end
353
+
354
+ rule space_or_break
355
+ [\s]+ {
356
+ def to_s
357
+ text_value
358
+ end
359
+ }
360
+ end
361
+
362
+ rule klass
363
+ (("IN" space) / '') {
364
+ def to_s
365
+ text_value.strip
366
+ end
367
+ }
368
+ end
369
+
370
+ rule comment
371
+ space* ";" [^\n\r]* {
372
+ def to_s
373
+ text_value[2..].to_s.strip
374
+ end
375
+
376
+ def parse_type ; :comment ; end
377
+ }
378
+ end
379
+
380
+ rule ns
381
+ host comment* {
382
+ def to_s
383
+ "#{host}"
384
+ end
385
+ }
386
+ end
387
+
388
+ rule rp
389
+ rp_value comment* {
390
+ def to_s
391
+ "#{rp_value}"
392
+ end
393
+ }
394
+ end
395
+
396
+ rule rp_value
397
+ ("." / (("\\." / [a-zA-Z0-9\-)])+ "."?)+) {
398
+ def to_s
399
+ text_value
400
+ end
401
+ }
402
+ end
403
+
404
+ rule serial
405
+ integer comment* {
406
+ def to_i
407
+ integer.to_i
408
+ end
409
+ def to_s
410
+ "#{to_i}"
411
+ end
412
+ }
413
+ end
414
+
415
+ rule time_interval
416
+ integer time_multiplier {
417
+ def to_s
418
+ text_value
419
+ end
420
+
421
+ def to_i
422
+ time_multiplier.to_i * integer.to_i
423
+ end
424
+ }
425
+ end
426
+
427
+ rule refresh
428
+ time_interval comment* {
429
+ def to_i
430
+ time_interval.to_i
431
+ end
432
+ def to_s
433
+ time_interval.to_s
434
+ end
435
+ }
436
+ end
437
+
438
+ rule integer
439
+ [0-9]+ {
440
+ def to_i
441
+ text_value.to_i
442
+ end
443
+ def to_s
444
+ "#{to_i}"
445
+ end
446
+ }
447
+ end
448
+
449
+ rule time_multiplier
450
+ ( 's' / 'S' / 'm' / 'M' / 'h' / 'H' / 'd' / 'D' / 'w' / 'W' / '' ) {
451
+ def to_s
452
+ text_value
453
+ end
454
+ def to_i
455
+ case text_value.downcase
456
+ when 'm' then 60
457
+ when 'h' then 60 * 60
458
+ when 'd' then 60 * 60 * 24
459
+ when 'w' then 60 * 60 * 24 * 7
460
+ else
461
+ 1
462
+ end
463
+ end
464
+ }
465
+ end
466
+
467
+ rule reretry
468
+ time_interval comment* {
469
+ def to_i
470
+ time_interval.to_i
471
+ end
472
+ def to_s
473
+ time_interval.to_s
474
+ end
475
+ }
476
+ end
477
+
478
+ rule expiry
479
+ time_interval comment* {
480
+ def to_i
481
+ time_interval.to_i
482
+ end
483
+ def to_s
484
+ time_interval.to_s
485
+ end
486
+ }
487
+ end
488
+
489
+ rule nxttl
490
+ time_interval comment* {
491
+ def to_i
492
+ time_interval.to_i
493
+ end
494
+ def to_s
495
+ time_interval.to_s
496
+ end
497
+ }
498
+ end
499
+
500
+ rule ms_age
501
+ ( "[AGE:" [\d]+ "]" space / '' ) {
502
+ def to_s
503
+ text_value
504
+ end
505
+ }
506
+ end
507
+
508
+ rule ttl
509
+ ((time_interval space) / '') {
510
+ def to_i
511
+ respond_to?(:time_interval) ? time_interval.to_i : nil
512
+ end
513
+ def to_s
514
+ respond_to?(:time_interval) ? time_interval.to_s : ''
515
+ end
516
+ }
517
+ end
518
+
519
+ rule host
520
+ ( ([*a-zA-Z0-9\-\._]+) / "@" / ' ' / "\t" ) {
521
+ def to_s
522
+ text_value
523
+ end
524
+ }
525
+ end
526
+
527
+ rule fingerprint
528
+ [a-fA-Z0-9:]+ {
529
+ def to_s
530
+ text_value.strip
531
+ end
532
+ }
533
+ end
534
+
535
+ rule data
536
+ [^;\n\r]+ {
537
+ def to_s
538
+ text_value.strip
539
+ end
540
+ }
541
+ end
542
+
543
+ rule ms_txt_data
544
+ (
545
+ "(" space* data:txt_data space* ")" /
546
+ data:txt_data
547
+ ) {
548
+ def to_s
549
+ data.to_s
550
+ end
551
+ }
552
+ end
553
+
554
+ rule txt_data
555
+ txt_string (space txt_data)* {
556
+ def to_s
557
+ text_value
558
+ end
559
+ }
560
+ end
561
+
562
+ rule txt_string
563
+ (quoted_string / unquoted_string) {
564
+ def to_s
565
+ text_value
566
+ end
567
+ }
568
+ end
569
+
570
+ rule quoted_string
571
+ ( '"' ( '\"' / [^"] )* '"') {
572
+ def to_s
573
+ text_value
574
+ end
575
+ }
576
+ end
577
+
578
+ rule unquoted_string
579
+ '[a-zA-Z0-9=_\.\-\@\:\~]+'r {
580
+ def to_s
581
+ text_value
582
+ end
583
+ }
584
+ end
585
+
586
+ end
data/lib/zonesync.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require "zonesync/provider"
2
2
  require "zonesync/diff"
3
+ require "zonesync/validator"
3
4
  require "zonesync/logger"
4
5
  require "zonesync/cli"
5
6
  require "zonesync/rake"
7
+ require "zonesync/errors"
6
8
 
7
9
  module Zonesync
8
10
  def self.call zonefile: "Zonefile", credentials: default_credentials, dry_run: false
@@ -33,7 +35,33 @@ module Zonesync
33
35
  def call dry_run: false
34
36
  source = Provider.from(self.source)
35
37
  destination = Provider.from(self.destination)
36
- operations = Diff.call(from: destination, to: source)
38
+ operations = Diff.call(
39
+ from: destination.diffable_records,
40
+ to: source.diffable_records,
41
+ )
42
+
43
+ Validator.call(operations, destination)
44
+
45
+ smanifest = source.manifest.generate
46
+ dmanifest = destination.manifest.existing
47
+ if smanifest != dmanifest
48
+ if dmanifest
49
+ operations << [:change, [dmanifest, smanifest]]
50
+ else
51
+ operations << [:add, [smanifest]]
52
+ end
53
+ end
54
+
55
+ schecksum = source.manifest.generate_checksum
56
+ dchecksum = destination.manifest.existing_checksum
57
+ if schecksum != dchecksum
58
+ if dchecksum
59
+ operations << [:change, [dchecksum, schecksum]]
60
+ else
61
+ operations << [:add, [schecksum]]
62
+ end
63
+ end
64
+
37
65
  operations.each do |method, args|
38
66
  Logger.log(method, args, dry_run: dry_run)
39
67
  destination.send(method, *args) unless dry_run
data/zonesync.gemspec CHANGED
@@ -27,9 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
- spec.add_dependency "dns-zonefile", "~>1.0"
31
30
  spec.add_dependency "diff-lcs", "~>1.4"
32
31
  spec.add_dependency "thor", "~>1.0"
32
+ spec.add_dependency "treetop", "~>1.6"
33
33
 
34
34
  spec.add_development_dependency "rake"
35
35
  spec.add_development_dependency "rspec"