syncwrap 1.5.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/History.rdoc +19 -0
  3. data/Manifest.txt +82 -34
  4. data/README.rdoc +96 -48
  5. data/Rakefile +0 -65
  6. data/bin/syncwrap +27 -0
  7. data/examples/LAYOUT.rdoc +70 -0
  8. data/examples/Rakefile +16 -0
  9. data/examples/ec2.rb +44 -0
  10. data/examples/hello.rb +14 -0
  11. data/examples/hello_binding.rb +27 -0
  12. data/examples/jruby.rb +11 -0
  13. data/examples/private/aws.json +4 -0
  14. data/examples/rput.rb +24 -0
  15. data/examples/sync/home/bob/.ssh/authorized_keys +1 -0
  16. data/examples/sync/tmp/sample.erb +3 -0
  17. data/lib/syncwrap/amazon_ec2.rb +236 -0
  18. data/lib/syncwrap/amazon_ws.rb +308 -0
  19. data/lib/syncwrap/base.rb +4 -2
  20. data/lib/syncwrap/cli.rb +328 -0
  21. data/lib/syncwrap/component.rb +443 -0
  22. data/lib/syncwrap/components/commercial_jdk.rb +76 -0
  23. data/lib/syncwrap/components/cruby_vm.rb +144 -0
  24. data/lib/syncwrap/components/etc_hosts.rb +44 -0
  25. data/lib/syncwrap/{geminabox.rb → components/geminabox.rb} +12 -17
  26. data/lib/syncwrap/components/hashdot.rb +97 -0
  27. data/lib/syncwrap/components/iyyov.rb +144 -0
  28. data/lib/syncwrap/components/iyyov_daemon.rb +125 -0
  29. data/lib/syncwrap/components/jruby_vm.rb +122 -0
  30. data/lib/syncwrap/components/mdraid.rb +204 -0
  31. data/lib/syncwrap/components/network.rb +99 -0
  32. data/lib/syncwrap/components/open_jdk.rb +70 -0
  33. data/lib/syncwrap/components/postgresql.rb +159 -0
  34. data/lib/syncwrap/components/qpid.rb +303 -0
  35. data/lib/syncwrap/components/rhel.rb +71 -0
  36. data/lib/syncwrap/components/run_user.rb +99 -0
  37. data/lib/syncwrap/components/ubuntu.rb +85 -0
  38. data/lib/syncwrap/components/users.rb +200 -0
  39. data/lib/syncwrap/context.rb +260 -0
  40. data/lib/syncwrap/distro.rb +53 -60
  41. data/lib/syncwrap/formatter.rb +149 -0
  42. data/lib/syncwrap/host.rb +134 -0
  43. data/lib/syncwrap/main.rb +62 -0
  44. data/lib/syncwrap/path_util.rb +55 -0
  45. data/lib/syncwrap/rsync.rb +227 -0
  46. data/lib/syncwrap/ruby_support.rb +110 -0
  47. data/lib/syncwrap/shell.rb +207 -0
  48. data/lib/syncwrap.rb +367 -1
  49. data/{etc → sync/etc}/gemrc +1 -3
  50. data/sync/etc/hosts.erb +8 -0
  51. data/{etc/init.d/iyyov → sync/etc/init.d/iyyov.erb} +35 -7
  52. data/sync/etc/sysconfig/pgsql/postgresql.erb +2 -0
  53. data/sync/src/hashdot/Makefile.erb +98 -0
  54. data/sync/src/hashdot/profiles/default.hdp.erb +25 -0
  55. data/sync/src/hashdot/profiles/jruby-common.hdp +28 -0
  56. data/sync/src/hashdot/profiles/jruby-shortlived.hdp +9 -0
  57. data/sync/src/hashdot/profiles/jruby.hdp.erb +13 -0
  58. data/sync/src/hashdot/profiles/shortlived.hdp +6 -0
  59. data/sync/var/iyyov/default/config.rb +1 -0
  60. data/sync/var/iyyov/default/daemon.rb.erb +15 -0
  61. data/sync/var/iyyov/jobs.rb.erb +4 -0
  62. data/test/muddled_sync.rb +13 -0
  63. data/test/setup.rb +39 -0
  64. data/test/sync/d1/bar +1 -0
  65. data/test/sync/d1/foo.erb +1 -0
  66. data/test/sync/d3/d2/bar +1 -0
  67. data/test/sync/d3/d2/foo.erb +1 -0
  68. data/test/test_components.rb +108 -0
  69. data/test/test_context.rb +107 -0
  70. data/test/test_context_rput.rb +289 -0
  71. data/test/test_rsync.rb +138 -0
  72. data/test/test_shell.rb +233 -0
  73. data/test/test_space.rb +218 -0
  74. data/test/test_space_main.rb +40 -0
  75. data/test/zfile +1 -0
  76. metadata +204 -71
  77. data/etc/sysconfig/pgsql/postgresql +0 -2
  78. data/lib/syncwrap/aws.rb +0 -448
  79. data/lib/syncwrap/common.rb +0 -161
  80. data/lib/syncwrap/ec2.rb +0 -59
  81. data/lib/syncwrap/hashdot.rb +0 -70
  82. data/lib/syncwrap/iyyov.rb +0 -139
  83. data/lib/syncwrap/java.rb +0 -61
  84. data/lib/syncwrap/jruby.rb +0 -118
  85. data/lib/syncwrap/postgresql.rb +0 -135
  86. data/lib/syncwrap/qpid.rb +0 -251
  87. data/lib/syncwrap/remote_task.rb +0 -199
  88. data/lib/syncwrap/rhel.rb +0 -67
  89. data/lib/syncwrap/ubuntu.rb +0 -78
  90. data/lib/syncwrap/user_run.rb +0 -102
  91. data/test/test_syncwrap.rb +0 -202
  92. data/var/iyyov/jobs.rb +0 -11
  93. /data/{etc → sync/etc}/corosync/corosync.conf +0 -0
  94. /data/{etc → sync/etc}/corosync/uidgid.d/qpid +0 -0
  95. /data/{etc → sync/etc}/init.d/qpidd +0 -0
  96. /data/{etc → sync/etc}/sysctl.d/61-postgresql-shm.conf +0 -0
  97. /data/{usr/local → sync/jruby}/bin/jgem +0 -0
  98. /data/{postgresql → sync/postgresql}/rhel/pg_hba.conf +0 -0
  99. /data/{postgresql → sync/postgresql}/rhel/pg_ident.conf +0 -0
  100. /data/{postgresql → sync/postgresql}/rhel/postgresql.conf +0 -0
  101. /data/{postgresql → sync/postgresql}/ubuntu/environment +0 -0
  102. /data/{postgresql → sync/postgresql}/ubuntu/pg_ctl.conf +0 -0
  103. /data/{postgresql → sync/postgresql}/ubuntu/pg_hba.conf +0 -0
  104. /data/{postgresql → sync/postgresql}/ubuntu/pg_ident.conf +0 -0
  105. /data/{postgresql → sync/postgresql}/ubuntu/postgresql.conf +0 -0
  106. /data/{postgresql → sync/postgresql}/ubuntu/start.conf +0 -0
  107. /data/{usr → sync/usr}/local/etc/qpidd.conf +0 -0
data/lib/syncwrap/aws.rb DELETED
@@ -1,448 +0,0 @@
1
- #--
2
- # Copyright (c) 2011-2013 David Kellum
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License"); you
5
- # may not use this file except in compliance with the License. You may
6
- # obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
- # implied. See the License for the specific language governing
14
- # permissions and limitations under the License.
15
- #++
16
-
17
- require 'json'
18
- require 'aws-sdk'
19
- require 'resolv'
20
-
21
- require 'syncwrap/common'
22
-
23
- # Supports host provisioning in EC2 via AWS APIs, creating and
24
- # attaching EBS volumes, creating Route53 record sets, and as a remote
25
- # task: building mdraid volumes.
26
- #
27
- # This module also includes a disk based cache of meta-data on created
28
- # instances which allows automated role assignment (i.e. create an
29
- # instance and run deploy tasks on it in a single pass.)
30
- module SyncWrap::AWS
31
- include SyncWrap::Common
32
-
33
- # The json configuration file, parsed and passed directly to
34
- # AWS::config method. This file should contain a json object with
35
- # the minimal required keys: access_key_id, secret_access_key
36
- # (default: ./private/aws.json)
37
- attr_accessor :aws_config_json
38
-
39
- # The cached aws instance json file (default: ./aws_instances.json)
40
- attr_accessor :aws_instances_json
41
-
42
- # Array of region strings to check for aws_import_instances
43
- attr_accessor :aws_regions
44
-
45
- # Array of imported or read instances represented as hashes.
46
- attr_accessor :aws_instances
47
-
48
- # Default options (which may be overridden) in call to
49
- # aws_create_instance.
50
- attr_accessor :aws_default_instance_options
51
-
52
- # Default options (which may be overridden) in call to
53
- # aws_create_security_group.
54
- attr_accessor :aws_default_sg_options
55
-
56
- # Default options for Route53 record set creation
57
- attr_accessor :route53_default_rs_options
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
-
63
- def initialize
64
- @aws_config_json = 'private/aws.json'
65
- @aws_regions = %w[ us-east-1 ]
66
- @aws_instances_json = 'aws_instances.json'
67
- @aws_instances = []
68
- @aws_default_instance_options = {
69
- :ebs_volumes => 0,
70
- :ebs_volume_options => { :size => 16 }, #gb
71
- :lvm_volumes => [ [ 1.00, '/data' ] ],
72
- :security_groups => :default,
73
- :instance_type => 'm1.medium',
74
- :region => 'us-east-1'
75
- }
76
- @aws_default_sg_options = {
77
- :region => 'us-east-1'
78
- }
79
-
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
- }
88
-
89
- super
90
-
91
- aws_configure if File.exist?( @aws_config_json )
92
- aws_read_instances if File.exist?( @aws_instances_json )
93
- end
94
-
95
- def aws_configure
96
- AWS.config( JSON.parse( IO.read( @aws_config_json ),
97
- :symbolize_names => true ) )
98
- end
99
-
100
- # Create a security_group given name and options. :region is the
101
- # only required option, :description is a good to have. Currently
102
- # this is a no-op if the security group already exists.
103
- def aws_create_security_group( name, opts = {} )
104
- opts = deep_merge_hashes( @aws_default_sg_options, opts )
105
- region = opts.delete( :region )
106
- ec2 = AWS::EC2.new.regions[ region ]
107
- unless ec2.security_groups.find { |sg| sg.name == name }
108
- ec2.security_groups.create( name, opts )
109
- end
110
- end
111
-
112
- # Create an instance, using name as the Name tag and assumed
113
- # host name. For options see
114
- # {AWS::EC2::InstanceCollection.create}[http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/InstanceCollection.html#create-instance_method]
115
- # with the following additions/differences:
116
- #
117
- # :count:: must be 1 or unspecified.
118
- # :region:: Default 'us-east-1'
119
- # :security_groups:: As per aws-sdk, but the special :default value
120
- # is replaced with a single security group with
121
- # same name as the :region option.
122
- # :ebs_volumes:: The number of EBS volumes to create an attach to this instance.
123
- # :ebs_volume_options:: A nested Hash of options, as per
124
- # {AWS::EC2::VolumeCollection.create}[http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/VolumeCollection.html#create-instance_method]
125
- # with custom default :size 16 GB, and the same
126
- # :availibility_zone as the instance.
127
- # :lvm_volumes:: Ignored here.
128
- # :roles:: Array of role Strings or Symbols (applied as Roles tag)
129
- def aws_create_instance( name, opts = {} )
130
- opts = deep_merge_hashes( @aws_default_instance_options, opts )
131
- region = opts.delete( :region )
132
- opts.delete( :lvm_volumes ) #unused here
133
-
134
- ec2 = AWS::EC2.new.regions[ region ]
135
-
136
- iopts = opts.dup
137
- iopts.delete( :ebs_volumes )
138
- iopts.delete( :ebs_volume_options )
139
- iopts.delete( :roles )
140
-
141
- if iopts[ :count ] && iopts[ :count ] != 1
142
- raise ":count #{iopts[ :count ]} != 1 is not supported"
143
- end
144
-
145
- if iopts[ :security_groups ] == :default
146
- iopts[ :security_groups ] = [ region ]
147
- end
148
-
149
- inst = ec2.instances.create( iopts )
150
-
151
- inst.add_tag( 'Name', :value => name )
152
-
153
- if opts[ :roles ]
154
- inst.add_tag( 'Roles', :value => opts[ :roles ].join(' ') )
155
- end
156
-
157
- wait_for_running( inst )
158
-
159
- if opts[ :ebs_volumes ] > 0
160
- vopts = { :availability_zone => inst.availability_zone }.
161
- merge( opts[ :ebs_volume_options ] )
162
-
163
- attachments = opts[ :ebs_volumes ].times.map do |i|
164
- vol = ec2.volumes.create( vopts )
165
- wait_until( vol.id, 0.5 ) { vol.status == :available }
166
- vol.attach_to( inst, "/dev/sdh#{i+1}" ) #=> Attachment
167
- end
168
-
169
- wait_until( "volumes to attach" ) do
170
- !( attachments.any? { |a| a.status == :attaching } )
171
- end
172
- end
173
-
174
- iprops = aws_instance_to_props( region, inst )
175
- aws_instance_added( iprops )
176
- aws_write_instances
177
- iprops
178
- end
179
-
180
- # Create a Route53 DNS CNAME from iprops :name to :internet_name.
181
- # Options are per {AWS::Route53::ResourceRecordSetCollection.create}[http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/Route53/ResourceRecordSetCollection.html#create-instance_method]
182
- # (currently undocumented) with the following addition:
183
- #
184
- # :domain_name:: name of the hosted zone and suffix for
185
- # CNAME. Should terminate in a DOT '.'
186
- # :wait:: If true, wait for CNAME to resolve
187
- def route53_create_host_cname( iprops, opts = {} )
188
- opts = deep_merge_hashes( @route53_default_rs_options, opts )
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]} ] )
193
-
194
- r53 = AWS::Route53.new
195
- zone = r53.hosted_zones.find { |hz| hz.name == dname } or
196
- raise "Route53 Hosted Zone name #{dname} not found"
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
218
- end
219
-
220
- # Terminates an instance and permanently deletes any EBS volumes
221
- # attached to /dev/sdh like via create. WARNING: potential for data
222
- # loss! The minimum required propererties in iprops hash are :region
223
- # and :id.
224
- def aws_terminate_instance_and_ebs_volumes( iprops )
225
- ec2 = AWS::EC2.new.regions[ iprops[ :region ] ]
226
- inst = ec2.instances[ iprops[ :id ] ]
227
- unless inst.exists?
228
- raise "Instance #{iprops[:id]} does not exist in #{iprops[:region]}"
229
- end
230
-
231
- ebs_volumes = inst.block_devices.map do |dev|
232
- ebs = dev[ :ebs ]
233
- if ebs && dev[:device_name] =~ /dh\d+$/ && !ebs[:delete_on_termination]
234
- ebs[ :volume_id ]
235
- end
236
- end.compact
237
-
238
- inst.terminate
239
- wait_until( "termination of #{inst.id}", 2.0 ) { inst.status == :terminated }
240
-
241
- ebs_volumes = ebs_volumes.map do |vid|
242
- volume = ec2.volumes[ vid ]
243
- if volume.exists?
244
- volume
245
- else
246
- puts "WARN: #{volume} doesn't exist"
247
- nil
248
- end
249
- end.compact
250
-
251
- ebs_volumes.each do |vol|
252
- wait_until( "deletion of vol #{vol.id}" ) do
253
- vol.status == :available || vol.status == :deleted
254
- end
255
- vol.delete if vol.status == :available
256
- end
257
-
258
- found = aws_find_instance( iprops )
259
- if found
260
- aws_instance_removed( found )
261
- aws_write_instances
262
- end
263
- end
264
-
265
- # Return instance properties, by example via iprops, either by [
266
- # :id, :region ], :internet_name, :internet_ip, or :name, attempted
267
- # in that order.
268
- def aws_find_instance( iprops )
269
- if iprops[:id]
270
- @aws_instances.find do |r|
271
- r[:id] == iprops[:id] && r[:region] == iprops[:region]
272
- end
273
- else
274
- [ :internet_name, :internet_ip, :name ].inject( nil ) do |found, key|
275
- found || @aws_instances.find { |r| r[key] == iprops[key] }
276
- end
277
- end
278
- end
279
-
280
- def aws_instance_added( inst )
281
- @aws_instances << inst
282
- @aws_instances.sort! { |p,n| p[:name] <=> n[:name] }
283
- end
284
-
285
- def aws_instance_removed( iprops )
286
- @aws_instances.reject! do |row|
287
- row[:id] == iprops[:id] && row[:region] == iprops[:region]
288
- end
289
- end
290
-
291
- def wait_for_running( inst )
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
295
- nil
296
- end
297
-
298
- # Find running/pending instances in each of aws_regions, convert to
299
- # props, and save in aws_instances list.
300
- def aws_import_instances
301
-
302
- instances = []
303
-
304
- aws_regions.each do |region|
305
- ec2 = AWS::EC2.new.regions[ region ]
306
-
307
- found = ec2.instances.map do |inst|
308
- next unless [ :running, :pending ].include?( inst.status )
309
- aws_instance_to_props( region, inst )
310
- end
311
-
312
- instances += found.compact
313
- end
314
-
315
- @aws_instances = instances
316
- end
317
-
318
- def aws_instance_to_props( region, inst )
319
- tags = inst.tags.to_h
320
- name = tags[ 'Name' ]
321
- roles = decode_roles( tags[ 'Roles' ] )
322
-
323
- { :id => inst.id,
324
- :region => region,
325
- :ami => inst.image_id,
326
- :name => name,
327
- :internet_name => inst.dns_name,
328
- :internet_ip => inst.ip_address,
329
- :internal_ip => inst.private_ip_address,
330
- :instance_type => inst.instance_type,
331
- :roles => roles }
332
- end
333
-
334
- # Read the aws_instances_json file, replacing in RAM AWS instances
335
- def aws_read_instances
336
- list = JSON.parse( IO.read( aws_instances_json ), :symbolize_names => true )
337
- list.each do |inst|
338
- inst[:roles] = ( inst[:roles] || [] ).map { |r| r.to_sym }
339
- end
340
- @aws_instances = list.sort { |p,n| p[:name] <=> n[:name] }
341
- end
342
-
343
- # Overwrite aws_instances_json file with the current AWS instances.
344
- def aws_write_instances
345
- File.open( aws_instances_json, 'w' ) do |fout|
346
- aws_dump_instances( fout )
347
- end
348
- end
349
-
350
- # Dump AWS instances as JSON but with custom layout of host per line.
351
- def aws_dump_instances( fout = $stdout )
352
- fout.puts '['
353
- rows = @aws_instances.sort { |p,n| p[:name] <=> n[:name] }
354
- rows.each_with_index do |row, i|
355
- fout.puts( " " + JSON.generate( row, :space => ' ', :object_nl => ' ' ) +
356
- ( ( i == ( rows.length - 1 ) ) ? '' : ',' ) )
357
- end
358
- fout.puts ']'
359
- end
360
-
361
- def decode_roles( roles )
362
- ( roles || "" ).split( /\s+/ ).map { |r| r.to_sym }
363
- end
364
-
365
- # Runs create_lvm_volumes! if the first :lvm_volumes mount path does
366
- # not yet exist.
367
- def create_lvm_volumes( opts = {} )
368
- opts = deep_merge_hashes( @aws_default_instance_options, opts )
369
- unless exist?( opts[ :lvm_volumes ].first[1] )
370
- create_lvm_volumes!( opts )
371
- end
372
- end
373
-
374
- # Create an mdraid array from previously attached EBS volumes, then
375
- # divvy up across N lvm mount points by ratio, creating filesystems and
376
- # mounting. This mdadm and lvm recipe was originally derived from
377
- # {Install MongoDB on Amazon EC2}[http://docs.mongodb.org/ecosystem/tutorial/install-mongodb-on-amazon-ec2/]
378
- #
379
- # === Options
380
- # :ebs_volumes:: The number of EBS volumes previously created and
381
- # attached to this instance.
382
- # :lvm_volumes:: A table of [ slice, path (,name) ] rows where;
383
- # slice is a floating point ratio in range (0.0,1.0],
384
- # path is the mount point, and name is the lvm name,
385
- # defaulting if omitted to the last path element. The
386
- # sum of all slice values in the table should be 1.0.
387
- def create_lvm_volumes!( opts = {} )
388
- opts = deep_merge_hashes( @aws_default_instance_options, opts )
389
-
390
- vol_count = opts[ :ebs_volumes ]
391
- devices = vol_count.times.map { |i| "/dev/xvdh#{i+1}" }
392
-
393
- cmd = <<-SH
394
- #{dist_install_s( "mdadm", "lvm2", :minimal => true )}
395
- mdadm --create /dev/md0 --level=10 --chunk=256 --raid-devices=#{vol_count} \
396
- #{devices.join ' '}
397
- echo "DEVICE #{devices.join ' '}" > /etc/mdadm.conf
398
- mdadm --detail --scan >> /etc/mdadm.conf
399
- SH
400
-
401
- devices.each do |d|
402
- cmd << <<-SH
403
- blockdev --setra 128 #{d}
404
- SH
405
- end
406
-
407
- cmd << <<-SH
408
- blockdev --setra 128 /dev/md0
409
- dd if=/dev/zero of=/dev/md0 bs=512 count=1
410
- pvcreate /dev/md0
411
- vgcreate vg0 /dev/md0
412
- SH
413
-
414
- opts[ :lvm_volumes ].each do | slice, path, name |
415
- name ||= ( path =~ /\/(\w+)$/ ) && $1
416
- cmd << <<-SH
417
- lvcreate -l #{(slice * 100).round}%vg -n #{name} vg0
418
- mke2fs -t ext4 -F /dev/vg0/#{name}
419
- if [ -d #{path} ]; then
420
- rm -rf #{path}
421
- fi
422
- mkdir -p #{path}
423
- echo '/dev/vg0/#{name} #{path} ext4 defaults,auto,noatime,noexec 0 0' >> /etc/fstab
424
- mount #{path}
425
- SH
426
- end
427
-
428
- sudo cmd
429
- end
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
448
- end
@@ -1,161 +0,0 @@
1
- #--
2
- # Copyright (c) 2011-2013 David Kellum
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License"); you
5
- # may not use this file except in compliance with the License. You may
6
- # obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
- # implied. See the License for the specific language governing
14
- # permissions and limitations under the License.
15
- #++
16
-
17
- require 'syncwrap/base'
18
-
19
- # Common utility methods and variables.
20
- module SyncWrap::Common
21
-
22
- # The prefix for local non-distro installs (default: /usr/local)
23
- attr_accessor :common_prefix
24
-
25
- def initialize
26
- super
27
- @common_prefix = '/usr/local'
28
- end
29
-
30
- # Return true if remote file exists, as per "test -e"
31
- def exist?( file )
32
- exec_conditional { run "test -e #{file}" } == 0
33
- end
34
-
35
- # Put files or entire directories to remote.
36
- #
37
- # rput( src..., dest, {options} )
38
- # rput( src, {options} )
39
- #
40
- # A trailing hash is interpreted as options, see below.
41
- #
42
- # If there is two or more remaining arguments, the last is
43
- # interpreted as the remote destination. If there is a single
44
- # remaining argument, the destination is implied by finding its base
45
- # directory and prepending '/'. Thus for example:
46
- #
47
- # rput( 'etc/gemrc', :user => 'root' )
48
- #
49
- # has an implied destination of: `/etc/`. The src and destination
50
- # are intrepreted as by `rsync`: glob patterns are expanded and
51
- # trailing '/' is significant.
52
- #
53
- # ==== Options
54
- # :user:: Files should be owned on destination by a user other than
55
- # installer (ex: 'root') (implies sudo)
56
- # :perms:: Permissions to set for install files.
57
- # :excludes:: One or more rsync compatible --filter excludes, or
58
- # :dev which excludes common developmoent tree droppings
59
- # like '*~'
60
- def rput( *args )
61
- opts = args.last.is_a?( Hash ) && args.pop || {}
62
-
63
- if args.length == 1
64
- abspath = "/" + args.first
65
- abspath = File.dirname( abspath ) + '/' unless abspath =~ %r{/$}
66
- else
67
- abspath = args.pop
68
- end
69
-
70
- flags = []
71
-
72
- excludes = Array( opts[ :excludes ] )
73
- flags += excludes.map do |e|
74
- if e == :dev
75
- '--cvs-exclude'
76
- else
77
- "--filter=#{e}"
78
- end
79
- end
80
-
81
- if opts[ :perms ]
82
- flags << '-p'
83
- flags << "--chmod=#{opts[ :perms ]}"
84
- end
85
-
86
- if opts[ :user ]
87
- # Use sudo to place files at remote.
88
- user = opts[ :user ] || 'root'
89
- flags << ( if user != 'root'
90
- "--rsync-path=sudo -u #{user} rsync"
91
- else
92
- "--rsync-path=sudo rsync"
93
- end )
94
- end
95
-
96
- cmd = [ flags, args, [ target_host, abspath ].join(':') ].flatten.compact
97
- rsync( *cmd )
98
-
99
- end
100
-
101
- # Run args as shell command on the remote host. A line delimited
102
- # argument is interpreted as multiple commands, otherwise arguments
103
- # are joined as a single command.
104
- #
105
- # A trailing Hash is interpreted as options, see below.
106
- #
107
- # ==== options
108
- # :error:: Set the error handling mode: If `:exit`, causes "set -e" to
109
- # be passed as the first line of a multi-line
110
- # command. (Default: :exit)
111
- def run( *args )
112
- raise "Include a remoting-specific module, e.g. RemoteTask"
113
- end
114
-
115
- # Run args under sudo on remote host. A line delimited argument is
116
- # interpreted as multiple commands, otherwise arguments are joined
117
- # as a single command.
118
- #
119
- # A trailing Hash is interpreted as options, see below.
120
- #
121
- # ==== options
122
- # :user:: Run as specified user (default: root)
123
- # :flags:: Additional sudo flags
124
- # :shell:: Run command in a shell by wrapping it in sh -c "", and
125
- # escaping quotes in the original joined args command.
126
- # (default: true)
127
- # :error:: Set the error handling mode: If `:exit`, causes "set -e" to
128
- # be passed as the first line of a multi-line
129
- # command. (Default: :exit, only applies if :shell)
130
- def sudo( *args )
131
- raise "Include a remoting-specific module, e.g. RemoteTask"
132
- end
133
-
134
- # Return the exit status of the first non-zero command result, or 0
135
- # if all commands succeeded.
136
- def exec_conditional
137
- raise "Include a remoting-specific module, e.g. RemoteTask"
138
- end
139
-
140
- # Implement rsync as used by rput. Note that args should not be
141
- # passed through shell interpretation, eg run via system( Array )
142
- def rsync( *args )
143
- raise "Include a remoting-specific module, e.g. RemoteTask"
144
- end
145
-
146
- # Returns the current target host when called from a running task.
147
- def target_host
148
- raise "Include a remoting-specific module, e.g. RemoteTask"
149
- end
150
-
151
- def deep_merge_hashes( h1, h2 )
152
- h1.merge( h2 ) do |key, v1, v2|
153
- if v1.is_a?( Hash ) && v2.is_a?( Hash )
154
- deep_merge_hashes( v1, v2 )
155
- else
156
- v2
157
- end
158
- end
159
- end
160
-
161
- end
data/lib/syncwrap/ec2.rb DELETED
@@ -1,59 +0,0 @@
1
- #--
2
- # Copyright (c) 2011-2013 David Kellum
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License"); you
5
- # may not use this file except in compliance with the License. You may
6
- # obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
- # implied. See the License for the specific language governing
14
- # permissions and limitations under the License.
15
- #++
16
-
17
- require 'syncwrap/common'
18
-
19
- # Provisions for common Amazon EC2 image tasks.
20
- module SyncWrap::EC2
21
- include SyncWrap::Common
22
-
23
- # The device name of the ephemeral storage device
24
- # (default: 'xvdb')
25
- attr_accessor :ec2_es_device
26
-
27
- def initialize
28
- super
29
-
30
- @ec2_es_device = 'xvdb'
31
- end
32
-
33
- # WARNING: Destructive if run!
34
- # Re-mkfs /mnt partition as ext4 if its ec2_es_device and is
35
- # currently ext3
36
- def ec2_reformat_mnt_as_ext4
37
- rc = exec_conditional do
38
- run "mount | grep '/dev/#{ec2_es_device} on /mnt'"
39
- end
40
- raise "Device /dev/#{ec2_es_device} not mounted on /mnt" unless rc == 0
41
-
42
- rc = exec_conditional do
43
- run "mount | grep '/dev/#{ec2_es_device} on /mnt type ext3'"
44
- end
45
- ec2_reformat_mnt_as_ext4! if rc == 0
46
- end
47
-
48
- # WARNING: Destructive!
49
- # Re-mkfs /mnt partition as ext4
50
- # See: http://serverfault.com/questions/317009
51
- def ec2_reformat_mnt_as_ext4!
52
- sudo <<-SH
53
- umount /mnt
54
- mkfs -t ext4 /dev/#{ec2_es_device}
55
- mount /mnt
56
- SH
57
- end
58
-
59
- end