syncwrap 1.5.2 → 2.0.0

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