roadworker 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.
@@ -0,0 +1,69 @@
1
+ # Roadworker
2
+
3
+ Roadworker is a tool to manage Route53.
4
+
5
+ It defines the state of Route53 using DSL, and updates Route53 according to DSL.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'roadworker'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install roadworker
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ shell> export AWS_ACCESS_KEY_ID='...'
25
+ shell> export AWS_SECRET_ACCESS_KEY='...'
26
+ shell> roadwork -e -o Routefile
27
+ shell> vi Routefile
28
+ shell> roadwork --dry-run
29
+ shell> roudwork
30
+ ```
31
+
32
+ ## Routefile esample
33
+
34
+ ```ruby
35
+ require 'other/routefile'
36
+
37
+ hosted_zone "winebarrel.jp." do
38
+ rrset "winebarrel.jp.", "MX" do
39
+ ttl 300
40
+ resource_records(
41
+ "10 mx.winebarrel.jp",
42
+ "10 mx2.winebarrel.jp"
43
+ )
44
+ end
45
+
46
+ rrset "winebarrel.jp.", "NS" do
47
+ ttl 86400
48
+ resource_records(
49
+ "ns-XXX.awsdns-XX.com.",
50
+ "ns-XXX.awsdns-XX.org.",
51
+ "ns-XXX.awsdns-XX.net.",
52
+ "ns-XXX.awsdns-XX.co.uk."
53
+ )
54
+ end
55
+
56
+ rrset "winebarrel.jp.", "SOA" do
57
+ ttl 86400
58
+ resource_records(
59
+ "ns-XXX.awsdns-XX.com. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
60
+ )
61
+ end
62
+ end
63
+
64
+ hosted_zone "info.winebarrel.jp." do
65
+ rrset "xxx.info.winebarrel.jp.", "A" do
66
+ dns_name "elb-dns-name.elb.amazonaws.com"
67
+ end
68
+ end
69
+ ```
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("#{File.dirname __FILE__}/../lib")
3
+ require 'rubygems'
4
+ require 'roadworker'
5
+ require 'optparse'
6
+ require 'logger'
7
+
8
+ file = 'Routefile'
9
+ output_file = '-'
10
+ export_mode = false
11
+ logger = Logger.new($stdout)
12
+
13
+ logger.formatter = proc {|severity, datetime, progname, msg|
14
+ "#{msg}\n"
15
+ }
16
+ options = {
17
+ :logger => logger,
18
+ :dry_run => false,
19
+ :debug => false,
20
+ :force => false,
21
+ :color => true,
22
+ }
23
+
24
+ ARGV.options do |opt|
25
+ access_key = nil
26
+ secret_key = nil
27
+
28
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
29
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
30
+ opt.on('-f', '--file FILE') {|v| file = v }
31
+ opt.on('-e', '--export') {|v| export_mode = true }
32
+ opt.on('-o', '--output FILE') {|v| output_file = v }
33
+ opt.on('', '--dry-run') {|v| options[:dry_run] = true }
34
+ opt.on('' , '--force') { options[:force] = true }
35
+ opt.on('' , '--no-color') { options[:color] = false }
36
+ opt.on('' , '--debug') { options[:debug] = true }
37
+ opt.parse!
38
+
39
+ if access_key and secret_key
40
+ AWS.config({
41
+ :access_key_id => access_key,
42
+ :secret_access_key => secret_key,
43
+ })
44
+ elsif (access_key and !secret_key) or (!access_key and secret_key)
45
+ puts opt.help
46
+ exit 1
47
+ end
48
+ end
49
+
50
+ if options[:debug]
51
+ AWS.config(
52
+ :http_wire_trace => true,
53
+ :logger => options[:logger]
54
+ )
55
+ end
56
+
57
+ begin
58
+ client = Roadworker::Client.new(options)
59
+
60
+ if export_mode
61
+ exported = client.export
62
+
63
+ if output_file == '-'
64
+ logger.info('Export Route53')
65
+ puts client.export
66
+ else
67
+ logger.info("Export Route53 to `#{output_file}`")
68
+ open(output_file, 'wb') {|f| f.puts client.export }
69
+ end
70
+ else
71
+ unless File.exist?(file)
72
+ raise "No Routefile found (looking for: #{file})"
73
+ end
74
+
75
+ msg = "Apply `#{file}` to Route53"
76
+ msg << ' (dry-run)' if options[:dry_run]
77
+ logger.info(msg)
78
+
79
+ updated = client.apply(file)
80
+
81
+ logger.info('There is no update') unless updated
82
+ end
83
+ rescue => e
84
+ if options[:debug]
85
+ raise e
86
+ else
87
+ $stderr.puts e
88
+ end
89
+ end
@@ -0,0 +1,2 @@
1
+ require 'roadworker/version'
2
+ require 'roadworker/client'
@@ -0,0 +1,109 @@
1
+ require 'roadworker/string-ext'
2
+ require 'roadworker/dsl'
3
+ require 'roadworker/log'
4
+ require 'roadworker/route53-wrapper'
5
+
6
+ require 'logger'
7
+ require 'ostruct'
8
+
9
+ module Roadworker
10
+ class Client
11
+ include Roadworker::Log
12
+
13
+ def initialize(options)
14
+ @options = OpenStruct.new(options)
15
+ @options.logger ||= Logger.new($stdout)
16
+ String.colorize = @options.color
17
+ @options.route53 = AWS::Route53.new
18
+ @route53 = Route53Wrapper.new(@options)
19
+ end
20
+
21
+ def apply(file)
22
+ dsl = nil
23
+
24
+ if file.kind_of?(String)
25
+ open(file) do |f|
26
+ dsl = DSL.define(f.read, file).result
27
+ end
28
+ else
29
+ dsl = DSL.define(file.read, file.path).result
30
+ end
31
+
32
+ updated = false
33
+
34
+ if dsl.hosted_zones.empty? and not @options.force
35
+ log(:warn, "Nothing is defined (pass `--force` if you want to remove)", :yellow)
36
+ else
37
+ AWS.memoize {
38
+ walk_hosted_zones(dsl)
39
+ updated = @options.updated
40
+ }
41
+ end
42
+
43
+ return updated
44
+ end
45
+
46
+ def export
47
+ exported = AWS.memoize { @route53.export }
48
+ DSL.convert(exported)
49
+ end
50
+
51
+ private
52
+
53
+ def walk_hosted_zones(dsl)
54
+ expected = collection_to_hash(dsl.hosted_zones, :name)
55
+ actual = collection_to_hash(@route53.hosted_zones, :name)
56
+
57
+ expected.each do |keys, expected_zone|
58
+ name = keys[0]
59
+ actual_zone = actual.delete(keys) || @route53.hosted_zones.create(name)
60
+ walk_rrsets(expected_zone, actual_zone)
61
+ end
62
+
63
+ actual.each do |keys, zone|
64
+ zone.rrsets.each do |record|
65
+ record.delete(:cascaded => true)
66
+ end
67
+
68
+ zone.delete
69
+ end
70
+ end
71
+
72
+ def walk_rrsets(expected_zone, actual_zone)
73
+ expected = collection_to_hash(expected_zone.rrsets, :name, :type, :set_identifier)
74
+ actual = collection_to_hash(actual_zone.rrsets, :name, :type, :set_identifier)
75
+
76
+ expected.each do |keys, expected_record|
77
+ name = keys[0]
78
+ type = keys[1]
79
+ set_identifier = keys[2]
80
+
81
+ actual_record = actual.delete(keys)
82
+
83
+ if actual_record
84
+ unless actual_record.eql?(expected_record)
85
+ actual_record.update(expected_record)
86
+ end
87
+ else
88
+ actual_record = actual_zone.rrsets.create(name, type, expected_record)
89
+ end
90
+ end
91
+
92
+ actual.each do |keys, record|
93
+ record.delete
94
+ end
95
+ end
96
+
97
+ def collection_to_hash(collection, *keys)
98
+ hash = {}
99
+
100
+ collection.each do |item|
101
+ key_list = keys.map {|k| item.send(k) }
102
+ hash[key_list] = item
103
+ end
104
+
105
+ return hash
106
+ end
107
+
108
+ end # Client
109
+ end # Roadworker
@@ -0,0 +1,21 @@
1
+ module Roadworker
2
+ class Collection
3
+
4
+ class << self
5
+ def batch(collection)
6
+ if collection.respond_to?(:each_batch)
7
+ collection.each_batch do |batch|
8
+ batch.each do |item|
9
+ yield(item)
10
+ end
11
+ end
12
+ else
13
+ collection.each do |item|
14
+ yield(item)
15
+ end
16
+ end
17
+ end
18
+ end # of class method
19
+
20
+ end # Collection
21
+ end # Roadworker
@@ -0,0 +1,50 @@
1
+ module Roadworker
2
+ class DSL
3
+ class Converter
4
+
5
+ class << self
6
+ def convert(hosted_zones)
7
+ hosted_zones.map {|i| output_zone(i) }.join("\n")
8
+ end
9
+
10
+ private
11
+
12
+ def output_rrset(recrod)
13
+ name = recrod.delete(:name).inspect
14
+ type = recrod.delete(:type).inspect
15
+
16
+ attrs = recrod.map {|key, value|
17
+ if value.kind_of?(Array)
18
+ if value.empty?
19
+ nil
20
+ else
21
+ value = value.map {|i| i.inspect }.join(",\n ")
22
+ "#{key}(\n #{value}\n )"
23
+ end
24
+ else
25
+ "#{key} #{value.inspect}"
26
+ end
27
+ }.select {|i| i }.join("\n ")
28
+
29
+ return(<<-EOS)
30
+ rrset #{name}, #{type} do
31
+ #{attrs}
32
+ end
33
+ EOS
34
+ end
35
+
36
+ def output_zone(zone)
37
+ name = zone[:name].inspect
38
+ rrsets = zone[:rrsets]
39
+
40
+ return(<<-EOS)
41
+ hosted_zone #{name} do
42
+ #{rrsets.map {|i| output_rrset(i) }.join("\n").chomp}
43
+ end
44
+ EOS
45
+ end
46
+ end # of class method
47
+
48
+ end # Converter
49
+ end # DSL
50
+ end # Roadworker
@@ -0,0 +1,119 @@
1
+ require 'roadworker/dsl-converter'
2
+
3
+ require 'ostruct'
4
+
5
+ module Roadworker
6
+ class DSL
7
+
8
+ class << self
9
+ def define(source, path)
10
+ self.new(path) do
11
+ eval(source, binding)
12
+ end
13
+ end
14
+
15
+ def convert(hosted_zones)
16
+ Converter.convert(hosted_zones)
17
+ end
18
+ end # of class method
19
+
20
+ attr_reader :result
21
+
22
+ def initialize(path, &block)
23
+ @path = path
24
+ @result = OpenStruct.new({:hosted_zones => []})
25
+ instance_eval(&block)
26
+ end
27
+
28
+ private
29
+
30
+ def require(file)
31
+ routefile = File.expand_path(File.join(File.dirname(@path), file))
32
+
33
+ if File.exist?(routefile)
34
+ instance_eval(File.read(routefile))
35
+ else
36
+ Kernel.require(file)
37
+ end
38
+ end
39
+
40
+ def hosted_zone(name, &block)
41
+ @result.hosted_zones << HostedZone.new(name, &block).result
42
+ end
43
+
44
+ class HostedZone
45
+ attr_reader :result
46
+
47
+ def initialize(name, &block)
48
+ @name = name
49
+ rrsets = []
50
+
51
+ @result = OpenStruct.new({
52
+ :name => name,
53
+ :resource_record_sets => rrsets,
54
+ :rrsets => rrsets,
55
+ })
56
+
57
+ instance_eval(&block)
58
+ end
59
+
60
+ private
61
+
62
+ def resource_record_set(rrset_name, type, &block)
63
+ if rrset_name.gsub(/\.\Z/, '') !~ /#{Regexp.escape(@name.gsub(/\.\Z/, ''))}\Z/i
64
+ raise "Invalid ResourceRecordSet Name: #{rrset_name}"
65
+ end
66
+
67
+ @result.resource_record_sets << ResourceRecordSet.new(rrset_name, type, &block).result
68
+ end
69
+ alias rrset resource_record_set
70
+
71
+ class ResourceRecordSet
72
+ attr_reader :result
73
+
74
+ def initialize(name, type, &block)
75
+ @result = OpenStruct.new({
76
+ :name => name,
77
+ :type => type,
78
+ })
79
+
80
+ instance_eval(&block)
81
+ end
82
+
83
+ private
84
+
85
+ def set_identifier(value = nil)
86
+ @result.set_identifier = value
87
+ end
88
+ alias identifier set_identifier
89
+
90
+ def weight(value)
91
+ @result.weight = value
92
+ end
93
+
94
+ def ttl(value)
95
+ @result.ttl = value
96
+ end
97
+
98
+ def region(value)
99
+ @result.region = value
100
+ end
101
+
102
+ def dns_name(value)
103
+ @result.dns_name = value
104
+ end
105
+
106
+ def resource_records(*values)
107
+ if values.uniq.length != values.length
108
+ raise "Duplicate ResourceRecords: #{values.join(', ')}"
109
+ end
110
+
111
+ @result.resource_records = [values].flatten.map {|i| {:value => i} }
112
+ end
113
+
114
+ end # ResourceRecordSet
115
+
116
+ end # HostedZone
117
+
118
+ end # DSL
119
+ end # RoadWorker
@@ -0,0 +1,12 @@
1
+ module Roadworker
2
+ module Log
3
+
4
+ def log(level, message, color, log_id = nil)
5
+ log_id = yield if block_given?
6
+ message = "#{message}: #{log_id}"
7
+ message << ' (dry-run)' if @options.dry_run
8
+ @options.logger.send(level, message.send(color))
9
+ end
10
+
11
+ end # Log
12
+ end # Roadworker
@@ -0,0 +1,69 @@
1
+ require 'roadworker/collection'
2
+
3
+ require 'ostruct'
4
+
5
+ module Roadworker
6
+ class Exporter
7
+
8
+ class << self
9
+ def export(route53)
10
+ self.new(route53).export
11
+ end
12
+ end # of class method
13
+
14
+ def initialize(route53)
15
+ @route53 = route53
16
+ end
17
+
18
+ def export
19
+ result = []
20
+
21
+ Collection.batch(@route53.hosted_zones) do |zone|
22
+ zone_h = item_to_hash(zone, :name)
23
+ result << zone_h
24
+
25
+ rrsets = []
26
+ zone_h[:rrsets] = rrsets
27
+
28
+ Collection.batch(zone.rrsets) do |record|
29
+ attrs = [
30
+ :name,
31
+ :type,
32
+ :set_identifier,
33
+ :weight,
34
+ :ttl,
35
+ :resource_records,
36
+ :alias_target,
37
+ :region,
38
+ ]
39
+
40
+ record_h = item_to_hash(record, *attrs)
41
+ rrsets << record_h
42
+
43
+ rrs = record_h.delete(:resource_records)
44
+ record_h[:resource_records] = rrs.map {|i| i[:value] }
45
+
46
+ if (alias_target = record_h.delete(:alias_target))
47
+ record_h[:dns_name] = alias_target[:dns_name]
48
+ end
49
+ end
50
+ end
51
+
52
+ return result
53
+ end
54
+
55
+ private
56
+
57
+ def item_to_hash(item, *attrs)
58
+ h = {}
59
+
60
+ attrs.each do |attr|
61
+ value = item.send(attr)
62
+ h[attr] = value if value
63
+ end
64
+
65
+ return h
66
+ end
67
+
68
+ end # Exporter
69
+ end # Roadworker
@@ -0,0 +1,32 @@
1
+ require 'aws-sdk'
2
+
3
+ module AWS
4
+ class Route53
5
+
6
+ def dns_name_to_alias_target(name)
7
+ name = name.gsub(/\.\Z/, '')
8
+
9
+ unless name =~ /([^.]+)\.elb\.amazonaws.com\Z/i
10
+ raise "Invalid DNS Name: #{name}"
11
+ end
12
+
13
+ region = $1.downcase
14
+ elb = AWS::ELB.new(:region => region)
15
+
16
+ load_balancer = elb.load_balancers.find do |lb|
17
+ lb.dns_name == name
18
+ end
19
+
20
+ unless load_balancer
21
+ raise "Cannot find ELB: #{name}"
22
+ end
23
+
24
+ {
25
+ :hosted_zone_id => load_balancer.canonical_hosted_zone_name_id,
26
+ :dns_name => load_balancer.dns_name,
27
+ :evaluate_target_health => false, # XXX:
28
+ }
29
+ end
30
+
31
+ end # Route53
32
+ end # Roadworker
@@ -0,0 +1,253 @@
1
+ require 'roadworker/collection'
2
+ require 'roadworker/log'
3
+ require 'roadworker/route53-exporter'
4
+ require 'roadworker/route53-ext'
5
+
6
+ require 'ostruct'
7
+
8
+ module Roadworker
9
+ class Route53Wrapper
10
+
11
+ RRSET_ATTRS = [
12
+ :set_identifier,
13
+ :weight,
14
+ :ttl,
15
+ :resource_records,
16
+ :dns_name,
17
+ :region
18
+ ]
19
+
20
+ def initialize(options)
21
+ @options = options
22
+ end
23
+
24
+ def export
25
+ Exporter.export(@options.route53)
26
+ end
27
+
28
+ def hosted_zones
29
+ HostedZoneCollectionWrapper.new(@options.route53.hosted_zones, @options)
30
+ end
31
+
32
+ class HostedZoneCollectionWrapper
33
+ include Roadworker::Log
34
+
35
+ def initialize(hosted_zones, options)
36
+ @hosted_zones = hosted_zones
37
+ @options = options
38
+ end
39
+
40
+ def each
41
+ Collection.batch(@hosted_zones) do |zone|
42
+ yield(HostedZoneWrapper.new(zone, @options))
43
+ end
44
+ end
45
+
46
+ def create(name, opts = {})
47
+ log(:info, 'Create HostedZone', :cyan, name)
48
+
49
+ if @options.dry_run
50
+ zone = OpenStruct.new({:name => name, :rrsets => []}.merge(opts))
51
+ else
52
+ zone = @hosted_zones.create(name, opts)
53
+ @options.updated = true
54
+ end
55
+
56
+ HostedZoneWrapper.new(zone, @options)
57
+ end
58
+ end # HostedZoneCollection
59
+
60
+ class HostedZoneWrapper
61
+ include Roadworker::Log
62
+
63
+ def initialize(hosted_zone, options)
64
+ @hosted_zone = hosted_zone
65
+ @options = options
66
+ end
67
+
68
+ def resource_record_sets
69
+ ResourceRecordSetCollectionWrapper.new(@hosted_zone.rrsets, @options)
70
+ end
71
+ alias rrsets resource_record_sets
72
+
73
+ def delete
74
+ if @options.force
75
+ log(:info, 'Delete HostedZone', :red, @hosted_zone.name)
76
+
77
+ unless @options.dry_run
78
+ @hosted_zone.delete
79
+ @options.updated = true
80
+ end
81
+ else
82
+ log(:info, 'Undefined HostedZone (pass `--force` if you want to remove)', :yellow, @hosted_zone.name)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def method_missing(method_name, *args)
89
+ @hosted_zone.send(method_name, *args)
90
+ end
91
+ end # HostedZoneWrapper
92
+
93
+ class ResourceRecordSetCollectionWrapper
94
+ include Roadworker::Log
95
+
96
+ def initialize(resource_record_sets, options)
97
+ @resource_record_sets = resource_record_sets
98
+ @options = options
99
+ end
100
+
101
+ def each
102
+ Collection.batch(@resource_record_sets) do |record|
103
+ yield(ResourceRecordSetWrapper.new(record, @options))
104
+ end
105
+ end
106
+
107
+ def create(name, type, expected_record)
108
+ log(:info, 'Create ResourceRecordSet', :cyan) do
109
+ log_id = [name, type].join(' ')
110
+ rrset_setid = expected_record.set_identifier
111
+ rrset_setid ? (log_id + " (#{rrset_setid})") : log_id
112
+ end
113
+
114
+ if @options.dry_run
115
+ record = expected_record
116
+ else
117
+ opts = {}
118
+
119
+ Route53Wrapper::RRSET_ATTRS.each do |attr|
120
+ value = expected_record.send(attr)
121
+ next unless value
122
+
123
+ case attr
124
+ when :dns_name
125
+ attr = :alias_target
126
+ value = @options.route53.dns_name_to_alias_target(value)
127
+ end
128
+
129
+ opts[attr] = value
130
+ end
131
+
132
+ record = @resource_record_sets.create(name, type, opts)
133
+ @options.updated = true
134
+ end
135
+
136
+ ResourceRecordSetWrapper.new(record, @options)
137
+ end
138
+ end # ResourceRecordSetCollectionWrapper
139
+
140
+ class ResourceRecordSetWrapper
141
+ include Roadworker::Log
142
+
143
+ def initialize(resource_record_set, options)
144
+ @resource_record_set = resource_record_set
145
+ @options = options
146
+ end
147
+
148
+ def eql?(expected_record)
149
+ Route53Wrapper::RRSET_ATTRS.all? do |attr|
150
+ expected = expected_record.send(attr)
151
+ expected = nil if expected.kind_of?(Array) && expected.empty?
152
+ actual = self.send(attr)
153
+ actual = nil if actual.kind_of?(Array) && actual.empty?
154
+
155
+ if !expected and !actual
156
+ true
157
+ elsif expected and actual
158
+ case attr
159
+ when :resource_records
160
+ expected = expected.sort_by {|i| i[:value] }
161
+ actual = actual.sort_by {|i| i[:value] }
162
+ end
163
+
164
+ (expected == actual)
165
+ else
166
+ false
167
+ end
168
+ end
169
+ end
170
+
171
+ def update(expected_record)
172
+ log(:info, 'Update ResourceRecordSet', :green) do
173
+ log_id = [@resource_record_set.name, @resource_record_set.type].join(' ')
174
+ rrset_setid = @resource_record_set.set_identifier
175
+ rrset_setid ? (log_id + " (#{rrset_setid})") : log_id
176
+ end
177
+
178
+ Route53Wrapper::RRSET_ATTRS.each do |attr|
179
+ expected = expected_record.send(attr)
180
+ expected = nil if expected.kind_of?(Array) && expected.empty?
181
+ actual = self.send(attr)
182
+ actual = nil if actual.kind_of?(Array) && actual.empty?
183
+
184
+ if (expected and !actual) or (!expected and actual)
185
+ log(:info, " set #{attr}=#{expected.inspect}" , :green) do
186
+ log_id = [@resource_record_set.name, @resource_record_set.type].join(' ')
187
+ rrset_setid = @resource_record_set.set_identifier
188
+ rrset_setid ? (log_id + " (#{rrset_setid})") : log_id
189
+ end
190
+
191
+ self.send(:"#{attr}=", expected) unless @options.dry_run
192
+ elsif expected and actual
193
+ case attr
194
+ when :resource_records
195
+ expected = expected.sort_by {|i| i[:value] }
196
+ actual = actual.sort_by {|i| i[:value] }
197
+ end
198
+
199
+ if expected != actual
200
+ log(:info, " set #{attr}=#{expected.inspect}" , :green) do
201
+ log_id = [@resource_record_set.name, @resource_record_set.type].join(' ')
202
+ rrset_setid = @resource_record_set.set_identifier
203
+ rrset_setid ? (log_id + " (#{rrset_setid})") : log_id
204
+ end
205
+
206
+ self.send(:"#{attr}=", expected) unless @options.dry_run
207
+ end
208
+ end
209
+ end
210
+
211
+ unless @options.dry_run
212
+ @resource_record_set.update
213
+ @options.updated = true
214
+ end
215
+ end
216
+
217
+ def delete(opts = {})
218
+ return if type =~ /\A(SOA|NS)\Z/i
219
+ if not opts[:cascaded] or @options.force
220
+ log(:info, 'Delete ResourceRecordSet', :red) do
221
+ log_id = [@resource_record_set.name, @resource_record_set.type].join(' ')
222
+ rrset_setid = @resource_record_set.set_identifier
223
+ rrset_setid ? (log_id + " (#{rrset_setid})") : log_id
224
+ end
225
+ end
226
+
227
+ unless @options.dry_run
228
+ @resource_record_set.delete
229
+ @options.updated = true
230
+ end
231
+ end
232
+
233
+ def dns_name=(name)
234
+ if name
235
+ @resource_record_set.alias_target = @options.route53.dns_name_to_alias_target(name)
236
+ else
237
+ @resource_record_set.alias_target = nil
238
+ end
239
+ end
240
+
241
+ def dns_name
242
+ (@resource_record_set.alias_target || {})[:dns_name]
243
+ end
244
+
245
+ private
246
+
247
+ def method_missing(method_name, *args)
248
+ @resource_record_set.send(method_name, *args)
249
+ end
250
+ end # ResourceRecordSetWrapper
251
+
252
+ end # Route53Wrapper
253
+ end # Roadworker
@@ -0,0 +1,28 @@
1
+ require 'term/ansicolor'
2
+
3
+ class String
4
+ @@colorize = false
5
+
6
+ class << self
7
+ def colorize=(value)
8
+ @@colorize = value
9
+ end
10
+
11
+ def colorize
12
+ @@colorize
13
+ end
14
+ end # of class method
15
+
16
+ Term::ANSIColor::Attribute.named_attributes.map do |attr|
17
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
18
+ def #{attr.name}
19
+ if @@colorize
20
+ Term::ANSIColor.send(#{attr.name.inspect}, self)
21
+ else
22
+ self
23
+ end
24
+ end
25
+ EOS
26
+ end
27
+
28
+ end
@@ -0,0 +1,5 @@
1
+ module Roadworker
2
+ VERSION = "0.0.1"
3
+ end
4
+
5
+ Version = Roadworker::VERSION
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: roadworker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - winebarrel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: aws-sdk
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
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
+ - !ruby/object:Gem::Dependency
31
+ name: term-ansicolor
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Roadworker is a tool to manage Route53. It defines the state of Route53
79
+ using DSL, and updates Route53 according to DSL.
80
+ email: sgwr_dts@yahoo.co.jp
81
+ executables:
82
+ - roadwork
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - README.md
87
+ - bin/roadwork
88
+ - lib/roadworker/client.rb
89
+ - lib/roadworker/collection.rb
90
+ - lib/roadworker/dsl-converter.rb
91
+ - lib/roadworker/dsl.rb
92
+ - lib/roadworker/log.rb
93
+ - lib/roadworker/route53-exporter.rb
94
+ - lib/roadworker/route53-ext.rb
95
+ - lib/roadworker/route53-wrapper.rb
96
+ - lib/roadworker/string-ext.rb
97
+ - lib/roadworker/version.rb
98
+ - lib/roadworker.rb
99
+ homepage: https://bitbucket.org/winebarrel/roadworker
100
+ licenses:
101
+ - MIT
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 1.8.23
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: Roadworker is a tool to manage Route53.
124
+ test_files: []