dnser 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/LICENSE +20 -0
- data/README.md +69 -0
- data/bin/dnser +35 -0
- data/dnser.gemspec +22 -0
- data/lib/dnser.rb +52 -0
- data/lib/dnser/builder.rb +20 -0
- data/lib/dnser/builders/stream.rb +66 -0
- data/lib/dnser/domain.rb +92 -0
- data/lib/dnser/record.rb +126 -0
- data/lib/dnser/records/base.rb +59 -0
- data/lib/dnser/records/soa.rb +44 -0
- data/lib/dnser/records/srv.rb +56 -0
- data/lib/dnser/template.rb +25 -0
- data/lib/dnser/version.rb +3 -0
- data/spec/record_spec.rb +149 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/template_spec.rb +70 -0
- data/spec/zone_spec.rb +47 -0
- data/test.rb +41 -0
- metadata +83 -0
data/.gitignore
ADDED
data/.rspec
ADDED
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.
|
data/README.md
ADDED
@@ -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.
|
data/bin/dnser
ADDED
@@ -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
|
data/dnser.gemspec
ADDED
@@ -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
|
data/lib/dnser.rb
ADDED
@@ -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
|
data/lib/dnser/domain.rb
ADDED
@@ -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
|
data/lib/dnser/record.rb
ADDED
@@ -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
|
data/spec/record_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
data/spec/zone_spec.rb
ADDED
@@ -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: []
|