syncwrap 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc CHANGED
@@ -1,3 +1,12 @@
1
+ === 1.5.2 (2013-4-10)
2
+ * Add check for init, aws_configure only if aws_config_json file
3
+ exists.
4
+ * Generalize waiting for created/terminated AWS resources, including
5
+ better diagnostic output.
6
+ * Add missing wait for EBS volume creation.
7
+ * Add default wait for Route53 CNAME creation, using current
8
+ authoritative Amazon name server.
9
+
1
10
  === 1.5.1 (2013-4-3)
2
11
  * Include syncwrap/aws.rb for real.
3
12
 
@@ -20,7 +29,7 @@
20
29
  may already be installed)
21
30
 
22
31
  === 1.3.0 (2012-10-4)
23
- * Include RHEL/Amazon Linux Postgresql 9.1 config and deploy support
32
+ * Include RHEL/Amazon Linux PostgreSQL 9.1 config and deploy support
24
33
  and reorganize for Ubuntu support as well. Default deploy data dir
25
34
  is now /pg/data which makes sense for an EBS mount. Config is
26
35
  further tuned for EBS. PostgreSQL::EC2 has been dropped.
data/lib/syncwrap/aws.rb CHANGED
@@ -16,6 +16,7 @@
16
16
 
17
17
  require 'json'
18
18
  require 'aws-sdk'
19
+ require 'resolv'
19
20
 
20
21
  require 'syncwrap/common'
21
22
 
@@ -55,6 +56,10 @@ module SyncWrap::AWS
55
56
  # Default options for Route53 record set creation
56
57
  attr_accessor :route53_default_rs_options
57
58
 
59
+ # DNS Resolver options for testing Route53 (default: Use public
60
+ # google name servers to avoid local negative caching)
61
+ attr_accessor :resolver_options
62
+
58
63
  def initialize
59
64
  @aws_config_json = 'private/aws.json'
60
65
  @aws_regions = %w[ us-east-1 ]
@@ -72,11 +77,18 @@ module SyncWrap::AWS
72
77
  :region => 'us-east-1'
73
78
  }
74
79
 
75
- @route53_default_rs_options = {}
80
+ @route53_default_rs_options = {
81
+ :ttl => 300,
82
+ :wait => true
83
+ }
84
+
85
+ @resolver_options = {
86
+ :nameserver => [ '8.8.8.8', '8.8.4.4' ]
87
+ }
76
88
 
77
89
  super
78
90
 
79
- aws_configure
91
+ aws_configure if File.exist?( @aws_config_json )
80
92
  aws_read_instances if File.exist?( @aws_instances_json )
81
93
  end
82
94
 
@@ -150,10 +162,13 @@ module SyncWrap::AWS
150
162
 
151
163
  attachments = opts[ :ebs_volumes ].times.map do |i|
152
164
  vol = ec2.volumes.create( vopts )
165
+ wait_until( vol.id, 0.5 ) { vol.status == :available }
153
166
  vol.attach_to( inst, "/dev/sdh#{i+1}" ) #=> Attachment
154
167
  end
155
168
 
156
- sleep 1 while attachments.any? { |a| a.status == :attaching }
169
+ wait_until( "volumes to attach" ) do
170
+ !( attachments.any? { |a| a.status == :attaching } )
171
+ end
157
172
  end
158
173
 
159
174
  iprops = aws_instance_to_props( region, inst )
@@ -168,18 +183,38 @@ module SyncWrap::AWS
168
183
  #
169
184
  # :domain_name:: name of the hosted zone and suffix for
170
185
  # CNAME. Should terminate in a DOT '.'
186
+ # :wait:: If true, wait for CNAME to resolve
171
187
  def route53_create_host_cname( iprops, opts = {} )
172
188
  opts = deep_merge_hashes( @route53_default_rs_options, opts )
173
- dname = opts.delete( :domain_name ) #with terminal '.'
174
- rs_opts =
175
- { :ttl => 300 }.
176
- merge( opts ).
177
- merge( :resource_records => [ { :value => iprops[:internet_name] } ] )
189
+ dname = dot_terminate( opts.delete( :domain_name ) )
190
+ do_wait = opts.delete( :wait )
191
+ rs_opts = opts.
192
+ merge( :resource_records => [ {:value => iprops[:internet_name]} ] )
178
193
 
179
194
  r53 = AWS::Route53.new
180
195
  zone = r53.hosted_zones.find { |hz| hz.name == dname } or
181
196
  raise "Route53 Hosted Zone name #{dname} not found"
182
- zone.rrsets.create( [ iprops[:name], dname ].join('.'), 'CNAME', rs_opts )
197
+ long_name = [ iprops[:name], dname ].join('.')
198
+ zone.rrsets.create( long_name, 'CNAME', rs_opts )
199
+ wait_for_dns_resolve( long_name, dname ) if do_wait
200
+ end
201
+
202
+ def wait_for_dns_resolve( long_name,
203
+ domain,
204
+ rtype = Resolv::DNS::Resource::IN::CNAME )
205
+
206
+ ns_addr = Resolv::DNS.open( @resolver_options ) do |rvr|
207
+ ns_n = rvr.getresource( domain, Resolv::DNS::Resource::IN::SOA ).mname
208
+ rvr.getaddress( ns_n ).to_s
209
+ end
210
+
211
+ sleep 3 # Initial wait
212
+
213
+ wait_until( "#{long_name} to resolve", 3.0 ) do
214
+ Resolv::DNS.open( :nameserver => ns_addr ) do |rvr|
215
+ rvr.getresources( long_name, rtype ).first
216
+ end
217
+ end
183
218
  end
184
219
 
185
220
  # Terminates an instance and permanently deletes any EBS volumes
@@ -200,9 +235,8 @@ module SyncWrap::AWS
200
235
  end
201
236
  end.compact
202
237
 
203
- puts "Terminating instance #{inst.id}"
204
238
  inst.terminate
205
- sleep 1 while inst.status != :terminated
239
+ wait_until( "termination of #{inst.id}", 2.0 ) { inst.status == :terminated }
206
240
 
207
241
  ebs_volumes = ebs_volumes.map do |vid|
208
242
  volume = ec2.volumes[ vid ]
@@ -215,8 +249,9 @@ module SyncWrap::AWS
215
249
  end.compact
216
250
 
217
251
  ebs_volumes.each do |vol|
218
- puts "Deleting vol #{vol.id} (#{vol.status})"
219
- sleep 1 until vol.status == :available || vol.status == :deleted
252
+ wait_until( "deletion of vol #{vol.id}" ) do
253
+ vol.status == :available || vol.status == :deleted
254
+ end
220
255
  vol.delete if vol.status == :available
221
256
  end
222
257
 
@@ -254,13 +289,9 @@ module SyncWrap::AWS
254
289
  end
255
290
 
256
291
  def wait_for_running( inst )
257
- while ( stat = inst.status ) == :pending
258
- puts "Waiting 1s for instance to run"
259
- sleep 1
260
- end
261
- unless stat == :running
262
- raise "Instance #{inst.id} has status #{stat}"
263
- end
292
+ wait_until( "instance #{inst.id} to run", 2.0 ) { inst.status != :pending }
293
+ stat = inst.status
294
+ raise "Instance #{inst.id} has status #{stat}" unless stat == :running
264
295
  nil
265
296
  end
266
297
 
@@ -397,4 +428,21 @@ module SyncWrap::AWS
397
428
  sudo cmd
398
429
  end
399
430
 
431
+ # Wait until block returns truthy, sleeping for freq seconds between
432
+ # attempts. Writes desc and a sequence of DOTs on a single line
433
+ # until complete.
434
+ def wait_until( desc, freq = 1.0 )
435
+ $stdout.write( "Waiting for " + desc )
436
+ until (ret = yield) do
437
+ $stdout.write '.'
438
+ sleep freq
439
+ end
440
+ ret
441
+ ensure
442
+ puts
443
+ end
444
+
445
+ def dot_terminate( name )
446
+ ( name =~ /\.$/ ) ? name : ( name + '.' )
447
+ end
400
448
  end
data/lib/syncwrap/base.rb CHANGED
@@ -15,5 +15,5 @@
15
15
  #++
16
16
 
17
17
  module SyncWrap
18
- VERSION='1.5.1'
18
+ VERSION='1.5.2'
19
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syncwrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.2
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-04-03 00:00:00.000000000 Z
12
+ date: 2013-04-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -128,7 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
128
  version: '0'
129
129
  segments:
130
130
  - 0
131
- hash: -4463767626501128078
131
+ hash: -2508006048029112256
132
132
  required_rubygems_version: !ruby/object:Gem::Requirement
133
133
  none: false
134
134
  requirements:
@@ -137,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
137
  version: '0'
138
138
  segments:
139
139
  - 0
140
- hash: -4463767626501128078
140
+ hash: -2508006048029112256
141
141
  requirements: []
142
142
  rubyforge_project:
143
143
  rubygems_version: 1.8.25