elasticdns 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.DS_Store ADDED
Binary file
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+ gem 'rake'
3
+ gem 'aws-sdk'
4
+ gem 'fileutils'
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ aws-sdk (1.7.0)
5
+ httparty (~> 0.7)
6
+ json (~> 1.4)
7
+ nokogiri (>= 1.4.4)
8
+ uuidtools (~> 2.1)
9
+ fileutils (0.7)
10
+ rmagick (>= 2.13.1)
11
+ httparty (0.9.0)
12
+ multi_json (~> 1.0)
13
+ multi_xml
14
+ json (1.7.5)
15
+ multi_json (1.3.7)
16
+ multi_xml (0.5.1)
17
+ nokogiri (1.5.5)
18
+ rake (0.9.2.2)
19
+ rmagick (2.13.1)
20
+ uuidtools (2.1.3)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ aws-sdk
27
+ fileutils
28
+ rake
data/bin/elasticdns ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'yaml'
6
+
7
+ require_relative '../lib/elasticdns'
8
+
9
+ file = __FILE__
10
+
11
+ options = {}
12
+
13
+ opt_parser = OptionParser.new do |opt|
14
+ opt.banner = "Usage: #{file} [OPTIONS]"
15
+ opt.separator ""
16
+ opt.separator "Options"
17
+
18
+ options[:config_file] = ENV['config_file']
19
+ opt.on("-c","--config_file=elasticdns.yml","Use specific config file") do |config_file|
20
+ options[:config_file] = config_file
21
+ end
22
+
23
+ options[:debug] = ENV['debug']
24
+ opt.on("-d","--debug=1","Use to debug") do |debug|
25
+ options[:debug] = debug
26
+ end
27
+
28
+ options[:ec2_access_key_id] = ENV['ec2_access_key_id']
29
+ opt.on("--ec2_access_key_id","--ec2_access_key_id=ec2_key_id","Use specific ec2_key_id") do |ec2_access_key_id|
30
+ options[:ec2_access_key_id] = ec2_access_key_id
31
+ end
32
+
33
+ options[:ec2_secret_access_key] = ENV['ec2_secret_access_key']
34
+ opt.on("--ec2_secret_access_key","--ec2_secret_access_key=secret_access_key","Use specific secret_access_key") do |ec2_secret_access_key|
35
+ options[:ec2_secret_access_key] = ec2_secret_access_key
36
+ end
37
+
38
+ options[:ec2_tag_attribute] = ENV['ec2_tag_attribute'] || "Name"
39
+ opt.on("--ec2_tag_attribute","--ec2_tag_attribute=Name","Use to specifiy which tags attribute read to detect master servers (default: Name)") do |ec2_tag_attribute|
40
+ options[:ec2_tag_attribute] = ec2_tag_attribute
41
+ end
42
+
43
+ options[:ec2_ip_attribute] = ENV['ec2_ip_attribute'] || "private_ip_address"
44
+ opt.on("--ec2_ip_attribute","--ec2_ip_attribute=Name","Use to specifiy which ip attribute read public_ip_address or private_ip_address (default: private_ip_address)") do |ec2_ip_attribute|
45
+ options[:ec2_ip_attribute] = ec2_ip_attribute
46
+ end
47
+
48
+
49
+ options[:bind9_notify_file] = ENV['bind9_notify_file']
50
+ opt.on("--bind9_notify_file","--bind9_notify_file=/etc/bind/also_notify.conf","") do |bind9_notify_file|
51
+ options[:bind9_notify_file] = bind9_notify_file
52
+ end
53
+
54
+ options[:bind9_acl_masters_file] = ENV['bind9_acl_masters_file']
55
+ opt.on("--bind9_acl_masters_file","--bind9_acl_masters_file=/etc/bind/acl_masters_file.conf","") do |bind9_acl_masters_file|
56
+ options[:bind9_acl_masters_file] = bind9_acl_masters_file
57
+ end
58
+
59
+ options[:bind9_named_conf_file] = ENV['bind9_named_conf_file']
60
+ opt.on("--bind9_named_conf_file","--bind9_named_conf_file=/data/bind/etc/named-master.conf","") do |bind9_named_conf_file|
61
+ options[:bind9_named_conf_file] = bind9_named_conf_file
62
+ end
63
+
64
+ options[:bind9_zone_files] = ENV['bind9_zone_files']
65
+ opt.on("--bind9_zone_files","--bind9_zone_files=[/data/bind/var/zone1.priv.hosts,/data/bind/var/zone2.priv.hosts]","") do |bind9_zone_files|
66
+ options[:bind9_zone_files] = bind9_zone_files
67
+ end
68
+
69
+ options[:bind9_checkconf_path] = ENV['bind9_checkconf_path']
70
+ opt.on("--bind9_checkconf_path","--bind9_checkconf_path=named-checkconf","") do |bind9_checkconf_path|
71
+ options[:bind9_checkconf_path] = bind9_checkconf_path
72
+ end
73
+
74
+ options[:bind9_checkzone_path] = ENV['bind9_checkzone_path']
75
+ opt.on("--bind9_checkzone_path","--bind9_checkzone_path=named-checkzone","") do |bind9_checkzone_path|
76
+ options[:bind9_checkzone_path] = bind9_checkzone_path
77
+ end
78
+
79
+ options[:bind9_init_cmd] = ENV['bind9_init_cmd']
80
+ opt.on("--bind9_init_file","--bind9_init_file='sudo /etc/init.d/bind9 reload'","") do |bind9_init_cmd|
81
+ options[:bind9_init_cmd] = bind9_init_cmd
82
+ end
83
+
84
+ options[:bind9_masters] = ENV['bind9_masters']
85
+ opt.on("--bind9_masters","--bind9_masters=[master1,maser2]","") do |bind9_masters|
86
+ options[:bind9_masters] = bind9_masters
87
+ end
88
+
89
+ options[:test] = ENV['test']
90
+ opt.on("-t","--test","Use to test dns propagation") do |test|
91
+ options[:test] = test
92
+ end
93
+
94
+ options[:slave] = ENV['slave'] || false
95
+ opt.on("-s","--slave=false","Use if host is slave (default: false)") do |slave|
96
+ options[:slave] = slave
97
+ end
98
+
99
+ opt.on("-h","--help","help")
100
+ end
101
+
102
+ opt_parser.parse!
103
+
104
+ Elasticdns::Generator.new(options).run
data/config.yml ADDED
@@ -0,0 +1,22 @@
1
+ debug: 1
2
+
3
+ ec2:
4
+ access_key_id: "AKIAITTVP5VOZ2UP3SCA"
5
+ secret_access_key: "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"
6
+ region: 'us-west-2'
7
+ tag_attribute: 'Name'
8
+ ip_attribute: 'private_ip_address'
9
+
10
+
11
+ bind9:
12
+ notify_file: "/etc/bind/also_notify.conf"
13
+ acl_masters_file: "/etc/bind/acl_masters_file.conf"
14
+ named_conf_file: "/data/bind/etc/named-master.conf"
15
+ zone_files:
16
+ - "/data/bind/var/zone1.priv.hosts"
17
+ init_cmd: "sudo /etc/init.d/bind9 reload"
18
+ checkconf_path: 'named-checkconf'
19
+ checkzone_path: 'named-checkzone'
20
+ masters:
21
+ - admin-01
22
+ - admin-02
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'elasticdns'
3
+ s.version = '0.0.1'
4
+ s.date = '2013-06-23'
5
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
6
+ s.summary = "Elasticdns, a simple bind9 configurator"
7
+ s.description = "Elasticdns, a simple bind9 configurator"
8
+ s.authors = ["Gabriel Klein"]
9
+ s.email = 'gabriel.klein.fr@gmail.com'
10
+ s.files = `git ls-files`.split("\n")
11
+ s.require_paths = ["lib"]
12
+ s.homepage = 'http://github.com/GabKlein/elasticdns'
13
+ s.add_dependency('fileutils')
14
+ s.add_dependency('aws-sdk')
15
+ end
data/lib/config.rb ADDED
@@ -0,0 +1,47 @@
1
+ module Elasticdns
2
+ class Config
3
+ attr_accessor :ec2_access_key_id, :ec2_secret_access_key, :ec2_attribute, :bind9_notify_file, :bind9_acl_masters_file, :bind9_named_conf_file, :bind9_zone_files, :bind9_checkconf_path, :bind9_checkzone_path, :bind9_init_cmd, :bind9_masters
4
+
5
+ def initialize(options={})
6
+ @config_from_file = from_file(options[:config_file])
7
+
8
+ @test = options[:test]
9
+ @slave =options[:slave]
10
+
11
+ @debug = options[:debug] || (@config_from_file['debug'] if @config_from_file)
12
+
13
+ @ec2_access_key_id = options[:ec2_access_key_id] || (@config_from_file['ec2']['access_key_id'] if @config_from_file)
14
+ @ec2_secret_access_key = options[:ec2_secret_access_key] || (@config_from_file['ec2']['secret_access_key'] if @config_from_file)
15
+ @ec2_region = options[:ec2_region] || (@config_from_file['ec2']['region'] if @config_from_file)
16
+ @ec2_tag_attribute = options[:ec2_tag_attribute] || (@config_from_file['ec2']['tag_attribute'] if @config_from_file)
17
+ @ec2_ip_attribute = options[:ec2_ip_attribute] || (@config_from_file['ec2']['ip_attribute'] if @config_from_file)
18
+
19
+ @bind9_notify_file = options[:bind9_notify_file] || (@config_from_file['bind9']['notify_file'] if @config_from_file)
20
+ @bind9_acl_masters_file = options[:bind9_acl_masters_file] || (@config_from_file['bind9']['acl_masters_file'] if @config_from_file)
21
+ @bind9_named_conf_file = options[:bind9_named_conf_file] || (@config_from_file['bind9']['named_conf_file'] if @config_from_file)
22
+ @bind9_zone_files = split(options[:bind9_zone_files]) || (@config_from_file['bind9']['zone_files'] if @config_from_file)
23
+ @bind9_checkconf_path = options[:bind9_checkconf_path] || (@config_from_file['bind9']['checkconf_path'] if @config_from_file)
24
+ @bind9_checkzone_path = options[:bind9_checkzone_path] || (@config_from_file['bind9']['checkzone_path'] if @config_from_file)
25
+ @bind9_init_cmd = options[:bind9_init_cmd] || (@config_from_file['bind9']['init_cmd'] if @config_from_file)
26
+ @bind9_masters = split(options[:bind9_masters]) || (@config_from_file['bind9']['masters'] if @config_from_file)
27
+ end
28
+
29
+ def split(param)
30
+ if param
31
+ param.split(',')
32
+ end
33
+ end
34
+
35
+ def to_hash
36
+ hash = {}
37
+ self.instance_variables.each {|var| hash[var.to_s.delete("@").to_sym] = self.instance_variable_get(var) }
38
+ return hash
39
+ end
40
+
41
+ def from_file(config_file)
42
+ if config_file && File.exists?(config_file)
43
+ YAML.load_file(config_file)
44
+ end
45
+ end
46
+ end
47
+ end
data/lib/elasticdns.rb ADDED
@@ -0,0 +1,166 @@
1
+ require 'yaml'
2
+ require 'aws-sdk'
3
+ require 'tempfile'
4
+ require 'fileutils'
5
+ require 'digest/md5'
6
+ require 'pp'
7
+ require_relative 'config'
8
+
9
+ module Elasticdns
10
+ class Generator
11
+ def initialize(options={})
12
+ @config = Elasticdns::Config.new(options).to_hash
13
+ end
14
+
15
+ def run
16
+ pp @config if @config[:debug]
17
+ if @config[:slave] == 'true'
18
+ update_acl_masters_file
19
+ else
20
+ update_notify_file
21
+ end
22
+ end
23
+
24
+ def ec2init
25
+ AWS.memoize do
26
+ AWS::EC2.new(:access_key_id => @config[:ec2_access_key_id], :secret_access_key => @config[:ec2_secret_access_key], :region => @config[:ec2_region])
27
+ end
28
+ end
29
+
30
+ def closefile(file)
31
+ file.close
32
+ file.unlink
33
+ end
34
+
35
+ def md5(string)
36
+ md5 = Digest::MD5.hexdigest(string)
37
+ end
38
+
39
+ def md5chk(orig_file, new_md5)
40
+ File.open(orig_file, 'r') do |file|
41
+ file.each_line do |line|
42
+ if line =~ /### MD5:/
43
+ old_md5 = line.split(':')[1]
44
+ if old_md5 =~ /#{new_md5}/
45
+ return new_md5
46
+ end
47
+ end
48
+ end
49
+ end if File.exists?(orig_file)
50
+ return false
51
+ end
52
+
53
+ def updatefile(ips, new_md5, temp_file, orig_file, prefix)
54
+ puts "Updating #{orig_file}"
55
+ md5 = "### MD5:#{new_md5}\n"
56
+ line = "#{prefix} { #{ips.to_s.gsub(/\[|\]|"/, '').gsub(/,/, ';')}; };\n"
57
+ temp_file.write(md5)
58
+ temp_file.write(line)
59
+ temp_file.rewind
60
+ FileUtils.mv(temp_file.path, orig_file)
61
+ return line
62
+ end
63
+
64
+ def bind_checkconf
65
+ `#{@config[:bind9_checkconf_path]} #{@config[:bind9_named_conf_file]}`
66
+ end
67
+
68
+ def bind_checkzone
69
+ @config[:bind9_zone_files].each do |zone|
70
+ `#{@config[:bind9_checkzone_path]} #{zone}`
71
+ end
72
+ end
73
+
74
+ def bind_init_cmd
75
+ if bind_checkconf && bind_checkzone
76
+ `#{@config[:bind9_init_cmd]}`
77
+ end
78
+ end
79
+
80
+ def update_hosts_file
81
+ orig_file = '/etc/hosts'
82
+ temp_file = Tempfile.new('hosts')
83
+ begin
84
+ ec2 = ec2init
85
+ File.open(orig_file, 'r') do |file|
86
+ file.each_line do |line|
87
+ unless line =~ /### EC2 HOSTS/
88
+ temp_file.write("#{line}")
89
+ end
90
+ end
91
+ end
92
+ ec2.instances.each do |i|
93
+ if i.status == :running
94
+ if i.tags[@config[:ec2_tag_attribute]]
95
+ temp_file.write("#{i.private_ip_address}\t#{i.tags[@config[:ec2_tag_attribute]]}\t### EC2 HOSTS\n")
96
+ end
97
+ end
98
+ end
99
+ temp_file.rewind
100
+ FileUtils.mv(temp_file.path, orig_file)
101
+ ensure
102
+ temp_file.close
103
+ temp_file.unlink
104
+ end
105
+ end
106
+
107
+ def update_notify_file
108
+ # File dedicated to master servers
109
+ orig_file = @config[:bind9_notify_file]
110
+ temp_file = Tempfile.new('also-notify')
111
+ prefix = "also-notify"
112
+ begin
113
+ ec2 = ec2init
114
+ ips = []
115
+ ec2.instances.each do |i|
116
+ if i.status == :running
117
+ ips << i.send(@config[:ec2_ip_attribute])
118
+ #unless @config[:bind9_masters].include?(i.tags[@config[:ec2_tag_attribute]])
119
+ end
120
+ end
121
+ write_to_file(ips, orig_file, temp_file, prefix)
122
+ ensure
123
+ temp_file.close
124
+ temp_file.unlink
125
+ end
126
+ end
127
+
128
+ def update_acl_masters_file
129
+ # File dedicated to slave servers
130
+ orig_file = @config[:bind9_acl_masters_file]
131
+ temp_file = Tempfile.new('acl_masters_file')
132
+ prefix = "acl 'masters'"
133
+ begin
134
+ ec2 = ec2init
135
+ ips = []
136
+ ec2.instances.each do |i|
137
+ meta_name = i.tags[@config[:ec2_tag_attribute]]
138
+ if i.status == :running
139
+ @config[:bind9_masters].each do |master|
140
+ if meta_name == master
141
+ ips << i.send(@config[:ec2_ip_attribute])
142
+ end
143
+ end
144
+ end
145
+ end
146
+ write_to_file(ips, orig_file, temp_file, prefix)
147
+ ensure
148
+ closefile(temp_file)
149
+ end
150
+ end
151
+
152
+ def write_to_file(ips, orig_file, temp_file, prefix)
153
+ if ips[0]
154
+ unless md5chk(orig_file, md5(ips.to_s))
155
+ update = updatefile(ips, md5(ips.to_s), temp_file, orig_file, prefix)
156
+ bind_init_cmd
157
+ puts "#{orig_file} updated with: " + update
158
+ else
159
+ puts "nothing changed in #{orig_file}: " + md5(ips.to_s)
160
+ end
161
+ else
162
+ puts 'No master found'
163
+ end
164
+ end
165
+ end
166
+ end
data/rakefile.rb ADDED
@@ -0,0 +1,90 @@
1
+ require './lib/ec2_dns.rb'
2
+
3
+ task :update_hosts_file do
4
+ orig_file = '/etc/hosts'
5
+ temp_file = Tempfile.new('hosts')
6
+ begin
7
+ ec2 = ec2init
8
+ File.open(orig_file, 'r') do |file|
9
+ file.each_line do |line|
10
+ unless line =~ /### EC2 HOSTS/
11
+ temp_file.write("#{line}")
12
+ end
13
+ end
14
+ end
15
+ ec2.instances.each do |i|
16
+ if i.status == :running
17
+ if i.tags[:meta_name]
18
+ temp_file.write("#{i.private_ip_address}\t#{i.tags[:meta_name]}\t### EC2 HOSTS\n")
19
+ end
20
+ end
21
+ end
22
+ temp_file.rewind
23
+ FileUtils.mv(temp_file.path, orig_file)
24
+ ensure
25
+ temp_file.close
26
+ temp_file.unlink
27
+ end
28
+ end
29
+
30
+ task :update_notify_file do
31
+ orig_file = @cnf['bind9']['notify_file']
32
+ temp_file = Tempfile.new('also-notify')
33
+ prefix = "also-notify"
34
+ begin
35
+ ec2 = ec2init
36
+ ips = []
37
+ ec2.instances.each do |i|
38
+ if i.status == :running
39
+ ips << i.private_ip_address
40
+ end
41
+ end
42
+ if ips[0]
43
+ unless md5chk(orig_file, md5(ips.to_s))
44
+ update = updatefile(ips, md5(ips.to_s), temp_file, orig_file, prefix)
45
+ bind_reload
46
+ puts 'update with: ' + update
47
+ else
48
+ puts 'nothing changed: ' + md5(ips.to_s)
49
+ end
50
+ else
51
+ puts 'no master'
52
+ end
53
+ ensure
54
+ temp_file.close
55
+ temp_file.unlink
56
+ end
57
+ end
58
+
59
+ task :update_acl_masters_file do
60
+ orig_file = @cnf['bind9']['acl_masters_file']
61
+ temp_file = Tempfile.new('acl_masters_file')
62
+ prefix = "acl 'masters'"
63
+ begin
64
+ ec2 = ec2init
65
+ ips = []
66
+ ec2.instances.each do |i|
67
+ meta_name = i.tags[@cnf['ec2']['meta_tag_name']]
68
+ if i.status == :running
69
+ @cnf['bind9']['masters'].each do |master|
70
+ if meta_name == master
71
+ ips << i.private_ip_address
72
+ end
73
+ end
74
+ end
75
+ end
76
+ if ips[0]
77
+ unless md5chk(orig_file, md5(ips.to_s))
78
+ update = updatefile(ips, md5(ips.to_s), temp_file, orig_file, prefix)
79
+ bind_reload
80
+ puts 'update with: ' + update
81
+ else
82
+ puts 'nothing changed: ' + md5(ips.to_s)
83
+ end
84
+ else
85
+ puts 'no master'
86
+ end
87
+ ensure
88
+ closefile(temp_file)
89
+ end
90
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elasticdns
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Gabriel Klein
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2013-06-23 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: fileutils
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: aws-sdk
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ description: Elasticdns, a simple bind9 configurator
45
+ email: gabriel.klein.fr@gmail.com
46
+ executables:
47
+ - elasticdns
48
+ extensions: []
49
+
50
+ extra_rdoc_files: []
51
+
52
+ files:
53
+ - .DS_Store
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - bin/elasticdns
57
+ - config.yml
58
+ - elasticdns.gemspec
59
+ - lib/config.rb
60
+ - lib/elasticdns.rb
61
+ - rakefile.rb
62
+ has_rdoc: true
63
+ homepage: http://github.com/GabKlein/elasticdns
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.6
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Elasticdns, a simple bind9 configurator
92
+ test_files: []
93
+