dnser 0.0.3

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,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Alexey Shcherbakov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ DNSer
2
+ =====
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/dnser.png)](http://badge.fury.io/rb/dnser)
5
+
6
+ Ruby DSL for create DNS Zone file
7
+
8
+ ```ruby
9
+ template :google_app do |host, code, params|
10
+
11
+ TXT host, ('google-site-verification=' + code), :comment => "Google verification code"
12
+
13
+ MX host, 'ASPMX.L.GOOGLE.COM.', priority: 1, comment: "GMail"
14
+ MX host, 'ALT1.ASPMX.L.GOOGLE.COM.', priority: 5, comment: "GMail"
15
+ MX host, 'ALT2.ASPMX.L.GOOGLE.COM.', priority: 5, comment: "GMail"
16
+ MX host, 'ASPMX2.GOOGLEMAIL.COM.', priority: 10, comment: "GMail"
17
+ MX host, 'ASPMX23.GOOGLEMAIL.COM.', priority: 10, comment: "GMail"
18
+ TXT host, 'v=spf1 include:_spf.google.com ~all', comment: "GMail SPF"
19
+
20
+ %w(mail doc).each do |sub|
21
+ CNAME [sub, host].join('.'), 'ghs.googlehosted.com.'
22
+ end
23
+ end
24
+
25
+ zone 'domain.ltd' do
26
+ ttl 3600
27
+ ns = NS 'ns1', 'ns1.dnsimple.com.'
28
+
29
+ SOA host do
30
+ nameserver ns
31
+ email 'admin@domain.ltd'
32
+ end
33
+
34
+ A IPAddr.new('127.0.0.1'), alias: :www
35
+
36
+ A :dev, IPAddr.new('127.0.0.2')
37
+
38
+ apply_google_app host, '6tTalLzrBXBO4Gy9700TAbpg2QTKzGYEuZ_Ls69jle8'
39
+
40
+ SRV 'corp', 'calendar.abc.com.' do
41
+ service '_caldavs'
42
+ protocol :tcp
43
+ port 8443
44
+ end
45
+
46
+ SRV 'calendar2.abc.com.', service: :caldavs, protocol: :tcp, port: 8443, weight: 0, priority: 1
47
+ end
48
+ ```
49
+
50
+ Result:
51
+
52
+ $ORIGIN domain.ltd.
53
+ $TTL 3600
54
+ domain.ltd. IN SOA ns1.domain.ltd. admin.domain.ltd. (20130803 3600 3600 3600 3600)
55
+ ns1 IN NS ns1.dnsimple.com.
56
+ @ IN A 127.0.0.1
57
+ @ IN TXT "v=spf1 include:_spf.google.com ~all" #GMail SPF
58
+ @ IN MX 10 ASPMX23.GOOGLEMAIL.COM. #GMail
59
+ @ IN TXT google-site-verification=6tTalLzrBXBO4Gy9700TAbpg2QTKzGYEuZ_Ls69jle8 #Google verification code
60
+ @ IN MX 1 ASPMX.L.GOOGLE.COM. #GMail
61
+ @ IN MX 5 ALT1.ASPMX.L.GOOGLE.COM. #GMail
62
+ @ IN MX 5 ALT2.ASPMX.L.GOOGLE.COM. #GMail
63
+ @ IN MX 10 ASPMX2.GOOGLEMAIL.COM. #GMail
64
+ _caldavs._tcp.corp.domain.ltd. IN SRV 0 0 8443 calendar.abc.com.
65
+ _caldavs._tcp.domain.ltd. IN SRV 1 0 8443 calendar2.abc.com.
66
+ dev IN A 127.0.0.2
67
+ doc IN CNAME ghs.googlehosted.com.
68
+ mail IN CNAME ghs.googlehosted.com.
69
+ www IN CNAME domain.ltd.
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'dnser'
5
+ require 'dnser/version'
6
+
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: dnser [options] zone"
9
+ opts.on('-o', '--output [file]', 'Path to output file') do |file|
10
+ DNSer.config.output = File.open(file, 'w')
11
+ end
12
+ opts.on('-f', '--full', 'Use full domain name in records') do
13
+ DNSer.config.full_domain = true
14
+ end
15
+ opts.on_tail('-v', '--version') { puts "DNSer v#{DNSer::VERSION}"; exit(0) }
16
+
17
+ opts.on_tail("-h", "--help", "Show this message") do
18
+ puts opts
19
+ exit
20
+ end
21
+ end.parse!
22
+
23
+ zone_file = ARGV.last
24
+
25
+ unless zone_file
26
+ puts "Zone file not defined."
27
+ exit(0)
28
+ end
29
+
30
+ unless File.exist?(zone_file)
31
+ puts "Zone file #{zone_file} doesn't exist."
32
+ exit(0)
33
+ end
34
+
35
+ load zone_file
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dnser/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'dnser'
7
+ s.version = DNSer::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.date = '2013-08-03'
10
+ s.summary = "DNS zone file in ruby"
11
+ s.description = "Clean ruby syntax for writing DNS zone file."
12
+ s.authors = ["Alexey Shcherbakov"]
13
+ s.email = 'schalexey@gmail.com'
14
+ s.files = `git ls-files`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.homepage = 'https://github.com/fuCtor/DNSer'
17
+ s.license = 'MIT'
18
+
19
+ s.add_development_dependency "rspec"
20
+
21
+ s.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,52 @@
1
+ require ::File.expand_path('../dnser/domain.rb', __FILE__)
2
+ require ::File.expand_path('../dnser/template.rb', __FILE__)
3
+ require 'singleton'
4
+
5
+ module DNSer
6
+
7
+ def self.domain domain_name, params = {} , &block
8
+ Domain.new domain_name, params, &block
9
+ end
10
+
11
+ def self.create_template name, params = {}, &block
12
+ @templates ||= {}
13
+ @templates[name.to_s.downcase.to_sym] = DNSer::Template.new params, &block
14
+ end
15
+
16
+ def self.apply_template name, &block
17
+ if @templates
18
+ tpl = @templates[name.to_s.downcase.to_sym].dup rescue nil
19
+ yield tpl if tpl if block_given?
20
+ raise Template::Unknown.new(name.to_s.downcase.to_sym), 'Unknown DNS template' unless tpl
21
+ tpl
22
+ end
23
+ end
24
+
25
+ def self.config
26
+ Config.instance
27
+ end
28
+
29
+
30
+ class Config
31
+ include ::Singleton
32
+
33
+ attr_accessor :output, :full_domain
34
+
35
+ def output
36
+ @output ||= DNSer::StreamBuilder.new($stdout)
37
+ end
38
+ def full_domain
39
+ @full_domain ||= false
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ def zone *args , &block
47
+ DNSer.domain *args , &block
48
+ end
49
+
50
+ def template *args , &block
51
+ DNSer.create_template *args , &block
52
+ end
@@ -0,0 +1,20 @@
1
+ module DNSer
2
+ class Builder
3
+ def write *args
4
+ raise NotImplementedError
5
+ end
6
+
7
+ def origin name
8
+ raise NotImplementedError
9
+ end
10
+
11
+ def ttl value
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def sync
16
+ end
17
+ end
18
+ end
19
+
20
+ Dir.glob(::File.expand_path('../builders/*.rb', __FILE__)).each{|file| require file }
@@ -0,0 +1,66 @@
1
+ require 'stringio'
2
+ module DNSer
3
+ class StreamBuilder < Builder
4
+ attr_reader :stream
5
+ def initialize stream
6
+ case stream
7
+ when String
8
+ @stream = File.new stream, 'w'
9
+ when ::IO,::File,::StringIO
10
+ @stream = stream
11
+ else
12
+ raise "Unknown stream type #{stream.class}"
13
+ end
14
+
15
+ @buffer = []
16
+ end
17
+
18
+ def origin name
19
+ @stream << ('$ORIGIN ' + name.to_s + "\n")
20
+ end
21
+
22
+ def ttl value
23
+ @stream << ('$TTL ' + value.to_s + "\n")
24
+ end
25
+
26
+ def write *args
27
+ if (args.count == 1)
28
+ record = args.first
29
+ write record.host, record.type, record.value, record.comment
30
+ else
31
+
32
+ value = args[2]
33
+ if value.is_a? DNSer::Record
34
+ value = value.full_host
35
+ else
36
+ value = value.to_s
37
+ end
38
+ @buffer << {host: args[0].to_s, type: args[1].to_s.upcase ,value: value, comment: args[3] }
39
+ end
40
+ end
41
+
42
+ def sync
43
+
44
+ max_host_length = 0
45
+ max_type_length = 0
46
+ max_value_length = 0
47
+
48
+ @buffer.each do |r|
49
+ max_host_length = max_host_length < r[:host].size ? r[:host].length : max_host_length
50
+ max_type_length = max_type_length < r[:type].size ? r[:type].length : max_type_length
51
+ max_value_length = max_value_length < r[:value].size ? r[:value].length : max_value_length
52
+ end
53
+
54
+ @buffer.each do |r|
55
+ @stream << r[:host].ljust(max_host_length + 2)
56
+ @stream << 'IN ' + r[:type].ljust(max_type_length)
57
+ @stream << "\t" + r[:value].ljust(max_value_length)
58
+ @stream << "\t##{r[:comment]}" unless r[:comment].empty?
59
+ @stream << "\n"
60
+ end
61
+
62
+ @buffer.clear
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,92 @@
1
+ require 'date'
2
+ require 'ipaddr'
3
+
4
+ require ::File.expand_path('../record.rb', __FILE__)
5
+ require ::File.expand_path('../builder.rb', __FILE__)
6
+
7
+ module DNSer
8
+ class Domain
9
+ attr :name
10
+
11
+ def initialize domain_name, params = {}, &block
12
+ @name = domain_name
13
+
14
+ @builder = params[:builder] || DNSer.config.output #DNSer::StreamBuilder.new($stdout)
15
+ @builder = DNSer::StreamBuilder.new(@builder) unless @builder.is_a? DNSer::Builder
16
+
17
+ @name = @name + '.' unless @name.end_with?('.')
18
+ @ttl_val = 3600
19
+ @records = []
20
+ instance_exec self, &block if block
21
+
22
+ dump
23
+ end
24
+
25
+ def name
26
+ @name
27
+ end
28
+
29
+ alias_method :current, :name
30
+ alias_method :host, :name
31
+
32
+ def ttl(*args)
33
+ @ttl_val = args.first unless args.empty?
34
+ @ttl_val
35
+ end
36
+
37
+ def dump
38
+ @builder.origin @name
39
+ @builder.ttl @ttl_val
40
+
41
+ @records_tmp = @records.dup
42
+
43
+ soa_index = @records_tmp.index {|x| x.is_a?(DNSer::SoaRecord) }
44
+ @builder.write @records_tmp.delete_at( soa_index ) if soa_index
45
+
46
+ ns = []
47
+ @records_tmp = @records_tmp.map do |r|
48
+ if r.type.to_s.downcase == 'ns'
49
+ @builder.write r
50
+ nil
51
+ else
52
+ r
53
+ end
54
+ end .compact
55
+
56
+ # @records_tmp.sort! {|x, y| x.host <=> y.host }
57
+ @records_tmp.each {|r| @builder.write r }
58
+
59
+ @builder.sync
60
+ end
61
+
62
+ def method_missing name, *args, &block
63
+ name = name.to_s.downcase
64
+
65
+ return DNSer.apply_template name.gsub('apply_', '') do |tpl|
66
+ tpl.apply self, *args, &block
67
+ end if name.start_with? 'apply_'
68
+
69
+ params = args.last.dup if args.last.is_a? Hash
70
+
71
+ record_class = begin
72
+ eval "::DNSer::#{name.capitalize}Record"
73
+ rescue NameError => e
74
+ args = [name] + args
75
+ DNSer::BaseRecord
76
+ end
77
+
78
+ record = record_class.new(self, *args, &block)
79
+ @records << record
80
+
81
+ if params.key? :alias
82
+ [params[:alias]].flatten.each do |host|
83
+ @records << DNSer::BaseRecord.new(self, :CNAME, host, record, &block)
84
+ end
85
+ end if params
86
+
87
+ record
88
+ end
89
+
90
+
91
+ end
92
+ end
@@ -0,0 +1,126 @@
1
+ module DNSer
2
+ class Record
3
+ attr_writer :host
4
+ attr_reader :domain
5
+
6
+ class Unknown < RuntimeError
7
+ attr_reader :name
8
+ attr_reader :args
9
+ def initialize name, args
10
+ @name = name
11
+ @args = args
12
+ end
13
+ end
14
+
15
+ class EmptyValue < RuntimeError
16
+ attr_reader :record
17
+ attr_reader :field
18
+ def initialize record
19
+ @record = record
20
+ end
21
+ end
22
+
23
+
24
+ def initialize domain, host, params = {}
25
+
26
+ ttl domain.ttl
27
+ priority 0 unless @priority_val
28
+
29
+ unless host.is_a? Symbol
30
+ @host = host.dup
31
+ else
32
+ @host = host
33
+ end
34
+
35
+ @domain = domain
36
+ end
37
+
38
+ def ttl(value)
39
+ @ttl = value
40
+ end
41
+
42
+ def priority(*args)
43
+ @priority_val = args.first if args.size == 1
44
+ @priority_val
45
+ end
46
+
47
+ alias_method :prio, :priority
48
+
49
+ def host
50
+ DNSer.config.full_domain ? expand_domain(@host.to_s) : collapse_domain(@host.to_s)
51
+ end
52
+
53
+ def full_host
54
+ short_host = host
55
+ if short_host == '@'
56
+ domain.name
57
+ else
58
+ [short_host, domain.name].join('.')
59
+ end
60
+ end
61
+
62
+ def type
63
+ raise NotImplementedError
64
+ end
65
+
66
+ def value
67
+ raise NotImplementedError
68
+ end
69
+
70
+ def comment(v = nil)
71
+ @comment = v if v
72
+ @comment || ''
73
+ end
74
+
75
+
76
+ protected
77
+ def expand_domain( name )
78
+ return domain.host if name == '@'
79
+ return [name, domain.host].join('.') unless name.end_with?('.')
80
+ name
81
+ end
82
+
83
+ def collapse_domain( name )
84
+
85
+ name = name.dup
86
+
87
+ return name if name == '@'
88
+ return name unless name.end_with?('.')
89
+
90
+ name = name + '.' unless name.end_with?('.')
91
+
92
+ name.gsub!( domain.name.dup, '')
93
+ name.chop! if name.end_with?('.')
94
+
95
+ if name.empty?
96
+ '@'
97
+ else
98
+ name
99
+ end
100
+
101
+ end
102
+
103
+ def canonical_host( target_host )
104
+
105
+ case host
106
+ when DNSer::Record
107
+ target_host = target_host.full_host.to_s
108
+ when IPAddr
109
+ target_host = target_host.to_s
110
+ else
111
+
112
+ ip = IPAddr.new target_host rescue nil
113
+ return target_host.to_s if ip
114
+
115
+ target_host = target_host.to_s
116
+ target_host = target_host + '.' unless target_host.end_with? '.'
117
+ end
118
+
119
+ target_host
120
+
121
+ end
122
+
123
+ end
124
+ end
125
+
126
+ Dir.glob(::File.expand_path('../records/*.rb', __FILE__)).each{|file| require file }
@@ -0,0 +1,59 @@
1
+ module DNSer
2
+ class BaseRecord < DNSer::Record
3
+ attr :ttl_val
4
+ attr :value
5
+ attr_reader :name
6
+
7
+ def initialize domain, name, *args, &block
8
+
9
+ params = {}
10
+ params = args.pop if args.last.is_a? Hash
11
+
12
+ host = domain.host
13
+ value = nil
14
+
15
+ case args.size
16
+ when 2
17
+ host = args[0]
18
+ value = args[1]
19
+ when 1
20
+ value = args[0]
21
+ else
22
+ raise DNSer::Record::EmptyValue.new(name), 'Content must be defined'
23
+ end
24
+
25
+ @name = name.to_s.upcase.to_sym
26
+ @value = value
27
+ params = {ttl: domain.ttl}.merge(params)
28
+
29
+ params.each do |key, value|
30
+ self.send "#{key}", value if self.respond_to? key
31
+ end
32
+
33
+ super domain, host, params
34
+ instance_eval &block if block_given?
35
+ end
36
+
37
+ def type
38
+ self.name
39
+ end
40
+
41
+ def value
42
+ content = if type == :TXT
43
+ '"' + @value.to_s + '"'
44
+ else
45
+ @value
46
+ end
47
+
48
+ if @priority_val == 0
49
+ content
50
+ else
51
+ "#{@priority_val} #{content}"
52
+ end
53
+ end
54
+
55
+ def ttl v
56
+ @ttl_val = v
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,44 @@
1
+ module DNSer
2
+ class SoaRecord < DNSer::Record
3
+ def initialize domain, host, params = {}, &block
4
+
5
+ [:minimum, :nameserver, :email, :serial, :refresh, :retry, :expire].each do |m|
6
+ instance_variable_set("@#{m}".to_sym, nil)
7
+ self.class.send :define_method, m, proc { |*args|
8
+ instance_variable_set("@#{m}", args.first) unless args.empty?
9
+ instance_variable_get("@#{m}")
10
+ }
11
+ end
12
+
13
+ params = {minimum: domain.ttl, refresh: domain.ttl, retry: domain.ttl, expire: domain.ttl, serial: Time.now.strftime("%Y%m%d%H%M")}.merge(params)
14
+
15
+ params.each do |key, value|
16
+ self.send key, value if self.respond_to? key
17
+ end
18
+
19
+ super domain, host, params
20
+ instance_eval &block if block_given?
21
+
22
+ raise DNSer::Record::EmptyValue.new(self), 'Email must be defined' unless @email
23
+ raise DNSer::Record::EmptyValue.new(self), 'Email must be defined' unless @nameserver
24
+ end
25
+
26
+ def host
27
+ @host.to_s
28
+ end
29
+
30
+ def type
31
+ :SOA
32
+ end
33
+
34
+ def value
35
+ ns = @nameserver.to_s
36
+ if @nameserver.is_a?(DNSer::Record)
37
+ ns = @nameserver.full_host.to_s
38
+ end
39
+ em = @email.to_s.gsub('@', '.')
40
+ em = em + '.' unless em.end_with?('.')
41
+ [ns, em, @serial, @refresh, @retry, @expire, @ttl].join(' ')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,56 @@
1
+ require ::File.expand_path('../base.rb', __FILE__)
2
+
3
+ module DNSer
4
+ class SrvRecord < DNSer::BaseRecord
5
+ def initialize domain, *args, &block
6
+
7
+ params = {}
8
+ params = args.pop if args.last.is_a? Hash
9
+
10
+ host = domain.host
11
+ value = nil
12
+
13
+ [:port, :weight, :protocol, :service].each do |m|
14
+ instance_variable_set("@#{m}".to_sym, nil)
15
+ self.class.send :define_method, m, proc { |*args|
16
+ instance_variable_set("@#{m}", args.first) unless args.empty?
17
+ instance_variable_get("@#{m}")
18
+ }
19
+ end
20
+
21
+ params = {weight: 0, priority: 0, port: 0}.merge(params)
22
+
23
+ params.each do |key, value|
24
+ self.send key, value if self.respond_to? key
25
+ end
26
+
27
+ super domain, :SRV, *args, &block
28
+
29
+ raise DNSer::Record::EmptyValue.new(self), 'Service must be defined' unless @service
30
+ raise DNSer::Record::EmptyValue.new(self), 'Protocol must be defined' unless @protocol
31
+ raise DNSer::Record::EmptyValue.new(self), 'Port must be defined' if @port == 0
32
+ end
33
+
34
+ def host
35
+ first_part = [@service, @protocol].map(&:to_s).map {|i| i.start_with?('_') ? i : ('_' + i)} .join('.')
36
+
37
+ short_host = collapse_domain @host
38
+ if(short_host == '@')
39
+ [first_part, domain.name ]
40
+ else
41
+ [first_part, short_host, domain.name]
42
+ end .join('.')
43
+
44
+ end
45
+
46
+ def value
47
+ res = super.split(' ')
48
+ case res.size
49
+ when 1
50
+ ['0', @weight, @port, res.first ]
51
+ when 2
52
+ [res.first, @weight, @port, res.last ]
53
+ end .map(&:to_s).join(' ')
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,25 @@
1
+ module DNSer
2
+ class Template
3
+ def initialize(params = {}, &block)
4
+ @block = block
5
+ @params = params
6
+ end
7
+
8
+ def apply(domain, *args, &block)
9
+ if args.last.is_a? Hash
10
+ args.push @params.merge(args.pop)
11
+ else
12
+ args.push @params
13
+ end
14
+ domain.instance_exec *args, &@block if @block
15
+ domain.instance_exec *args, &block if block
16
+ end
17
+
18
+ class Unknown < RuntimeError
19
+ attr_reader :name
20
+ def initialize name
21
+ @name = name
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module DNSer
2
+ VERSION = '0.0.3'
3
+ end
@@ -0,0 +1,149 @@
1
+ require "rspec"
2
+ require ::File.expand_path('../../lib/dnser.rb', __FILE__)
3
+
4
+ describe DNSer::Record do
5
+
6
+ def test_zone &block
7
+ io = StringIO.new
8
+ zone = DNSer.domain 'domain.ltd', builder: io, &block
9
+ [zone, io]
10
+ end
11
+
12
+ context 'for Base record' do
13
+ it "should create base record" do
14
+
15
+ zone, io = test_zone
16
+ expect( DNSer::BaseRecord.new(zone, :A, '1.1.1.1') ).to be_a(DNSer::BaseRecord)
17
+
18
+ end
19
+
20
+ it "should return correct type" do
21
+ zone, io = test_zone
22
+ expect( DNSer::BaseRecord.new(zone, :A, '1.1.1.1').type ).to eq(:A)
23
+ end
24
+
25
+ it "should return correct value" do
26
+ zone, io = test_zone
27
+ expect( DNSer::BaseRecord.new(zone, :A, '1.1.1.1').value ).to eq('1.1.1.1')
28
+ end
29
+
30
+ it "should return correct priority" do
31
+ zone, io = test_zone
32
+ expect( DNSer::BaseRecord.new(zone, :A, '1.1.1.1', priority: 1).value ).to eq('1 1.1.1.1')
33
+ end
34
+
35
+ it "should return correct host" do
36
+ zone, io = test_zone
37
+ expect( DNSer::BaseRecord.new(zone, :A, zone.host, '1.1.1.1').host ).to eq('@')
38
+ end
39
+
40
+ it "should return correct canonical host" do
41
+ zone, io = test_zone
42
+ expect( DNSer::BaseRecord.new(zone, :A, zone.host, '1.1.1.1').full_host ).to eq(zone.host)
43
+ end
44
+
45
+ it "should return correct priority" do
46
+ zone, io = test_zone
47
+ expect( DNSer::BaseRecord.new(zone, :A, zone.host, '1.1.1.1', priority: 10).priority ).to eq(10)
48
+ end
49
+
50
+ it "should wrap value if TXT record" do
51
+ zone, io = test_zone
52
+ expect( DNSer::BaseRecord.new(zone, :TXT, zone.host, 'value', priority: 10).value ).to eq('10 "value"')
53
+ end
54
+
55
+ it "should support IPAddr as value" do
56
+ zone, io = test_zone
57
+ ip = IPAddr.new('1.1.1.1')
58
+ expect( DNSer::BaseRecord.new(zone, :A, zone.host, ip).value ).to eq(ip.to_s)
59
+ end
60
+
61
+ it "should support another record as value" do
62
+ zone, io = test_zone
63
+ ip = IPAddr.new('1.1.1.1')
64
+ record = DNSer::BaseRecord.new(zone, :A, zone.host, ip)
65
+ expect( DNSer::BaseRecord.new(zone, :CNAME, 'www', record).value ).to eq(record)
66
+ end
67
+
68
+ end
69
+
70
+ context 'for SOA record' do
71
+ it "should create" do
72
+ zone, io = test_zone
73
+ expect( DNSer::SoaRecord.new(zone, zone.name, email: 'user@test.ltd', nameserver: '1.1.1.1') ).to be_a(DNSer::SoaRecord)
74
+ end
75
+
76
+ it "should return correct type" do
77
+ zone, io = test_zone
78
+ expect( DNSer::SoaRecord.new(zone, zone.name, email: 'user@test.ltd', nameserver: '1.1.1.1').type ).to eq(:SOA)
79
+ end
80
+
81
+ it "should validate email " do
82
+ zone, io = test_zone
83
+ expect{ DNSer::SoaRecord.new(zone, zone.name, nameserver: '1.1.1.1') }.to raise_error(DNSer::Record::EmptyValue)
84
+ end
85
+
86
+ it "should validate nameserver " do
87
+ zone, io = test_zone
88
+ expect{ DNSer::SoaRecord.new(zone, zone.name, email: 'user@test.ltd') }.to raise_error(DNSer::Record::EmptyValue)
89
+ end
90
+
91
+ it "should return correct email" do
92
+ zone, io = test_zone
93
+ expect( DNSer::SoaRecord.new(zone, zone.name, email: 'user@test.ltd', nameserver: '1.1.1.1').email ).to eq('user@test.ltd')
94
+ end
95
+
96
+ it "should return correct nameserver" do
97
+ zone, io = test_zone
98
+ expect( DNSer::SoaRecord.new(zone, zone.name, email: 'user@test.ltd', nameserver: '1.1.1.1').nameserver ).to eq('1.1.1.1')
99
+ end
100
+
101
+ it "should return correct value" do
102
+ zone, io = test_zone
103
+ expect( DNSer::SoaRecord.new(zone, zone.name, email: 'admin@domain.ltd', nameserver: 'ns1.domain.ltd.', serial: 100).value ).to eq('ns1.domain.ltd. admin.domain.ltd. 100 3600 3600 3600 3600')
104
+ end
105
+
106
+ it "should return correct host" do
107
+ zone, io = test_zone
108
+ expect( DNSer::SoaRecord.new(zone, zone.name, email: 'admin@domain.ltd', nameserver: 'ns1.domain.ltd.', serial: 100).host ).to eq(zone.host)
109
+ end
110
+ end
111
+
112
+ context 'for SRV record' do
113
+ it "should create " do
114
+ zone, io = test_zone
115
+ expect( DNSer::SrvRecord.new(zone, 'dev', '1.1.1.1', service: 'test', protocol: 'tcp', port: 80) ).to be_a(DNSer::BaseRecord)
116
+ end
117
+
118
+ it "should validate service " do
119
+ zone, io = test_zone
120
+ expect{ DNSer::SrvRecord.new(zone, 'dev', '1.1.1.1', protocol: 'tcp', port: 80) }.to raise_error(DNSer::Record::EmptyValue)
121
+ end
122
+
123
+ it "should validate protocol" do
124
+ zone, io = test_zone
125
+ expect{ DNSer::SrvRecord.new(zone, 'dev', '1.1.1.1', service: 'test', port: 80) }.to raise_error(DNSer::Record::EmptyValue)
126
+ end
127
+
128
+ it "should validate port " do
129
+ zone, io = test_zone
130
+ expect{ DNSer::SrvRecord.new(zone, 'dev', '1.1.1.1', service: 'test', protocol: 'tcp') }.to raise_error(DNSer::Record::EmptyValue)
131
+ end
132
+
133
+ it "should return correct value" do
134
+ zone, io = test_zone
135
+ expect( DNSer::SrvRecord.new(zone, 'dev', '1.1.1.1', service: 'test', protocol: 'tcp', port: 80, weight: 100, priority: 1).value ).to eq('1 100 80 1.1.1.1')
136
+ end
137
+
138
+ it "should return support host" do
139
+ zone, io = test_zone
140
+ expect( DNSer::SrvRecord.new(zone, 'dev', '1.1.1.1', service: 'test', protocol: 'tcp', port: 80, weight: 100, priority: 1).host ).to eq("_test._tcp.dev.#{zone.host}")
141
+ end
142
+
143
+ it "should support weight" do
144
+ zone, io = test_zone
145
+ expect( DNSer::SrvRecord.new(zone, 'dev', '1.1.1.1', service: 'test', protocol: 'tcp', port: 80, weight: 100, priority: 1) ).to respond_to('weight')
146
+ end
147
+ end
148
+
149
+ end
@@ -0,0 +1,20 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+
9
+ RSpec.configure do |config|
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+
14
+ # Run specs in random order to surface order dependencies. If you find an
15
+ # order dependency and want to debug it, you can fix the order by providing
16
+ # the seed, which is printed after each run.
17
+ # --seed 1234
18
+ config.order = 'random'
19
+
20
+ end
@@ -0,0 +1,70 @@
1
+ require "rspec"
2
+ require ::File.expand_path('../../lib/dnser.rb', __FILE__)
3
+
4
+ describe DNSer::Template do
5
+
6
+ def test_zone &block
7
+ io = StringIO.new
8
+ zone = DNSer.domain 'domain.ltd', builder: io, &block
9
+ [zone, io]
10
+ end
11
+
12
+ it "should create template" do
13
+ expect( DNSer::create_template(:empty) ).to be_a(DNSer::Template )
14
+ end
15
+
16
+ it "should be available" do
17
+ expect(DNSer::apply_template(:empty)).to be_a(DNSer::Template)
18
+ end
19
+
20
+ it "should be throw error on unknown template" do
21
+ expect { DNSer::apply_template :other }.to raise_error(DNSer::Template::Unknown)
22
+ end
23
+
24
+ it 'should apply template for zone' do
25
+
26
+ DNSer::create_template(:first) do
27
+ A host, '1.1.1.1'
28
+ end
29
+ zone, io = test_zone do
30
+ apply_first
31
+ end
32
+
33
+ expect(io.string).to include('IN A')
34
+ end
35
+
36
+ it 'should arguments params' do
37
+ DNSer::create_template(:first) do |arg|
38
+ A host, arg
39
+ end
40
+
41
+ zone, io = test_zone do
42
+ apply_first 'test.com.'
43
+ end
44
+
45
+ expect(io.string).to include('test.com.')
46
+ end
47
+
48
+ it 'should support default params' do
49
+
50
+ DNSer::create_template(:first, host: 'sub', target: 'domain.ltd.') do |arg, params|
51
+ A params[:host], params[:target]
52
+ end
53
+
54
+ zone, io = test_zone do
55
+ apply_first 'test.com.'
56
+ end
57
+
58
+ expect(io.string).to include('sub')
59
+ expect(io.string).to include('domain.ltd.')
60
+ end
61
+
62
+ it 'should apply with params' do
63
+
64
+ zone, io = test_zone do
65
+ apply_first 'test.com.', target: 'foo.ltd.'
66
+ end
67
+
68
+ expect(io.string).to include('foo.ltd.')
69
+ end
70
+ end
@@ -0,0 +1,47 @@
1
+ require "rspec"
2
+ require ::File.expand_path('../../lib/dnser.rb', __FILE__)
3
+
4
+ describe DNSer::Domain do
5
+
6
+ it "should create zone w block" do
7
+ io = StringIO.new
8
+ zone = DNSer.domain 'domain.ltd', builder: io do
9
+
10
+ end
11
+
12
+ expect( zone ).to be_a(DNSer::Domain)
13
+ end
14
+
15
+ it "should create zone w/o block" do
16
+ io = StringIO.new
17
+ expect( DNSer.domain('domain.ltd', builder: io) ).to be_a(DNSer::Domain)
18
+ end
19
+
20
+ it "should create zone with name" do
21
+ io = StringIO.new
22
+ zone = DNSer.domain 'domain.ltd', builder: io
23
+ expect(zone.name).to eq('domain.ltd.')
24
+ end
25
+
26
+ it "should create zone with builder" do
27
+ io = StringIO.new
28
+ zone = DNSer.domain 'domain.ltd', builder: io
29
+
30
+ expect(zone.name).to eq('domain.ltd.')
31
+ end
32
+
33
+ it "should write in builder" do
34
+ io = StringIO.new
35
+ zone = DNSer.domain 'domain.ltd', builder: io
36
+
37
+ expect(io.string).to eq("$ORIGIN domain.ltd.\n$TTL 3600\n")
38
+ end
39
+
40
+ it "should set zone ttl" do
41
+ io = StringIO.new
42
+ zone = DNSer.domain 'domain.ltd', builder: io
43
+ zone.ttl 100
44
+ expect(zone.ttl).to eq(100)
45
+ end
46
+
47
+ end
data/test.rb ADDED
@@ -0,0 +1,41 @@
1
+ require "./lib/dnser.rb"
2
+
3
+ template :google_app do |host, code, params|
4
+
5
+ TXT host, ('google-site-verification=' + code), :comment => "Google verification code"
6
+
7
+ MX host, 'ASPMX.L.GOOGLE.COM.', priority: 1, comment: "GMail"
8
+ MX host, 'ALT1.ASPMX.L.GOOGLE.COM.', priority: 5, comment: "GMail"
9
+ MX host, 'ALT2.ASPMX.L.GOOGLE.COM.', priority: 5, comment: "GMail"
10
+ MX host, 'ASPMX2.GOOGLEMAIL.COM.', priority: 10, comment: "GMail"
11
+ MX host, 'ASPMX23.GOOGLEMAIL.COM.', priority: 10, comment: "GMail"
12
+ TXT host, 'v=spf1 include:_spf.google.com ~all', comment: "GMail SPF"
13
+
14
+ %w(mail doc).each do |sub|
15
+ CNAME [sub, host].join('.'), 'ghs.googlehosted.com.'
16
+ end
17
+ end
18
+
19
+ zone 'domain.ltd' do
20
+ ttl 3600
21
+ ns = NS 'ns1', 'ns1.dnsimple.com.'
22
+
23
+ SOA host do
24
+ nameserver ns
25
+ email 'admin@domain.ltd'
26
+ end
27
+
28
+ A IPAddr.new('127.0.0.1'), alias: :www
29
+ A :dev, IPAddr.new('127.0.0.2')
30
+
31
+ apply_google_app host, '6tTalLzrBXBO4Gy9700TAbpg2QTKzGYEuZ_Ls69jle8'
32
+
33
+ SRV 'corp', 'calendar.abc.com.' do
34
+ service '_caldavs'
35
+ protocol :tcp
36
+ port 8443
37
+ end
38
+
39
+ SRV 'calendar2.abc.com.', service: :caldavs, protocol: :tcp, port: 8443, weight: 0, priority: 1
40
+
41
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dnser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alexey Shcherbakov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Clean ruby syntax for writing DNS zone file.
31
+ email: schalexey@gmail.com
32
+ executables:
33
+ - dnser
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - LICENSE
40
+ - README.md
41
+ - bin/dnser
42
+ - dnser.gemspec
43
+ - lib/dnser.rb
44
+ - lib/dnser/builder.rb
45
+ - lib/dnser/builders/stream.rb
46
+ - lib/dnser/domain.rb
47
+ - lib/dnser/record.rb
48
+ - lib/dnser/records/base.rb
49
+ - lib/dnser/records/soa.rb
50
+ - lib/dnser/records/srv.rb
51
+ - lib/dnser/template.rb
52
+ - lib/dnser/version.rb
53
+ - spec/record_spec.rb
54
+ - spec/spec_helper.rb
55
+ - spec/template_spec.rb
56
+ - spec/zone_spec.rb
57
+ - test.rb
58
+ homepage: https://github.com/fuCtor/DNSer
59
+ licenses:
60
+ - MIT
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.23
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: DNS zone file in ruby
83
+ test_files: []