rubber 1.11.0 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +20 -0
- data/VERSION +1 -1
- data/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +7 -1
- data/lib/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +7 -1
- data/lib/rubber.rb +1 -0
- data/lib/rubber/instance.rb +25 -6
- data/lib/rubber/recipes/rubber.rb +5 -2
- data/lib/rubber/recipes/rubber/instances.rb +148 -62
- data/lib/rubber/thread_safe_proxy.rb +21 -0
- data/lib/rubber/util.rb +16 -0
- data/test/instance_test.rb +42 -0
- metadata +4 -30
data/CHANGELOG
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
1.11.0
|
2
|
+
-----
|
3
|
+
|
4
|
+
Regenerate gemspec for version 1.11.0 <1358116> [Kevin Menard]
|
5
|
+
We've been using RVM for a while now, so time to kill that warning message. <1d29137> [Kevin Menard]
|
6
|
+
Make the generated Rakefile play nicer with bundler and rubber transformation. <90f6702> [Kevin Menard]
|
7
|
+
Truly make the DBPASS field optional. <ba0aa56> [Kevin Menard]
|
8
|
+
Allow creation of LVM volumes over ephemeral devices. <319e80b> [Kevin Menard]
|
9
|
+
Bumped passenger version. <d4b4950> [Kevin Menard]
|
10
|
+
add detach volume <9daa912> [Matt Conway]
|
11
|
+
fix passing of passwd to mysqldump <143d467> [Matt Conway]
|
12
|
+
Added new feature to lock down the version of RubyGems installed on a cluster by RVM. <652f908> [Kevin Menard]
|
13
|
+
Bumped the version of RVM so we can get the latest security fix releases of Ruby. <9fb2383> [Kevin Menard]
|
14
|
+
Merge branch 'master' of github.com:wr0ngway/rubber <58d3209> [Kevin Menard]
|
15
|
+
Upgraded redis to 2.2.1. <aa0aa31> [Kevin Menard]
|
16
|
+
Bumped Passenger to version 3.0.3. <cad658a> [Kevin Menard]
|
17
|
+
sphinx default port has changed to 9312 <eee2bd0> [Nick Plante]
|
18
|
+
Merge branch 'master' of https://github.com/wr0ngway/rubber <2ff0188> [Nick Plante]
|
19
|
+
fix file write for db restoration <15fe2e0> [Nick Plante]
|
20
|
+
|
1
21
|
1.10.2
|
2
22
|
-----
|
3
23
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.12.0
|
@@ -9,8 +9,14 @@ namespace :rubber do
|
|
9
9
|
|
10
10
|
task :custom_install, :roles => :passenger do
|
11
11
|
rubber.sudo_script 'install_passenger', <<-ENDSCRIPT
|
12
|
-
|
12
|
+
# can't use passenger_lib from rubber here as it only evaluates correctly
|
13
|
+
# when variable interpolation of rvm_gem_home is run remotely, and since we
|
14
|
+
# are in cap, we run the interpolation locally
|
15
|
+
#
|
16
|
+
passenger_lib=$(find /usr/local/rvm -path "*/passenger-#{rubber_env.passenger_version}/*/mod_passenger.so" 2> /dev/null)
|
17
|
+
if [[ -z $passenger_lib ]]; then
|
13
18
|
echo -en "\n\n\n\n" | passenger-install-apache2-module
|
19
|
+
rvm #{rubber_env.rvm_ruby} --passenger
|
14
20
|
fi
|
15
21
|
ENDSCRIPT
|
16
22
|
end
|
@@ -9,8 +9,14 @@ namespace :rubber do
|
|
9
9
|
|
10
10
|
task :custom_install, :roles => :passenger do
|
11
11
|
rubber.sudo_script 'install_passenger', <<-ENDSCRIPT
|
12
|
-
|
12
|
+
# can't use passenger_lib from rubber here as it only evaluates correctly
|
13
|
+
# when variable interpolation of rvm_gem_home is run remotely, and since we
|
14
|
+
# are in cap, we run the interpolation locally
|
15
|
+
#
|
16
|
+
passenger_lib=$(find /usr/local/rvm -path "*/passenger-#{rubber_env.passenger_version}/*/mod_passenger.so" 2> /dev/null)
|
17
|
+
if [[ -z $passenger_lib ]]; then
|
13
18
|
echo -en "\n\n\n\n" | passenger-install-apache2-module
|
19
|
+
rvm #{rubber_env.rvm_ruby} --passenger
|
14
20
|
fi
|
15
21
|
ENDSCRIPT
|
16
22
|
end
|
data/lib/rubber.rb
CHANGED
data/lib/rubber/instance.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'monitor'
|
2
3
|
|
3
4
|
module Rubber
|
4
5
|
module Configuration
|
@@ -8,18 +9,20 @@ module Rubber
|
|
8
9
|
class Instance
|
9
10
|
attr_reader :file, :artifacts
|
10
11
|
include Enumerable
|
12
|
+
include MonitorMixin
|
11
13
|
|
12
14
|
def initialize(file)
|
15
|
+
super
|
13
16
|
Rubber.logger.debug{"Reading rubber instances from #{file}"}
|
14
17
|
@file = file
|
15
18
|
@items = {}
|
16
19
|
@artifacts = {'volumes' => {}, 'static_ips' => {}}
|
17
20
|
|
18
|
-
@filters = ENV['FILTER']
|
21
|
+
@filters = Rubber::Util::parse_aliases(ENV['FILTER'])
|
19
22
|
@filters, @filters_negated = @filters.partition {|f| f !~ /^-/ }
|
20
23
|
@filters_negated = @filters_negated.collect {|f| f[1..-1] }
|
21
24
|
|
22
|
-
@filter_roles = ENV['FILTER_ROLES']
|
25
|
+
@filter_roles = Rubber::Util::parse_aliases(ENV['FILTER_ROLES'])
|
23
26
|
@filter_roles, @filter_roles_negated = @filter_roles.partition {|f| f !~ /^-/ }
|
24
27
|
@filter_roles_negated = @filter_roles_negated.collect {|f| f[1..-1] }
|
25
28
|
|
@@ -38,10 +41,12 @@ module Rubber
|
|
38
41
|
end
|
39
42
|
|
40
43
|
def save()
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
synchronize do
|
45
|
+
data = []
|
46
|
+
data.push(*@items.values)
|
47
|
+
data.push(@artifacts)
|
48
|
+
File.open(@file, "w") { |f| f.write(YAML.dump(data)) }
|
49
|
+
end
|
45
50
|
end
|
46
51
|
|
47
52
|
def [](name)
|
@@ -57,6 +62,8 @@ module Rubber
|
|
57
62
|
def filtered()
|
58
63
|
filtered_results = []
|
59
64
|
|
65
|
+
validate_filters()
|
66
|
+
|
60
67
|
if @filters.size == 0 && @filter_roles.size == 0
|
61
68
|
filtered_results.concat(@items.values)
|
62
69
|
else
|
@@ -72,6 +79,18 @@ module Rubber
|
|
72
79
|
return filtered_results
|
73
80
|
end
|
74
81
|
|
82
|
+
def validate_filters()
|
83
|
+
aliases = @items.values.collect{|ic| ic.name}
|
84
|
+
[@filters, @filters_negated].flatten.each do |f|
|
85
|
+
raise "Filter doesn't match any hosts: #{f}" if ! aliases.include?(f)
|
86
|
+
end
|
87
|
+
|
88
|
+
roles = all_roles
|
89
|
+
[@filter_roles, @filter_roles_negated].flatten.each do |f|
|
90
|
+
raise "Filter doesn't match any roles: #{f}" if ! roles.include?(f)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
75
94
|
def all_roles()
|
76
95
|
@items.collect {|n, i| i.role_names}.flatten.uniq
|
77
96
|
end
|
@@ -53,9 +53,12 @@ namespace :rubber do
|
|
53
53
|
# Disable connecting to any Windows instance.
|
54
54
|
# pass -l to bash in :shell to that run also gets full env
|
55
55
|
# use a pty so we don't get "stdin: is not a tty" error output
|
56
|
-
|
56
|
+
default_run_options[:pty] = true
|
57
|
+
default_run_options[:shell] = "/bin/bash -l"
|
58
|
+
default_run_options[:except] = { :platform => 'windows' }
|
57
59
|
|
58
|
-
|
60
|
+
# sharing a Net::HTTP instance across threads doesn't work, so create a new instance per thread
|
61
|
+
set :cloud, Rubber::ThreadSafeProxy.new { Rubber::Cloud::get_provider(rubber_env.cloud_provider || "aws", rubber_env, self) }
|
59
62
|
|
60
63
|
load_roles() unless rubber_env.disable_auto_roles
|
61
64
|
# NOTE: for some reason Capistrano requires you to have both the public and
|
@@ -4,13 +4,21 @@ namespace :rubber do
|
|
4
4
|
Create a new EC2 instance with the given ALIAS and ROLES
|
5
5
|
DESC
|
6
6
|
required_task :create do
|
7
|
-
|
7
|
+
instance_aliases = get_env('ALIAS', "Instance alias (e.g. web01 or web01~web05,web09)", true)
|
8
|
+
|
9
|
+
aliases = Rubber::Util::parse_aliases(instance_aliases)
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
if aliases.size > 1
|
12
|
+
default_roles = "roles for instance in *.yml"
|
13
|
+
r = get_env("ROLES", "Instance roles (e.g. web,app,db:primary=true)", false, default_roles)
|
14
|
+
r = "" if r == default_roles
|
15
|
+
else
|
16
|
+
env = rubber_cfg.environment.bind(nil, aliases.first)
|
17
|
+
default_roles = env.instance_roles
|
18
|
+
r = get_env("ROLES", "Instance roles (e.g. web,app,db:primary=true)", true, default_roles)
|
19
|
+
end
|
12
20
|
|
13
|
-
create_spot_instance = ENV.delete("SPOT_INSTANCE")
|
21
|
+
create_spot_instance = ENV.delete("SPOT_INSTANCE")
|
14
22
|
|
15
23
|
if r == '*'
|
16
24
|
instance_roles = rubber_cfg.environment.known_roles
|
@@ -18,24 +26,8 @@ namespace :rubber do
|
|
18
26
|
else
|
19
27
|
instance_roles = r.split(",")
|
20
28
|
end
|
21
|
-
|
22
|
-
|
23
|
-
instance_roles.each do |r|
|
24
|
-
role = Rubber::Configuration::RoleItem.parse(r)
|
25
|
-
|
26
|
-
# If user doesn't setup a primary db, then be nice and do it
|
27
|
-
if role.name == "db" && role.options["primary"] == nil && rubber_instances.for_role("db").size == 0
|
28
|
-
value = Capistrano::CLI.ui.ask("You do not have a primary db role, should #{instance_alias} be it [y/n]?: ")
|
29
|
-
role.options["primary"] = true if value =~ /^y/
|
30
|
-
end
|
31
|
-
|
32
|
-
ir << role
|
33
|
-
end
|
34
|
-
|
35
|
-
# Add in roles that the given set of roles depends on
|
36
|
-
ir = Rubber::Configuration::RoleItem.expand_role_dependencies(ir, get_role_dependencies)
|
37
|
-
|
38
|
-
create_instance(instance_alias, ir, create_spot_instance)
|
29
|
+
|
30
|
+
create_instances(aliases, instance_roles, create_spot_instance)
|
39
31
|
end
|
40
32
|
|
41
33
|
desc <<-DESC
|
@@ -43,18 +35,25 @@ namespace :rubber do
|
|
43
35
|
This is useful to run when rubber:create fails after instance creation
|
44
36
|
DESC
|
45
37
|
required_task :refresh do
|
46
|
-
|
38
|
+
instance_aliases = get_env('ALIAS', "Instance alias (e.g. web01 or web01~web05,web09)", true)
|
39
|
+
|
40
|
+
aliases = Rubber::Util::parse_aliases(instance_aliases)
|
41
|
+
|
47
42
|
ENV.delete('ROLES') # so we don't get an error if people leave ROLES in env from :create CLI
|
48
|
-
|
43
|
+
|
44
|
+
refresh_instances(aliases)
|
49
45
|
end
|
50
46
|
|
51
47
|
desc <<-DESC
|
52
48
|
Destroy the EC2 instance for the given ALIAS
|
53
49
|
DESC
|
54
50
|
required_task :destroy do
|
55
|
-
|
51
|
+
instance_aliases = get_env('ALIAS', "Instance alias (e.g. web01 or web01~web05,web09)", true)
|
52
|
+
|
53
|
+
aliases = Rubber::Util::parse_aliases(instance_aliases)
|
54
|
+
|
56
55
|
ENV.delete('ROLES') # so we don't get an error if people leave ROLES in env from :create CLI
|
57
|
-
|
56
|
+
destroy_instances(aliases, ENV['FORCE'] == 'true')
|
58
57
|
end
|
59
58
|
|
60
59
|
desc <<-DESC
|
@@ -178,25 +177,88 @@ namespace :rubber do
|
|
178
177
|
results.each {|r| logger.info r}
|
179
178
|
end
|
180
179
|
|
181
|
-
|
182
180
|
set :print_ip_command, "ifconfig eth0 | awk 'NR==2 {print $2}' | awk -F: '{print $2}'"
|
183
181
|
|
182
|
+
# Creates the set of new instancea after figuring out the roles for each
|
183
|
+
def create_instances(instance_aliases, instance_roles, create_spot_instance=false)
|
184
|
+
creation_threads = []
|
185
|
+
refresh_threads = []
|
186
|
+
|
187
|
+
instance_aliases.each do |instance_alias|
|
188
|
+
fatal "Instance already exists: #{instance_alias}" if rubber_instances[instance_alias]
|
189
|
+
|
190
|
+
ir = []
|
191
|
+
|
192
|
+
roles = instance_roles
|
193
|
+
if roles.size == 0
|
194
|
+
env = rubber_cfg.environment.bind(nil, instance_alias)
|
195
|
+
roles = env.instance_roles.split(",") rescue []
|
196
|
+
end
|
197
|
+
|
198
|
+
roles.each do |r|
|
199
|
+
role = Rubber::Configuration::RoleItem.parse(r)
|
200
|
+
|
201
|
+
# If user doesn't setup a primary db, then be nice and do it
|
202
|
+
if role.name == "db" && role.options["primary"] == nil && rubber_instances.for_role("db").size == 0
|
203
|
+
value = Capistrano::CLI.ui.ask("You do not have a primary db role, should #{instance_alias} be it [y/n]?: ")
|
204
|
+
role.options["primary"] = true if value =~ /^y/
|
205
|
+
end
|
206
|
+
|
207
|
+
ir << role
|
208
|
+
end
|
209
|
+
|
210
|
+
# Add in roles that the given set of roles depends on
|
211
|
+
ir = Rubber::Configuration::RoleItem.expand_role_dependencies(ir, get_role_dependencies)
|
212
|
+
|
213
|
+
creation_threads << Thread.new do
|
214
|
+
create_instance(instance_alias, ir, create_spot_instance)
|
215
|
+
|
216
|
+
refresh_threads << Thread.new do
|
217
|
+
while ! refresh_instance(instance_alias)
|
218
|
+
sleep 1
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
sleep 2
|
224
|
+
end
|
225
|
+
|
226
|
+
creation_threads.each {|t| t.join }
|
227
|
+
|
228
|
+
print "Waiting for instances to start"
|
229
|
+
|
230
|
+
while true do
|
231
|
+
print "."
|
232
|
+
sleep 2
|
233
|
+
|
234
|
+
break if refresh_threads.all? {|t| ! t.alive? }
|
235
|
+
end
|
236
|
+
|
237
|
+
refresh_threads.each {|t| t.join }
|
238
|
+
|
239
|
+
post_refresh
|
240
|
+
end
|
241
|
+
|
242
|
+
set :mutex, Mutex.new
|
243
|
+
|
184
244
|
# Creates a new ec2 instance with the given alias and roles
|
185
245
|
# Configures aliases (/etc/hosts) on local and remote machines
|
186
|
-
def create_instance(instance_alias, instance_roles, create_spot_instance
|
187
|
-
fatal "Instance already exists: #{instance_alias}" if rubber_instances[instance_alias]
|
188
|
-
|
246
|
+
def create_instance(instance_alias, instance_roles, create_spot_instance)
|
189
247
|
role_names = instance_roles.collect{|x| x.name}
|
190
248
|
env = rubber_cfg.environment.bind(role_names, instance_alias)
|
191
249
|
|
192
250
|
# We need to use security_groups during create, so create them up front
|
193
|
-
|
251
|
+
mutex.synchronize do
|
252
|
+
setup_security_groups(instance_alias, role_names)
|
253
|
+
end
|
194
254
|
security_groups = get_assigned_security_groups(instance_alias, role_names)
|
195
255
|
|
196
256
|
ami = env.cloud_providers[env.cloud_provider].image_id
|
197
257
|
ami_type = env.cloud_providers[env.cloud_provider].image_type
|
198
258
|
availability_zone = env.availability_zone
|
199
259
|
|
260
|
+
create_spot_instance ||= env.cloud_providers[env.cloud_provider].spot_instance
|
261
|
+
|
200
262
|
if create_spot_instance
|
201
263
|
spot_price = env.cloud_providers[env.cloud_provider].spot_price.to_s
|
202
264
|
|
@@ -231,7 +293,7 @@ namespace :rubber do
|
|
231
293
|
instance_id = cloud.create_instance(ami, ami_type, security_groups, availability_zone)
|
232
294
|
end
|
233
295
|
|
234
|
-
logger.info "Instance #{
|
296
|
+
logger.info "Instance #{instance_alias} created: #{instance_id}"
|
235
297
|
|
236
298
|
instance_item = Rubber::Configuration::InstanceItem.new(instance_alias, env.domain, instance_roles, instance_id, security_groups)
|
237
299
|
instance_item.spot_instance_request_id = request_id if create_spot_instance
|
@@ -246,14 +308,22 @@ namespace :rubber do
|
|
246
308
|
sleep 0.5
|
247
309
|
retry
|
248
310
|
end
|
311
|
+
end
|
249
312
|
|
250
|
-
|
251
|
-
|
252
|
-
print "."
|
253
|
-
sleep 2
|
313
|
+
def refresh_instances(instance_aliases)
|
314
|
+
refresh_threads = []
|
254
315
|
|
255
|
-
|
316
|
+
instance_aliases.each do |instance_alias|
|
317
|
+
refresh_threads << Thread.new do
|
318
|
+
while ! refresh_instance(instance_alias)
|
319
|
+
sleep 1
|
320
|
+
end
|
321
|
+
end
|
256
322
|
end
|
323
|
+
|
324
|
+
refresh_threads.each {|t| t.join }
|
325
|
+
|
326
|
+
post_refresh
|
257
327
|
end
|
258
328
|
|
259
329
|
# Refreshes a ec2 instance with the given alias
|
@@ -296,46 +366,57 @@ namespace :rubber do
|
|
296
366
|
end
|
297
367
|
end
|
298
368
|
|
299
|
-
|
300
|
-
|
369
|
+
return true
|
370
|
+
end
|
371
|
+
return false
|
372
|
+
end
|
301
373
|
|
302
|
-
|
303
|
-
|
304
|
-
setup_local_aliases
|
374
|
+
def post_refresh
|
375
|
+
env = rubber_cfg.environment.bind(nil, nil)
|
305
376
|
|
306
|
-
|
307
|
-
|
377
|
+
# setup amazon elastic ips if configured to do so
|
378
|
+
setup_static_ips
|
308
379
|
|
309
|
-
|
380
|
+
# Need to setup aliases so ssh doesn't give us errors when we
|
381
|
+
# later try to connect to same ip but using alias
|
382
|
+
setup_local_aliases
|
310
383
|
|
311
|
-
|
312
|
-
|
313
|
-
|
384
|
+
# re-load the roles since we may have just defined new ones
|
385
|
+
load_roles() unless env.disable_auto_roles
|
386
|
+
|
387
|
+
rubber_instances.save()
|
314
388
|
|
315
|
-
|
316
|
-
|
317
|
-
|
389
|
+
# Add the aliases for this instance to all other hosts
|
390
|
+
setup_remote_aliases
|
391
|
+
setup_dns_aliases
|
318
392
|
end
|
319
393
|
|
394
|
+
def destroy_instances(instance_aliases, force=false)
|
395
|
+
instance_aliases.each do |instance_alias|
|
396
|
+
destroy_instance(instance_alias, force)
|
397
|
+
end
|
398
|
+
|
399
|
+
post_destroy
|
400
|
+
end
|
320
401
|
|
321
402
|
# Destroys the given ec2 instance
|
322
|
-
def destroy_instance(instance_alias)
|
403
|
+
def destroy_instance(instance_alias, force=false)
|
323
404
|
instance_item = rubber_instances[instance_alias]
|
324
405
|
fatal "Instance does not exist: #{instance_alias}" if ! instance_item
|
325
406
|
|
326
407
|
env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
|
327
408
|
|
328
|
-
value = Capistrano::CLI.ui.ask("About to DESTROY #{instance_alias} (#{instance_item.instance_id}) in mode #{RUBBER_ENV}. Are you SURE [yes/NO]?: ")
|
329
|
-
fatal("Exiting", 0) if value != "yes"
|
409
|
+
value = Capistrano::CLI.ui.ask("About to DESTROY #{instance_alias} (#{instance_item.instance_id}) in mode #{RUBBER_ENV}. Are you SURE [yes/NO]?: ") unless force
|
410
|
+
fatal("Exiting", 0) if value != "yes" && ! force
|
330
411
|
|
331
412
|
if instance_item.static_ip
|
332
|
-
value = Capistrano::CLI.ui.ask("Instance has a static ip, do you want to release it? [y/N]?: ")
|
333
|
-
destroy_static_ip(instance_item.static_ip) if value =~ /^y/
|
413
|
+
value = Capistrano::CLI.ui.ask("Instance has a static ip, do you want to release it? [y/N]?: ") unless force
|
414
|
+
destroy_static_ip(instance_item.static_ip) if value =~ /^y/ || force
|
334
415
|
end
|
335
416
|
|
336
417
|
if instance_item.volumes
|
337
|
-
value = Capistrano::CLI.ui.ask("Instance has persistent volumes, do you want to destroy them? [y/N]?: ")
|
338
|
-
if value =~ /^y/
|
418
|
+
value = Capistrano::CLI.ui.ask("Instance has persistent volumes, do you want to destroy them? [y/N]?: ") unless force
|
419
|
+
if value =~ /^y/ || force
|
339
420
|
instance_item.volumes.clone.each do |volume_id|
|
340
421
|
destroy_volume(volume_id)
|
341
422
|
end
|
@@ -349,15 +430,20 @@ namespace :rubber do
|
|
349
430
|
rubber_instances.remove(instance_alias)
|
350
431
|
rubber_instances.save()
|
351
432
|
|
433
|
+
destroy_dyndns(instance_item)
|
434
|
+
cleanup_known_hosts(instance_item) unless env.disable_known_hosts_cleanup
|
435
|
+
end
|
436
|
+
|
437
|
+
def post_destroy
|
438
|
+
env = rubber_cfg.environment.bind(nil, nil)
|
439
|
+
|
352
440
|
# re-load the roles since we just removed some and setup_remote_aliases
|
353
441
|
# shouldn't hit removed ones
|
354
442
|
load_roles() unless env.disable_auto_roles
|
355
443
|
|
356
444
|
setup_aliases
|
357
|
-
destroy_dyndns(instance_item)
|
358
|
-
cleanup_known_hosts(instance_item) unless env.disable_known_hosts_cleanup
|
359
445
|
end
|
360
|
-
|
446
|
+
|
361
447
|
# Reboots the given ec2 instance
|
362
448
|
def reboot_instance(instance_alias)
|
363
449
|
instance_item = rubber_instances[instance_alias]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module Rubber
|
3
|
+
class ThreadSafeProxy
|
4
|
+
instance_methods.each { |m| undef_method m unless m =~ /(^__|^send$|^object_id$)/ }
|
5
|
+
|
6
|
+
def initialize(&block)
|
7
|
+
@target_block = block
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def method_missing(name, *args, &block)
|
13
|
+
target.send(name, *args, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def target
|
17
|
+
Thread.current["thread_safe_proxy_target_#{object_id}"] ||= @target_block.call
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/rubber/util.rb
CHANGED
@@ -24,6 +24,22 @@ module Rubber
|
|
24
24
|
|
25
25
|
end
|
26
26
|
|
27
|
+
def self.parse_aliases(instance_aliases)
|
28
|
+
aliases = []
|
29
|
+
alias_patterns = instance_aliases.to_s.strip.split(/\s*,\s*/)
|
30
|
+
alias_patterns.each do |a|
|
31
|
+
if a =~ /~/
|
32
|
+
range = a.split(/~/)
|
33
|
+
range_items = (range.first..range.last).to_a
|
34
|
+
raise "Invalid range, '#{a}', sequence generated no items" if range_items.size == 0
|
35
|
+
aliases.concat(range_items)
|
36
|
+
else
|
37
|
+
aliases << a
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return aliases
|
41
|
+
end
|
42
|
+
|
27
43
|
# Opens the file for writing by root
|
28
44
|
def self.sudo_open(path, perms, &block)
|
29
45
|
open("|sudo tee #{path} > /dev/null", perms, &block)
|
data/test/instance_test.rb
CHANGED
@@ -51,6 +51,14 @@ class InstanceTest < Test::Unit::TestCase
|
|
51
51
|
setup
|
52
52
|
assert_equal [@i1], @instance.filtered(), 'should not have negated hosts'
|
53
53
|
|
54
|
+
ENV['FILTER'] = 'host1~host3'
|
55
|
+
setup
|
56
|
+
assert_equal [@i1, @i2, @i3], @instance.filtered(), 'should allow range in filter'
|
57
|
+
|
58
|
+
ENV['FILTER'] = '-host1~-host3'
|
59
|
+
setup
|
60
|
+
assert_equal [@i4], @instance.filtered(), 'should allow negative range in filter'
|
61
|
+
|
54
62
|
ENV['FILTER'] = '-host1'
|
55
63
|
ENV['FILTER_ROLES'] = 'role1'
|
56
64
|
setup
|
@@ -70,6 +78,40 @@ class InstanceTest < Test::Unit::TestCase
|
|
70
78
|
ENV['FILTER_ROLES'] = '-role1'
|
71
79
|
setup
|
72
80
|
assert_equal [@i3, @i4], @instance.filtered(), 'should not have negated roles'
|
81
|
+
|
82
|
+
ENV['FILTER_ROLES'] = 'role1~role2'
|
83
|
+
setup
|
84
|
+
assert_equal [@i1, @i2, @i3, @i4], @instance.filtered(), 'should allow range in filter'
|
85
|
+
|
86
|
+
ENV['FILTER_ROLES'] = '-role1~-role2'
|
87
|
+
setup
|
88
|
+
assert_equal [], @instance.filtered(), 'should allow negative range in filter'
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_validate_filters
|
92
|
+
ENV['FILTER'] = "nohost"
|
93
|
+
setup
|
94
|
+
assert_raises do
|
95
|
+
@instance.filtered()
|
96
|
+
end
|
97
|
+
|
98
|
+
ENV['FILTER'] = "-nohost"
|
99
|
+
setup
|
100
|
+
assert_raises do
|
101
|
+
@instance.filtered()
|
102
|
+
end
|
103
|
+
|
104
|
+
ENV['FILTER_ROLES'] = "norole"
|
105
|
+
setup
|
106
|
+
assert_raises do
|
107
|
+
@instance.filtered()
|
108
|
+
end
|
109
|
+
|
110
|
+
ENV['FILTER_ROLES'] = "-norole"
|
111
|
+
setup
|
112
|
+
assert_raises do
|
113
|
+
@instance.filtered()
|
114
|
+
end
|
73
115
|
end
|
74
116
|
|
75
117
|
def test_equality
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 59
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 1
|
8
|
-
- 11
|
9
|
-
- 0
|
10
|
-
version: 1.11.0
|
5
|
+
version: 1.12.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Matt Conway
|
@@ -15,7 +10,7 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-03-
|
13
|
+
date: 2011-03-18 00:00:00 -04:00
|
19
14
|
default_executable: vulcanize
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
@@ -26,11 +21,6 @@ dependencies:
|
|
26
21
|
requirements:
|
27
22
|
- - ">="
|
28
23
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 31
|
30
|
-
segments:
|
31
|
-
- 2
|
32
|
-
- 4
|
33
|
-
- 0
|
34
24
|
version: 2.4.0
|
35
25
|
type: :runtime
|
36
26
|
version_requirements: *id001
|
@@ -42,11 +32,6 @@ dependencies:
|
|
42
32
|
requirements:
|
43
33
|
- - ">="
|
44
34
|
- !ruby/object:Gem::Version
|
45
|
-
hash: 25
|
46
|
-
segments:
|
47
|
-
- 0
|
48
|
-
- 9
|
49
|
-
- 17
|
50
35
|
version: 0.9.17
|
51
36
|
type: :runtime
|
52
37
|
version_requirements: *id002
|
@@ -58,9 +43,6 @@ dependencies:
|
|
58
43
|
requirements:
|
59
44
|
- - ">="
|
60
45
|
- !ruby/object:Gem::Version
|
61
|
-
hash: 3
|
62
|
-
segments:
|
63
|
-
- 0
|
64
46
|
version: "0"
|
65
47
|
type: :runtime
|
66
48
|
version_requirements: *id003
|
@@ -72,9 +54,6 @@ dependencies:
|
|
72
54
|
requirements:
|
73
55
|
- - ">="
|
74
56
|
- !ruby/object:Gem::Version
|
75
|
-
hash: 3
|
76
|
-
segments:
|
77
|
-
- 0
|
78
57
|
version: "0"
|
79
58
|
type: :runtime
|
80
59
|
version_requirements: *id004
|
@@ -474,6 +453,7 @@ files:
|
|
474
453
|
- lib/rubber/recipes/rubber/volumes.rb
|
475
454
|
- lib/rubber/tag.rb
|
476
455
|
- lib/rubber/tasks/rubber.rb
|
456
|
+
- lib/rubber/thread_safe_proxy.rb
|
477
457
|
- lib/rubber/util.rb
|
478
458
|
- rails/init.rb
|
479
459
|
- test/environment_test.rb
|
@@ -496,23 +476,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
496
476
|
requirements:
|
497
477
|
- - ">="
|
498
478
|
- !ruby/object:Gem::Version
|
499
|
-
hash: 3
|
500
|
-
segments:
|
501
|
-
- 0
|
502
479
|
version: "0"
|
503
480
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
504
481
|
none: false
|
505
482
|
requirements:
|
506
483
|
- - ">="
|
507
484
|
- !ruby/object:Gem::Version
|
508
|
-
hash: 3
|
509
|
-
segments:
|
510
|
-
- 0
|
511
485
|
version: "0"
|
512
486
|
requirements: []
|
513
487
|
|
514
488
|
rubyforge_project: rubber
|
515
|
-
rubygems_version: 1.
|
489
|
+
rubygems_version: 1.6.1
|
516
490
|
signing_key:
|
517
491
|
specification_version: 3
|
518
492
|
summary: A capistrano plugin for managing multi-instance deployments to the cloud (ec2)
|