roadworker 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +22 -1
- data/bin/roadwork +23 -16
- data/lib/roadworker/client.rb +6 -0
- data/lib/roadworker/dsl-converter.rb +20 -5
- data/lib/roadworker/dsl.rb +12 -0
- data/lib/roadworker/route53-exporter.rb +16 -6
- data/lib/roadworker/route53-health-check.rb +120 -0
- data/lib/roadworker/route53-wrapper.rb +17 -3
- data/lib/roadworker/version.rb +1 -1
- metadata +19 -2
data/README.md
CHANGED
@@ -6,7 +6,6 @@ It defines the state of Route53 using DSL, and updates Route53 according to DSL.
|
|
6
6
|
|
7
7
|
**Notice**
|
8
8
|
|
9
|
-
* HealthCheck is not supported.
|
10
9
|
* Cannot update TTL of two or more same records (with different SetIdentifier) after creation.
|
11
10
|
|
12
11
|
## Installation
|
@@ -61,6 +60,28 @@ hosted_zone "info.winebarrel.jp." do
|
|
61
60
|
rrset "xxx.info.winebarrel.jp.", "A" do
|
62
61
|
dns_name "elb-dns-name.elb.amazonaws.com"
|
63
62
|
end
|
63
|
+
|
64
|
+
rrset "zzz.info.winebarrel.jp", "A" do
|
65
|
+
set_identifier "Primary"
|
66
|
+
failover "PRIMARY"
|
67
|
+
health_check "http://192.0.43.10:80/path", "example.com"
|
68
|
+
ttl 456
|
69
|
+
resource_records(
|
70
|
+
"127.0.0.1",
|
71
|
+
"127.0.0.2"
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
rrset "zzz.info.winebarrel.jp", "A" do
|
76
|
+
set_identifier "Secondary"
|
77
|
+
failover "SECONDARY"
|
78
|
+
health_check "tcp://192.0.43.10:3306"
|
79
|
+
ttl 456
|
80
|
+
resource_records(
|
81
|
+
"127.0.0.3",
|
82
|
+
"127.0.0.4"
|
83
|
+
)
|
84
|
+
end
|
64
85
|
end
|
65
86
|
```
|
66
87
|
|
data/bin/roadwork
CHANGED
@@ -29,19 +29,20 @@ ARGV.options do |opt|
|
|
29
29
|
access_key = nil
|
30
30
|
secret_key = nil
|
31
31
|
|
32
|
-
opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key
|
33
|
-
opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key
|
34
|
-
opt.on('-a', '--apply') {|v| mode
|
35
|
-
opt.on('-f', '--file FILE') {|v| file
|
36
|
-
opt.on('', '--dry-run') {|v| options[:dry_run]
|
37
|
-
opt.on('' , '--force') { options[:force]
|
38
|
-
opt.on('
|
39
|
-
opt.on('-
|
40
|
-
opt.on('',
|
41
|
-
opt.on('', '--
|
42
|
-
opt.on('
|
43
|
-
opt.on(''
|
44
|
-
opt.on('' , '--
|
32
|
+
opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
|
33
|
+
opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
|
34
|
+
opt.on('-a', '--apply') {|v| mode = :apply }
|
35
|
+
opt.on('-f', '--file FILE') {|v| file = v }
|
36
|
+
opt.on('', '--dry-run') {|v| options[:dry_run] = true }
|
37
|
+
opt.on('' , '--force') { options[:force] = true }
|
38
|
+
opt.on('', '--no-health-check-gc') {|v| options[:no_health_check_gc] = true }
|
39
|
+
opt.on('-e', '--export') {|v| mode = :export }
|
40
|
+
opt.on('-o', '--output FILE') {|v| output_file = v }
|
41
|
+
opt.on('', '--split') {|v| split = true }
|
42
|
+
opt.on('', '--with-soa-ns') {|v| options[:with_soa_ns] = true }
|
43
|
+
opt.on('-t', '--test') {|v| mode = :test }
|
44
|
+
opt.on('' , '--no-color') { options[:color] = false }
|
45
|
+
opt.on('' , '--debug') { options[:debug] = true }
|
45
46
|
opt.parse!
|
46
47
|
|
47
48
|
if access_key and secret_key
|
@@ -76,13 +77,19 @@ begin
|
|
76
77
|
output_file = 'Routefile' if output_file == '-'
|
77
78
|
requires = []
|
78
79
|
|
79
|
-
client.export do |
|
80
|
-
hosted_zones.each do |zone|
|
80
|
+
client.export do |exported, converter|
|
81
|
+
exported[:hosted_zones].each do |zone|
|
81
82
|
route_file = File.join(File.dirname(output_file), "#{zone[:name].sub(/\.\Z/, '')}.route")
|
82
83
|
requires << route_file
|
83
84
|
|
84
85
|
logger.info(" write `#{route_file}`")
|
85
|
-
|
86
|
+
|
87
|
+
open(route_file, 'wb') do |f|
|
88
|
+
f.puts converter.call({
|
89
|
+
:hosted_zones => [zone],
|
90
|
+
:health_checks => exported[:health_checks],
|
91
|
+
})
|
92
|
+
end
|
86
93
|
end
|
87
94
|
end
|
88
95
|
|
data/lib/roadworker/client.rb
CHANGED
@@ -15,6 +15,8 @@ module Roadworker
|
|
15
15
|
@options.logger ||= Logger.new($stdout)
|
16
16
|
String.colorize = @options.color
|
17
17
|
@options.route53 = AWS::Route53.new
|
18
|
+
@health_checks = HealthCheck.health_checks(@options.route53, :extended => true)
|
19
|
+
@options.health_checks = @health_checks
|
18
20
|
@route53 = Route53Wrapper.new(@options)
|
19
21
|
end
|
20
22
|
|
@@ -31,6 +33,10 @@ module Roadworker
|
|
31
33
|
}
|
32
34
|
end
|
33
35
|
|
36
|
+
if updated and not @options.no_health_check_gc
|
37
|
+
HealthCheck.gc(@options.route53, :logger => @options.logger)
|
38
|
+
end
|
39
|
+
|
34
40
|
return updated
|
35
41
|
end
|
36
42
|
|
@@ -3,24 +3,40 @@ module Roadworker
|
|
3
3
|
class Converter
|
4
4
|
|
5
5
|
class << self
|
6
|
-
def convert(
|
7
|
-
|
6
|
+
def convert(exported)
|
7
|
+
self.new(exported).convert
|
8
8
|
end
|
9
|
+
end # of class method
|
10
|
+
|
11
|
+
def initialize(exported)
|
12
|
+
@health_checks = exported[:health_checks]
|
13
|
+
@hosted_zones = exported[:hosted_zones]
|
14
|
+
end
|
9
15
|
|
10
|
-
|
16
|
+
def convert
|
17
|
+
@hosted_zones.map {|i| output_zone(i) }.join("\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
11
21
|
|
12
22
|
def output_rrset(recrod)
|
13
23
|
name = recrod.delete(:name).inspect
|
14
24
|
type = recrod.delete(:type).inspect
|
15
25
|
|
16
26
|
attrs = recrod.map {|key, value|
|
17
|
-
|
27
|
+
case key
|
28
|
+
when :resource_records
|
18
29
|
if value.empty?
|
19
30
|
nil
|
20
31
|
else
|
21
32
|
value = value.map {|i| i.inspect }.join(",\n ")
|
22
33
|
"#{key}(\n #{value}\n )"
|
23
34
|
end
|
35
|
+
when :health_check_id
|
36
|
+
config = HealthCheck.config_to_hash(@health_checks[value])
|
37
|
+
hc_args = config[:url].inspect
|
38
|
+
hc_args << ", #{config[:host_name].inspect}" if config[:host_name]
|
39
|
+
"health_check #{hc_args}"
|
24
40
|
else
|
25
41
|
"#{key} #{value.inspect}"
|
26
42
|
end
|
@@ -43,7 +59,6 @@ hosted_zone #{name} do
|
|
43
59
|
end
|
44
60
|
EOS
|
45
61
|
end
|
46
|
-
end # of class method
|
47
62
|
|
48
63
|
end # Converter
|
49
64
|
end # DSL
|
data/lib/roadworker/dsl.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'roadworker/dsl-converter'
|
2
2
|
require 'roadworker/dsl-tester'
|
3
|
+
require 'roadworker/route53-health-check'
|
3
4
|
|
4
5
|
require 'ostruct'
|
6
|
+
require 'uri'
|
5
7
|
|
6
8
|
module Roadworker
|
7
9
|
class DSL
|
@@ -111,6 +113,16 @@ module Roadworker
|
|
111
113
|
@result.dns_name = value
|
112
114
|
end
|
113
115
|
|
116
|
+
def failover(value)
|
117
|
+
@result.failover = value
|
118
|
+
end
|
119
|
+
|
120
|
+
def health_check(url, host_name = nil)
|
121
|
+
config = HealthCheck.parse_url(url)
|
122
|
+
config[:fully_qualified_domain_name] = host_name if host_name
|
123
|
+
@result.health_check = config
|
124
|
+
end
|
125
|
+
|
114
126
|
def resource_records(*values)
|
115
127
|
if values.uniq.length != values.length
|
116
128
|
raise "Duplicate ResourceRecords: #{values.join(', ')}"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'roadworker/collection'
|
2
|
+
require 'roadworker/route53-health-check'
|
2
3
|
|
3
4
|
require 'ostruct'
|
4
5
|
|
@@ -16,11 +17,22 @@ module Roadworker
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def export
|
19
|
-
result =
|
20
|
+
result = {
|
21
|
+
:health_checks => HealthCheck.health_checks(@options.route53),
|
22
|
+
}
|
20
23
|
|
24
|
+
hosted_zones = result[:hosted_zones] = []
|
25
|
+
export_hosted_zones(hosted_zones)
|
26
|
+
|
27
|
+
return result
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def export_hosted_zones(hosted_zones)
|
21
33
|
Collection.batch(@options.route53.hosted_zones) do |zone|
|
22
34
|
zone_h = item_to_hash(zone, :name)
|
23
|
-
|
35
|
+
hosted_zones << zone_h
|
24
36
|
|
25
37
|
rrsets = []
|
26
38
|
zone_h[:rrsets] = rrsets
|
@@ -39,6 +51,8 @@ module Roadworker
|
|
39
51
|
:resource_records,
|
40
52
|
:alias_target,
|
41
53
|
:region,
|
54
|
+
:failover,
|
55
|
+
:health_check_id,
|
42
56
|
]
|
43
57
|
|
44
58
|
record_h = item_to_hash(record, *attrs)
|
@@ -53,12 +67,8 @@ module Roadworker
|
|
53
67
|
end
|
54
68
|
end
|
55
69
|
end
|
56
|
-
|
57
|
-
return result
|
58
70
|
end
|
59
71
|
|
60
|
-
private
|
61
|
-
|
62
72
|
def item_to_hash(item, *attrs)
|
63
73
|
h = {}
|
64
74
|
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'uuid'
|
3
|
+
|
4
|
+
module Roadworker
|
5
|
+
class HealthCheck
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def health_checks(route53, options = {})
|
9
|
+
self.new(route53).health_checks(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def gc(route53, options = {})
|
13
|
+
self.new(route53).gc(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def config_to_hash(config)
|
17
|
+
ipaddr = config[:ip_address]
|
18
|
+
port = config[:port]
|
19
|
+
type = config[:type].downcase
|
20
|
+
path = config[:resource_path]
|
21
|
+
fqdn = config[:fully_qualified_domain_name].downcase
|
22
|
+
|
23
|
+
url = "#{type}://#{ipaddr}:#{port}"
|
24
|
+
url << path if path && path != '/'
|
25
|
+
|
26
|
+
{:url => url, :host_name => fqdn}
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_url(url)
|
30
|
+
url = URI.parse(url)
|
31
|
+
path = url.path
|
32
|
+
|
33
|
+
if path.nil? or path.empty? or path == '/'
|
34
|
+
path = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
config = {}
|
38
|
+
|
39
|
+
{
|
40
|
+
:ip_address => url.host,
|
41
|
+
:port => url.port,
|
42
|
+
:type => url.scheme.upcase,
|
43
|
+
:resource_path => path,
|
44
|
+
}.each {|key, value|
|
45
|
+
config[key] = value if value
|
46
|
+
}
|
47
|
+
|
48
|
+
return config
|
49
|
+
end
|
50
|
+
end # of class method
|
51
|
+
|
52
|
+
def initialize(route53)
|
53
|
+
@route53 = route53
|
54
|
+
end
|
55
|
+
|
56
|
+
def health_checks(options = {})
|
57
|
+
check_list = {}
|
58
|
+
|
59
|
+
is_truncated = true
|
60
|
+
next_marker = nil
|
61
|
+
|
62
|
+
while is_truncated
|
63
|
+
opts = next_marker ? {:marker => next_marker} : {}
|
64
|
+
response = @route53.client.list_health_checks(opts)
|
65
|
+
|
66
|
+
response[:health_checks].each do |check|
|
67
|
+
check_list[check[:id]] = check[:health_check_config]
|
68
|
+
end
|
69
|
+
|
70
|
+
is_truncated = response[:is_truncated]
|
71
|
+
next_marker = response[:next_marker]
|
72
|
+
end
|
73
|
+
|
74
|
+
if options[:extended]
|
75
|
+
check_list.instance_variable_set(:@route53, @route53)
|
76
|
+
|
77
|
+
def check_list.find_or_create(attrs)
|
78
|
+
health_check_id, config = self.find {|hcid, elems| elems == attrs }
|
79
|
+
|
80
|
+
unless health_check_id
|
81
|
+
response = @route53.client.create_health_check({
|
82
|
+
:caller_reference => UUID.new.generate,
|
83
|
+
:health_check_config => attrs,
|
84
|
+
})
|
85
|
+
|
86
|
+
health_check_id = response[:health_check][:id]
|
87
|
+
config = response[:health_check][:health_check_config]
|
88
|
+
self[health_check_id] = config
|
89
|
+
end
|
90
|
+
|
91
|
+
return health_check_id
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
return check_list
|
96
|
+
end
|
97
|
+
|
98
|
+
def gc(options = {})
|
99
|
+
AWS.memoize {
|
100
|
+
check_list = health_checks
|
101
|
+
return if check_list.empty?
|
102
|
+
|
103
|
+
if (logger = options[:logger])
|
104
|
+
logger.info('Clean HealthChecks (pass `--no-health-check-gc` if you do not want to clean)')
|
105
|
+
end
|
106
|
+
|
107
|
+
@route53.hosted_zones.each do |zone|
|
108
|
+
zone.rrsets.each do |record|
|
109
|
+
check_list.delete(record.health_check_id)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
check_list.each do |health_check_id, config|
|
114
|
+
@route53.client.delete_health_check(:health_check_id => health_check_id)
|
115
|
+
end
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
end # HealthCheck
|
120
|
+
end # Roadworker
|
@@ -14,7 +14,9 @@ module Roadworker
|
|
14
14
|
:ttl,
|
15
15
|
:resource_records,
|
16
16
|
:dns_name,
|
17
|
-
:region
|
17
|
+
:region,
|
18
|
+
:failover,
|
19
|
+
:health_check,
|
18
20
|
]
|
19
21
|
|
20
22
|
def initialize(options)
|
@@ -130,6 +132,9 @@ module Roadworker
|
|
130
132
|
when :dns_name
|
131
133
|
attr = :alias_target
|
132
134
|
value = @options.route53.dns_name_to_alias_target(value)
|
135
|
+
when :health_check
|
136
|
+
attr = :health_check_id
|
137
|
+
value = @options.health_checks.find_or_create(value)
|
133
138
|
end
|
134
139
|
|
135
140
|
opts[attr] = value
|
@@ -231,6 +236,10 @@ module Roadworker
|
|
231
236
|
value ? value.gsub("\\052", '*') : value
|
232
237
|
end
|
233
238
|
|
239
|
+
def dns_name
|
240
|
+
(@resource_record_set.alias_target || {})[:dns_name]
|
241
|
+
end
|
242
|
+
|
234
243
|
def dns_name=(name)
|
235
244
|
if name
|
236
245
|
@resource_record_set.alias_target = @options.route53.dns_name_to_alias_target(name)
|
@@ -239,8 +248,13 @@ module Roadworker
|
|
239
248
|
end
|
240
249
|
end
|
241
250
|
|
242
|
-
def
|
243
|
-
|
251
|
+
def health_check
|
252
|
+
@options.health_checks[@resource_record_set.health_check_id]
|
253
|
+
end
|
254
|
+
|
255
|
+
def health_check=(check)
|
256
|
+
health_check_id = check ? @options.health_checks.find_or_create(check) : nil
|
257
|
+
@resource_record_set.health_check_id = health_check_id
|
244
258
|
end
|
245
259
|
|
246
260
|
private
|
data/lib/roadworker/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roadworker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk
|
@@ -59,6 +59,22 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 0.8.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: uuid
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.3.7
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.3.7
|
62
78
|
- !ruby/object:Gem::Dependency
|
63
79
|
name: bundler
|
64
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,6 +141,7 @@ files:
|
|
125
141
|
- lib/roadworker/log.rb
|
126
142
|
- lib/roadworker/route53-exporter.rb
|
127
143
|
- lib/roadworker/route53-ext.rb
|
144
|
+
- lib/roadworker/route53-health-check.rb
|
128
145
|
- lib/roadworker/route53-wrapper.rb
|
129
146
|
- lib/roadworker/string-ext.rb
|
130
147
|
- lib/roadworker/version.rb
|