elasticdns 0.0.1

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.
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
+