syncwrap 1.5.1 → 1.5.2

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/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