sml-rubber 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +339 -0
- data/README +6 -0
- data/TODO +9 -0
- data/VERSION +1 -0
- data/generators/vulcanize/USAGE +6 -0
- data/generators/vulcanize/templates/apache/config/rubber/deploy-apache.rb +45 -0
- data/generators/vulcanize/templates/apache/config/rubber/role/web/deflate.conf +10 -0
- data/generators/vulcanize/templates/apache/config/rubber/role/web/expires.conf +9 -0
- data/generators/vulcanize/templates/apache/config/rubber/role/web/headers.conf +6 -0
- data/generators/vulcanize/templates/apache/config/rubber/role/web/setenvif.conf +52 -0
- data/generators/vulcanize/templates/apache/config/rubber/role/web/vhost.conf +27 -0
- data/generators/vulcanize/templates/apache/config/rubber/rubber-apache.yml +15 -0
- data/generators/vulcanize/templates/apache/templates.yml +1 -0
- data/generators/vulcanize/templates/base/Capfile +17 -0
- data/generators/vulcanize/templates/base/config/deploy.rb +77 -0
- data/generators/vulcanize/templates/base/config/rubber/common/crontab +16 -0
- data/generators/vulcanize/templates/base/config/rubber/common/profile.rc +9 -0
- data/generators/vulcanize/templates/base/config/rubber/deploy-setup.rb +56 -0
- data/generators/vulcanize/templates/base/config/rubber/rubber.yml +221 -0
- data/generators/vulcanize/templates/base/lib/tasks/rubber.rake +18 -0
- data/generators/vulcanize/templates/base/script/cron-rake +18 -0
- data/generators/vulcanize/templates/base/script/cron-runner +18 -0
- data/generators/vulcanize/templates/base/script/cron-sh +67 -0
- data/generators/vulcanize/templates/base/templates.yml +1 -0
- data/generators/vulcanize/templates/complete_mysql/templates.yml +6 -0
- data/generators/vulcanize/templates/complete_passenger_mysql/templates.yml +8 -0
- data/generators/vulcanize/templates/cruise/config/rubber/deploy-cruise.rb +74 -0
- data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/cruise +40 -0
- data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/my.cnf +165 -0
- data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/production.rb +8 -0
- data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/site_config.rb +76 -0
- data/generators/vulcanize/templates/cruise/config/rubber/role/web_tools/cruise-nginx.conf +11 -0
- data/generators/vulcanize/templates/cruise/config/rubber/rubber-cruise.yml +18 -0
- data/generators/vulcanize/templates/cruise/templates.yml +1 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/deploy-haproxy.rb +45 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy-default.conf +8 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy.conf +44 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/monit-haproxy.conf +9 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslog-haproxy.conf +6 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslogd-default.conf +17 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/role/web_tools/haproxy-nginx.conf +10 -0
- data/generators/vulcanize/templates/haproxy/config/rubber/rubber-haproxy.yml +12 -0
- data/generators/vulcanize/templates/haproxy/templates.yml +1 -0
- data/generators/vulcanize/templates/memcached/config/memcached.yml +28 -0
- data/generators/vulcanize/templates/memcached/config/rubber/common/memcached.yml +14 -0
- data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached.conf +52 -0
- data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached_munin_plugin +249 -0
- data/generators/vulcanize/templates/memcached/config/rubber/rubber-memcached.yml +7 -0
- data/generators/vulcanize/templates/memcached/templates.yml +1 -0
- data/generators/vulcanize/templates/minimal_mysql/templates.yml +7 -0
- data/generators/vulcanize/templates/minimal_nodb/templates.yml +6 -0
- data/generators/vulcanize/templates/mongrel/config/rubber/deploy-mongrel.rb +75 -0
- data/generators/vulcanize/templates/mongrel/config/rubber/role/app/mongrel_cluster.yml +12 -0
- data/generators/vulcanize/templates/mongrel/config/rubber/role/app/monit-mongrel.conf +20 -0
- data/generators/vulcanize/templates/mongrel/config/rubber/rubber-mongrel.yml +9 -0
- data/generators/vulcanize/templates/mongrel/templates.yml +1 -0
- data/generators/vulcanize/templates/monit/config/rubber/common/monit-default.conf +15 -0
- data/generators/vulcanize/templates/monit/config/rubber/common/monit.conf +251 -0
- data/generators/vulcanize/templates/monit/config/rubber/deploy-monit.rb +32 -0
- data/generators/vulcanize/templates/monit/config/rubber/role/web_tools/monit-admin-nginx.conf +10 -0
- data/generators/vulcanize/templates/monit/config/rubber/rubber-monit.yml +6 -0
- data/generators/vulcanize/templates/monit/templates.yml +1 -0
- data/generators/vulcanize/templates/munin/config/rubber/common/monit-munin.conf +8 -0
- data/generators/vulcanize/templates/munin/config/rubber/common/munin-node.conf +48 -0
- data/generators/vulcanize/templates/munin/config/rubber/deploy-munin.rb +30 -0
- data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-nginx.conf +8 -0
- data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-plugins.conf +31 -0
- data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin.conf +80 -0
- data/generators/vulcanize/templates/munin/config/rubber/rubber-munin.yml +8 -0
- data/generators/vulcanize/templates/munin/script/munin/example_mysql_query.rb +57 -0
- data/generators/vulcanize/templates/munin/script/munin/example_simple.rb +24 -0
- data/generators/vulcanize/templates/munin/templates.yml +1 -0
- data/generators/vulcanize/templates/mysql/config/rubber/common/database.yml +11 -0
- data/generators/vulcanize/templates/mysql/config/rubber/deploy-mysql.rb +178 -0
- data/generators/vulcanize/templates/mysql/config/rubber/role/db/crontab +14 -0
- data/generators/vulcanize/templates/mysql/config/rubber/role/db/monit-mysql.cnf +10 -0
- data/generators/vulcanize/templates/mysql/config/rubber/role/db/my.cnf +167 -0
- data/generators/vulcanize/templates/mysql/config/rubber/role/mysql_slave/mysql_slave_munin_plugin +51 -0
- data/generators/vulcanize/templates/mysql/config/rubber/rubber-mysql.yml +38 -0
- data/generators/vulcanize/templates/mysql/templates.yml +1 -0
- data/generators/vulcanize/templates/mysql_cluster/config/rubber/common/mysql_cluster_migrations.rb +13 -0
- data/generators/vulcanize/templates/mysql_cluster/config/rubber/deploy-mysql_cluster.rb +173 -0
- data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_data/my.cnf +15 -0
- data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_mgm/ndb_mgmd.cnf +39 -0
- data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/monit-mysql_cluster_sql.cnf +10 -0
- data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/my.cnf +23 -0
- data/generators/vulcanize/templates/mysql_cluster/config/rubber/rubber-mysql_cluster.yml +32 -0
- data/generators/vulcanize/templates/mysql_cluster/templates.yml +1 -0
- data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/database.yml +16 -0
- data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/monit-mysql_proxy.cnf +10 -0
- data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy +153 -0
- data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.conf +10 -0
- data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.lua +5 -0
- data/generators/vulcanize/templates/mysql_proxy/config/rubber/deploy-mysql_proxy.rb +52 -0
- data/generators/vulcanize/templates/mysql_proxy/config/rubber/rubber-mysql_proxy.yml +11 -0
- data/generators/vulcanize/templates/mysql_proxy/templates.yml +1 -0
- data/generators/vulcanize/templates/nginx/config/rubber/deploy-nginx.rb +45 -0
- data/generators/vulcanize/templates/nginx/config/rubber/role/web/crontab +9 -0
- data/generators/vulcanize/templates/nginx/config/rubber/role/web/monit-nginx.conf +9 -0
- data/generators/vulcanize/templates/nginx/config/rubber/role/web/nginx.conf +133 -0
- data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/index.html +23 -0
- data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/nginx-tools.conf +74 -0
- data/generators/vulcanize/templates/nginx/config/rubber/rubber-nginx.yml +33 -0
- data/generators/vulcanize/templates/nginx/templates.yml +1 -0
- data/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +27 -0
- data/generators/vulcanize/templates/passenger/config/rubber/role/web/passenger.conf +8 -0
- data/generators/vulcanize/templates/passenger/config/rubber/rubber-passenger.yml +4 -0
- data/generators/vulcanize/templates/passenger/templates.yml +1 -0
- data/generators/vulcanize/templates/sphinx/config/rubber/common/sphinx.yml +46 -0
- data/generators/vulcanize/templates/sphinx/config/rubber/deploy-sphinx.rb +112 -0
- data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/crontab +11 -0
- data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/monit-sphinx.conf +10 -0
- data/generators/vulcanize/templates/sphinx/config/rubber/rubber-sphinx.yml +6 -0
- data/generators/vulcanize/templates/sphinx/templates.yml +1 -0
- data/generators/vulcanize/vulcanize_generator.rb +67 -0
- data/lib/capistrano/hostcmd.rb +12 -0
- data/lib/rubber.rb +37 -0
- data/lib/rubber/capistrano.rb +1 -0
- data/lib/rubber/cloud.rb +13 -0
- data/lib/rubber/cloud/aws.rb +261 -0
- data/lib/rubber/cloud/base.rb +16 -0
- data/lib/rubber/configuration.rb +47 -0
- data/lib/rubber/dns.rb +13 -0
- data/lib/rubber/dns/base.rb +69 -0
- data/lib/rubber/dns/dyndns.rb +63 -0
- data/lib/rubber/dns/nettica.rb +56 -0
- data/lib/rubber/dns/zerigo.rb +121 -0
- data/lib/rubber/environment.rb +161 -0
- data/lib/rubber/generator.rb +197 -0
- data/lib/rubber/instance.rb +113 -0
- data/lib/rubber/recipes/rubber.rb +88 -0
- data/lib/rubber/recipes/rubber/bundles.rb +28 -0
- data/lib/rubber/recipes/rubber/deploy.rb +66 -0
- data/lib/rubber/recipes/rubber/instances.rb +298 -0
- data/lib/rubber/recipes/rubber/security_groups.rb +149 -0
- data/lib/rubber/recipes/rubber/setup.rb +285 -0
- data/lib/rubber/recipes/rubber/static_ips.rb +107 -0
- data/lib/rubber/recipes/rubber/utils.rb +195 -0
- data/lib/rubber/recipes/rubber/volumes.rb +263 -0
- data/lib/rubber/tasks/rubber.rb +218 -0
- data/lib/rubber/util.rb +33 -0
- data/test/environment_test.rb +118 -0
- data/test/generator_test.rb +323 -0
- data/test/instance_test.rb +38 -0
- data/test/test_helper.rb +4 -0
- data/test/util_test.rb +16 -0
- metadata +246 -0
@@ -0,0 +1,298 @@
|
|
1
|
+
namespace :rubber do
|
2
|
+
|
3
|
+
desc <<-DESC
|
4
|
+
Create a new EC2 instance with the given ALIAS and ROLES
|
5
|
+
DESC
|
6
|
+
required_task :create do
|
7
|
+
instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
|
8
|
+
r = get_env('ROLES', "Instance roles (e.g. web,app,db:primary=true)", true)
|
9
|
+
if r == '*'
|
10
|
+
instance_roles = rubber_cfg.environment.known_roles
|
11
|
+
instance_roles = instance_roles.collect {|role| role == "db" ? "db:primary=true" : role }
|
12
|
+
else
|
13
|
+
instance_roles = r.split(",")
|
14
|
+
end
|
15
|
+
|
16
|
+
ir = []
|
17
|
+
instance_roles.each do |r|
|
18
|
+
data = r.split(':');
|
19
|
+
role = Rubber::Configuration::RoleItem.new(data[0])
|
20
|
+
if data[1]
|
21
|
+
data[1].split(';').each do |pair|
|
22
|
+
p = pair.split('=')
|
23
|
+
val = case p[1]
|
24
|
+
when 'true' then true
|
25
|
+
when 'false' then false
|
26
|
+
else p[1] end
|
27
|
+
role.options[p[0]] = val
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# If user doesn't setup a primary db, then be nice and do it
|
32
|
+
if role.name == "db" && role.options["primary"] == nil && rubber_cfg.instance.for_role("db").size == 0
|
33
|
+
value = Capistrano::CLI.ui.ask("You do not have a primary db role, should #{instance_alias} be it [y/n]?: ")
|
34
|
+
role.options["primary"] = true if value =~ /^y/
|
35
|
+
end
|
36
|
+
|
37
|
+
ir << role
|
38
|
+
end
|
39
|
+
|
40
|
+
create_instance(instance_alias, ir)
|
41
|
+
end
|
42
|
+
|
43
|
+
desc <<-DESC
|
44
|
+
Refresh the host data for a EC2 instance with the given ALIAS.
|
45
|
+
This is useful to run when rubber:create fails after instance creation
|
46
|
+
DESC
|
47
|
+
task :refresh do
|
48
|
+
instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
|
49
|
+
ENV.delete('ROLES') # so we don't get an error if people leave ROLES in env from :create CLI
|
50
|
+
refresh_instance(instance_alias)
|
51
|
+
end
|
52
|
+
|
53
|
+
desc <<-DESC
|
54
|
+
Destroy the EC2 instance for the given ALIAS
|
55
|
+
DESC
|
56
|
+
task :destroy do
|
57
|
+
instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
|
58
|
+
ENV.delete('ROLES') # so we don't get an error if people leave ROLES in env from :create CLI
|
59
|
+
destroy_instance(instance_alias)
|
60
|
+
end
|
61
|
+
|
62
|
+
desc <<-DESC
|
63
|
+
Destroy ALL the EC2 instances for the current env
|
64
|
+
DESC
|
65
|
+
task :destroy_all do
|
66
|
+
rubber_cfg.instance.each do |ic|
|
67
|
+
destroy_instance(ic.name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
desc <<-DESC
|
72
|
+
List all your EC2 instances
|
73
|
+
DESC
|
74
|
+
required_task :describe do
|
75
|
+
results = []
|
76
|
+
format = "%-10s %-10s %-10s %-15s %-30s"
|
77
|
+
results << format % %w[InstanceID State Zone IP Alias\ (*=unknown)]
|
78
|
+
|
79
|
+
instances = cloud.describe_instances()
|
80
|
+
instances.each do |instance|
|
81
|
+
local_alias = find_alias(instance[:external_ip], instance[:id], instance[:state] == 'running')
|
82
|
+
results << format % [instance[:id], instance[:state], instance[:zone], instance[:external_ip] || "NoIP", local_alias || "Unknown"]
|
83
|
+
end
|
84
|
+
results.each {|r| logger.info r}
|
85
|
+
end
|
86
|
+
|
87
|
+
desc <<-DESC
|
88
|
+
Describes the availability zones
|
89
|
+
DESC
|
90
|
+
required_task :describe_zones do
|
91
|
+
results = []
|
92
|
+
format = "%-20s %-15s"
|
93
|
+
results << format % %w[Name State]
|
94
|
+
|
95
|
+
zones = cloud.describe_availability_zones()
|
96
|
+
zones.each do |zone|
|
97
|
+
results << format % [zone[:name], zone[:state]]
|
98
|
+
end
|
99
|
+
|
100
|
+
results.each {|r| logger.info r}
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
set :print_ip_command, "ifconfig eth0 | awk 'NR==2 {print $2}' | awk -F: '{print $2}'"
|
105
|
+
|
106
|
+
# Creates a new ec2 instance with the given alias and roles
|
107
|
+
# Configures aliases (/etc/hosts) on local and remote machines
|
108
|
+
def create_instance(instance_alias, instance_roles)
|
109
|
+
fatal "Instance already exists: #{instance_alias}" if rubber_cfg.instance[instance_alias]
|
110
|
+
|
111
|
+
role_names = instance_roles.collect{|x| x.name}
|
112
|
+
env = rubber_cfg.environment.bind(role_names, instance_alias)
|
113
|
+
|
114
|
+
# We need to use security_groups during create, so create them up front
|
115
|
+
security_groups = env.assigned_security_groups
|
116
|
+
security_group_defns = env.security_groups
|
117
|
+
if env.auto_security_groups
|
118
|
+
hosts = rubber_cfg.instance.collect{|ic| ic.name } + [instance_alias]
|
119
|
+
roles = (rubber_cfg.instance.all_roles + role_names).uniq
|
120
|
+
security_groups << instance_alias
|
121
|
+
security_groups += role_names
|
122
|
+
security_groups.uniq!
|
123
|
+
security_group_defns = inject_auto_security_groups(security_group_defns, hosts, roles)
|
124
|
+
sync_security_groups(security_group_defns)
|
125
|
+
else
|
126
|
+
sync_security_groups(security_group_defns)
|
127
|
+
end
|
128
|
+
|
129
|
+
ami = env.cloud_providers[env.cloud_provider].image_id
|
130
|
+
ami_type = env.cloud_providers[env.cloud_provider].image_type
|
131
|
+
availability_zone = env.availability_zone
|
132
|
+
logger.info "Creating instance #{ami}/#{ami_type}/#{security_groups.join(',') rescue 'Default'}/#{availability_zone || 'Default'}"
|
133
|
+
instance_id = cloud.create_instance(ami, ami_type, security_groups, availability_zone)
|
134
|
+
|
135
|
+
logger.info "Instance #{instance_id} created"
|
136
|
+
|
137
|
+
instance_item = Rubber::Configuration::InstanceItem.new(instance_alias, env.domain, instance_roles, instance_id)
|
138
|
+
rubber_cfg.instance.add(instance_item)
|
139
|
+
rubber_cfg.instance.save()
|
140
|
+
|
141
|
+
|
142
|
+
print "Waiting for instance to start"
|
143
|
+
while true do
|
144
|
+
print "."
|
145
|
+
sleep 2
|
146
|
+
instance = cloud.describe_instances(instance_id).first
|
147
|
+
|
148
|
+
if instance[:state] == "running"
|
149
|
+
print "\n"
|
150
|
+
logger.info "Instance running, fetching hostname/ip data"
|
151
|
+
instance_item.external_host = instance[:external_host]
|
152
|
+
instance_item.external_ip = instance[:external_ip]
|
153
|
+
instance_item.internal_host = instance[:internal_host]
|
154
|
+
rubber_cfg.instance.save()
|
155
|
+
|
156
|
+
# setup amazon elastic ips if configured to do so
|
157
|
+
setup_static_ips
|
158
|
+
|
159
|
+
# Need to setup aliases so ssh doesn't give us errors when we
|
160
|
+
# later try? to connect to same ip but using alias
|
161
|
+
setup_local_aliases
|
162
|
+
|
163
|
+
# re-load the roles since we may have just defined new ones
|
164
|
+
load_roles() unless env.disable_auto_roles
|
165
|
+
|
166
|
+
# Connect to newly created instance and grab its internal ip
|
167
|
+
# so that we can update all aliases
|
168
|
+
|
169
|
+
task :_get_ip, :hosts => instance_item.external_ip do
|
170
|
+
instance_item.internal_ip = capture(print_ip_command).strip
|
171
|
+
rubber_cfg.instance.save()
|
172
|
+
end
|
173
|
+
|
174
|
+
# even though instance is running, sometimes ssh hasn't started yet,
|
175
|
+
# so retry on connect failure
|
176
|
+
begin
|
177
|
+
_get_ip
|
178
|
+
rescue ConnectionError
|
179
|
+
sleep 2
|
180
|
+
logger.info "Failed to connect to #{instance_alias} (#{instance_item.external_ip}), retrying"
|
181
|
+
retry
|
182
|
+
end
|
183
|
+
|
184
|
+
# Add the aliases for this instance to all other hosts
|
185
|
+
setup_remote_aliases
|
186
|
+
setup_dns_aliases
|
187
|
+
|
188
|
+
break
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Refreshes a ec2 instance with the given alias
|
194
|
+
# Configures aliases (/etc/hosts) on local and remote machines
|
195
|
+
def refresh_instance(instance_alias)
|
196
|
+
instance_item = rubber_cfg.instance[instance_alias]
|
197
|
+
|
198
|
+
fatal "Instance does not exist: #{instance_alias}" if ! instance_item
|
199
|
+
|
200
|
+
env = rubber_cfg.environment.bind(instance_item.role_names, instance_alias)
|
201
|
+
|
202
|
+
instance = cloud.describe_instance(instance_item.instance_id).first
|
203
|
+
|
204
|
+
if instance[:state] == "running"
|
205
|
+
logger.info "\nInstance running, fetching hostname/ip data"
|
206
|
+
instance_item.external_host = instance[:external_host]
|
207
|
+
instance_item.external_ip = instance[:external_ip]
|
208
|
+
instance_item.internal_host = instance[:internal_host]
|
209
|
+
|
210
|
+
# Need to setup aliases so ssh doesn't give us errors when we
|
211
|
+
# later try to connect to same ip but using alias
|
212
|
+
setup_local_aliases
|
213
|
+
|
214
|
+
# re-load the roles since we may have just defined new ones
|
215
|
+
load_roles() unless env.disable_auto_roles
|
216
|
+
|
217
|
+
# Connect to newly created instance and grab its internal ip
|
218
|
+
# so that we can update all aliases
|
219
|
+
task :_get_ip, :hosts => instance_item.external_ip do
|
220
|
+
instance_item.internal_ip = capture(print_ip_command).strip
|
221
|
+
end
|
222
|
+
# even though instance is running, we need to give ssh a chance
|
223
|
+
# to get started
|
224
|
+
sleep 5
|
225
|
+
_get_ip
|
226
|
+
|
227
|
+
# Add the aliases for this instance to all other hosts
|
228
|
+
setup_remote_aliases
|
229
|
+
setup_dns_aliases
|
230
|
+
end
|
231
|
+
|
232
|
+
rubber_cfg.instance.save()
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
# Destroys the given ec2 instance
|
237
|
+
def destroy_instance(instance_alias)
|
238
|
+
instance_item = rubber_cfg.instance[instance_alias]
|
239
|
+
fatal "Instance does not exist: #{instance_alias}" if ! instance_item
|
240
|
+
|
241
|
+
env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
|
242
|
+
|
243
|
+
value = Capistrano::CLI.ui.ask("About to DESTROY #{instance_alias} (#{instance_item.instance_id}) in mode #{RUBBER_ENV}. Are you SURE [yes/NO]?: ")
|
244
|
+
fatal("Exiting", 0) if value != "yes"
|
245
|
+
|
246
|
+
if instance_item.static_ip
|
247
|
+
value = Capistrano::CLI.ui.ask("Instance has a static ip, do you want to release it? [y/N]?: ")
|
248
|
+
destroy_static_ip(instance_item.static_ip) if value =~ /^y/
|
249
|
+
end
|
250
|
+
|
251
|
+
if instance_item.volumes
|
252
|
+
value = Capistrano::CLI.ui.ask("Instance has persistent volumes, do you want to destroy them? [y/N]?: ")
|
253
|
+
if value =~ /^y/
|
254
|
+
instance_item.volumes.clone.each do |volume_id|
|
255
|
+
destroy_volume(volume_id)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
logger.info "Destroying instance alias=#{instance_alias}, instance_id=#{instance_item.instance_id}"
|
261
|
+
|
262
|
+
cloud.destroy_instance(instance_item.instance_id)
|
263
|
+
|
264
|
+
rubber_cfg.instance.remove(instance_alias)
|
265
|
+
rubber_cfg.instance.save()
|
266
|
+
|
267
|
+
# re-load the roles since we just removed some and setup_remote_aliases
|
268
|
+
# shouldn't hit removed ones
|
269
|
+
load_roles() unless env.disable_auto_roles
|
270
|
+
|
271
|
+
setup_aliases
|
272
|
+
destroy_dyndns(instance_item)
|
273
|
+
cleanup_known_hosts(instance_item) unless env.disable_known_hosts_cleanup
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
# delete from ~/.ssh/known_hosts all lines that begin with ec2- or instance_alias
|
278
|
+
def cleanup_known_hosts(instance_item)
|
279
|
+
logger.info "Cleaning ~/.ssh/known_hosts"
|
280
|
+
File.open(File.expand_path('~/.ssh/known_hosts'), 'r+') do |f|
|
281
|
+
out = ""
|
282
|
+
f.each do |line|
|
283
|
+
line = case line
|
284
|
+
when /^ec2-/; ''
|
285
|
+
when /#{instance_item.full_name}/; ''
|
286
|
+
when /#{instance_item.external_host}/; ''
|
287
|
+
when /#{instance_item.external_ip}/; ''
|
288
|
+
else line;
|
289
|
+
end
|
290
|
+
out << line
|
291
|
+
end
|
292
|
+
f.pos = 0
|
293
|
+
f.print out
|
294
|
+
f.truncate(f.pos)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
namespace :rubber do
|
2
|
+
|
3
|
+
desc <<-DESC
|
4
|
+
Sets up the network security groups
|
5
|
+
All defined groups will be created, and any not defined will be removed.
|
6
|
+
Likewise, rules within a group will get created, and those not will be removed
|
7
|
+
DESC
|
8
|
+
required_task :setup_security_groups do
|
9
|
+
env = rubber_cfg.environment.bind()
|
10
|
+
security_group_defns = env.security_groups
|
11
|
+
if env.auto_security_groups
|
12
|
+
hosts = rubber_cfg.instance.collect{|ic| ic.name }
|
13
|
+
roles = rubber_cfg.instance.all_roles
|
14
|
+
security_group_defns = inject_auto_security_groups(security_group_defns, hosts, roles)
|
15
|
+
sync_security_groups(security_group_defns)
|
16
|
+
else
|
17
|
+
sync_security_groups(security_group_defns)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
desc <<-DESC
|
22
|
+
Describes the network security groups
|
23
|
+
DESC
|
24
|
+
required_task :describe_security_groups do
|
25
|
+
groups = cloud.describe_security_groups()
|
26
|
+
groups.each do |group|
|
27
|
+
puts "#{group[:name]}, #{group[:description]}"
|
28
|
+
group[:permissions].each do |perm|
|
29
|
+
puts " protocol: #{perm[:protocol]}"
|
30
|
+
puts " from_port: #{perm[:from_port]}"
|
31
|
+
puts " to_port: #{perm[:to_port]}"
|
32
|
+
puts " source_groups: #{perm[:source_groups].collect {|g| g[:name]}.join(", ") }" if perm[:source_groups]
|
33
|
+
puts " source_ips: #{perm[:source_ips].join(", ") }" if perm[:source_ips]
|
34
|
+
puts "\n"
|
35
|
+
end if group[:permissions]
|
36
|
+
puts "\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def inject_auto_security_groups(groups, hosts, roles)
|
42
|
+
hosts.each do |name|
|
43
|
+
group_name = name
|
44
|
+
groups[group_name] ||= {'description' => "Rubber automatic security group for host: #{name}", 'rules' => []}
|
45
|
+
end
|
46
|
+
roles.each do |name|
|
47
|
+
group_name = name
|
48
|
+
groups[group_name] ||= {'description' => "Rubber automatic security group for role: #{name}", 'rules' => []}
|
49
|
+
end
|
50
|
+
return groups
|
51
|
+
end
|
52
|
+
|
53
|
+
def sync_security_groups(groups)
|
54
|
+
env = rubber_cfg.environment.bind()
|
55
|
+
return unless groups
|
56
|
+
|
57
|
+
groups = Rubber::Util::stringify(groups)
|
58
|
+
group_keys = groups.keys.clone()
|
59
|
+
|
60
|
+
# For each group that does already exist in ec2
|
61
|
+
cloud_groups = cloud.describe_security_groups()
|
62
|
+
cloud_groups.each do |cloud_group|
|
63
|
+
group_name = cloud_group[:name]
|
64
|
+
if group_keys.delete(group_name)
|
65
|
+
# sync rules
|
66
|
+
logger.debug "Security Group already in ec2, syncing rules: #{group_name}"
|
67
|
+
group = groups[group_name]
|
68
|
+
rules = group['rules'].clone
|
69
|
+
rule_maps = []
|
70
|
+
|
71
|
+
# first collect the rule maps from the request (group/user pairs are duplicated for tcp/udp/icmp,
|
72
|
+
# so we need to do this up frnot and remove duplicates before checking against the local rubber rules)
|
73
|
+
cloud_group[:permissions].each do |rule|
|
74
|
+
if rule[:source_groups]
|
75
|
+
rule.source_groups.each do |source_group|
|
76
|
+
rule_map = {:source_group_name => source_group[:name], :source_group_account => source_group[:account]}
|
77
|
+
rule_map = Rubber::Util::stringify(rule_map)
|
78
|
+
rule_maps << rule_map unless rule_maps.include?(rule_map)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
rule_map = Rubber::Util::stringify(rule)
|
82
|
+
rule_maps << rule_map unless rule_maps.include?(rule_map)
|
83
|
+
end
|
84
|
+
end if cloud_group[:permissions]
|
85
|
+
# For each rule, if it exists, do nothing, otherwise remove it as its no longer defined locally
|
86
|
+
rule_maps.each do |rule_map|
|
87
|
+
if rules.delete(rule_map)
|
88
|
+
# rules match, don't need to do anything
|
89
|
+
# logger.debug "Rule in sync: #{rule_map.inspect}"
|
90
|
+
else
|
91
|
+
# rules don't match, remove them from ec2 and re-add below
|
92
|
+
answer = Capistrano::CLI.ui.ask("Rule '#{rule_map.inspect}' exists in ec2, but not locally, remove from ec2? [y/N]?: ")
|
93
|
+
rule_map = Rubber::Util::symbolize_keys(rule_map)
|
94
|
+
if rule_map[:source_group_name]
|
95
|
+
cloud.remove_security_group_rule(group_name, nil, nil, nil, {:name => rule_map[:source_group_name], :account => rule_map[:source_group_account]})
|
96
|
+
else
|
97
|
+
rule_map[:source_ips].each do |source_ip|
|
98
|
+
cloud.remove_security_group_rule(group_name, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
|
99
|
+
end if rule_map[:source_ips] && answer =~ /^y/
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
rules.each do |rule_map|
|
105
|
+
# create non-existing rules
|
106
|
+
logger.debug "Missing rule, creating: #{rule_map.inspect}"
|
107
|
+
rule_map = Rubber::Util::symbolize_keys(rule_map)
|
108
|
+
if rule_map[:source_group_name]
|
109
|
+
cloud.add_security_group_rule(group_name, nil, nil, nil, {:name => rule_map[:source_group_name], :account => rule_map[:source_group_account]})
|
110
|
+
else
|
111
|
+
rule_map[:source_ips].each do |source_ip|
|
112
|
+
cloud.add_security_group_rule(group_name, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
|
113
|
+
end if rule_map[:source_ips]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
else
|
117
|
+
# when using auto groups, get prompted too much to delete when
|
118
|
+
# switching between production/staging since the hosts aren't shared
|
119
|
+
# between the two environments
|
120
|
+
if env.force_security_group_cleanup || ! env.auto_security_groups
|
121
|
+
# delete group
|
122
|
+
answer = Capistrano::CLI.ui.ask("Security group '#{group_name}' exists in ec2 but not locally, remove from ec2? [y/N]: ")
|
123
|
+
cloud.destroy_security_group(group_name) if answer =~ /^y/
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# For each group that didnt already exist in ec2
|
129
|
+
group_keys.each do |group_name|
|
130
|
+
group = groups[group_name]
|
131
|
+
logger.debug "Creating new security group: #{group_name}"
|
132
|
+
# create each group
|
133
|
+
cloud.create_security_group(group_name, group['description'])
|
134
|
+
# create rules for group
|
135
|
+
group['rules'].each do |rule_map|
|
136
|
+
logger.debug "Creating new rule: #{rule_map.inspect}"
|
137
|
+
rule_map = Rubber::Util::symbolize_keys(rule_map)
|
138
|
+
if rule_map[:source_group_name]
|
139
|
+
cloud.add_security_group_rule(group_name, nil, nil, nil, {:name => rule_map[:source_group_name], :account => rule_map[:source_group_account]})
|
140
|
+
else
|
141
|
+
rule_map[:source_ips].each do |source_ip|
|
142
|
+
cloud.add_security_group_rule(group_name, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
|
143
|
+
end if rule_map[:source_ips]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
namespace :rubber do
|
2
|
+
|
3
|
+
desc <<-DESC
|
4
|
+
Bootstraps instances by setting timezone, installing packages and gems
|
5
|
+
DESC
|
6
|
+
task :bootstrap do
|
7
|
+
set_timezone
|
8
|
+
link_bash
|
9
|
+
install_packages
|
10
|
+
setup_volumes
|
11
|
+
add_gem_sources
|
12
|
+
install_gems
|
13
|
+
deploy.setup
|
14
|
+
end
|
15
|
+
|
16
|
+
desc <<-DESC
|
17
|
+
Sets up aliases for instance hostnames based on contents of instance.yml.
|
18
|
+
Generates /etc/hosts for local/remote machines and sets hostname on
|
19
|
+
remote instances, and sets values in dynamic dns entries
|
20
|
+
DESC
|
21
|
+
required_task :setup_aliases do
|
22
|
+
setup_local_aliases
|
23
|
+
setup_remote_aliases
|
24
|
+
setup_dns_aliases
|
25
|
+
end
|
26
|
+
|
27
|
+
desc <<-DESC
|
28
|
+
Sets up local aliases for instance hostnames based on contents of instance.yml.
|
29
|
+
Generates/etc/hosts for local machine
|
30
|
+
DESC
|
31
|
+
required_task :setup_local_aliases do
|
32
|
+
hosts_file = '/etc/hosts'
|
33
|
+
|
34
|
+
# Generate /etc/hosts contents for the local machine from instance config
|
35
|
+
env = rubber_cfg.environment.bind()
|
36
|
+
delim = "## rubber config #{env.domain} #{RUBBER_ENV}"
|
37
|
+
local_hosts = delim + "\n"
|
38
|
+
rubber_cfg.instance.each do |ic|
|
39
|
+
# don't add unqualified hostname in local hosts file since user may be
|
40
|
+
# managing multiple domains with same aliases
|
41
|
+
hosts_data = [ic.full_name, ic.external_host, ic.internal_host].join(' ')
|
42
|
+
local_hosts << ic.external_ip << ' ' << hosts_data << "\n"
|
43
|
+
end
|
44
|
+
local_hosts << delim << "\n"
|
45
|
+
|
46
|
+
# Write out the hosts file for this machine, use sudo
|
47
|
+
filtered = File.read(hosts_file).gsub(/^#{delim}.*^#{delim}\n?/m, '')
|
48
|
+
logger.info "Writing out aliases into local machines #{hosts_file}, sudo access needed"
|
49
|
+
Rubber::Util::sudo_open(hosts_file, 'w') do |f|
|
50
|
+
f.write(filtered)
|
51
|
+
f.write(local_hosts)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
desc <<-DESC
|
56
|
+
Sets up aliases in dynamic dns provider for instance hostnames based on contents of instance.yml.
|
57
|
+
DESC
|
58
|
+
required_task :setup_dns_aliases do
|
59
|
+
rubber_cfg.instance.each do |ic|
|
60
|
+
update_dyndns(ic)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc <<-DESC
|
65
|
+
Sets up aliases for instance hostnames based on contents of instance.yml.
|
66
|
+
Generates /etc/hosts for remote machines and sets hostname on remote instances
|
67
|
+
DESC
|
68
|
+
task :setup_remote_aliases do
|
69
|
+
hosts_file = '/etc/hosts'
|
70
|
+
|
71
|
+
# Generate /etc/hosts contents for the remote instance from instance config
|
72
|
+
delim = "## rubber config"
|
73
|
+
delim = "#{delim} #{RUBBER_ENV}"
|
74
|
+
remote_hosts = delim + "\n"
|
75
|
+
rubber_cfg.instance.each do |ic|
|
76
|
+
hosts_data = [ic.name, ic.full_name, ic.external_host, ic.internal_host].join(' ')
|
77
|
+
remote_hosts << ic.internal_ip << ' ' << hosts_data << "\n"
|
78
|
+
end
|
79
|
+
remote_hosts << delim << "\n"
|
80
|
+
if rubber_cfg.instance.size > 0
|
81
|
+
# write out the hosts file for the remote instances
|
82
|
+
# NOTE that we use "capture" to get the existing hosts
|
83
|
+
# file, which only grabs the hosts file from the first host
|
84
|
+
filtered = (capture "cat #{hosts_file}").gsub(/^#{delim}.*^#{delim}\n?/m, '')
|
85
|
+
filtered = filtered + remote_hosts
|
86
|
+
# Put the generated hosts back on remote instance
|
87
|
+
put filtered, hosts_file
|
88
|
+
|
89
|
+
# Setup hostname on instance so shell, etcs have nice display
|
90
|
+
sudo "echo $CAPISTRANO:HOST$ > /etc/hostname && hostname $CAPISTRANO:HOST$"
|
91
|
+
end
|
92
|
+
|
93
|
+
# TODO
|
94
|
+
# /etc/resolv.conf to add search domain
|
95
|
+
# ~/.ssh/options to setup user/host/key aliases
|
96
|
+
end
|
97
|
+
|
98
|
+
desc <<-DESC
|
99
|
+
Update to the newest versions of all packages/gems.
|
100
|
+
DESC
|
101
|
+
task :update do
|
102
|
+
upgrade_packages
|
103
|
+
update_gems
|
104
|
+
end
|
105
|
+
|
106
|
+
desc <<-DESC
|
107
|
+
Upgrade to the newest versions of all Ubuntu packages.
|
108
|
+
DESC
|
109
|
+
task :upgrade_packages do
|
110
|
+
package_helper(true)
|
111
|
+
end
|
112
|
+
|
113
|
+
desc <<-DESC
|
114
|
+
Upgrade to the newest versions of all rubygems.
|
115
|
+
DESC
|
116
|
+
task :update_gems do
|
117
|
+
gem_helper(true)
|
118
|
+
end
|
119
|
+
|
120
|
+
desc <<-DESC
|
121
|
+
Install extra packages and gems.
|
122
|
+
DESC
|
123
|
+
task :install do
|
124
|
+
install_packages
|
125
|
+
install_gems
|
126
|
+
end
|
127
|
+
|
128
|
+
desc <<-DESC
|
129
|
+
Install extra Ubuntu packages. Set 'packages' in rubber.yml to \
|
130
|
+
be an array of strings.
|
131
|
+
DESC
|
132
|
+
task :install_packages do
|
133
|
+
package_helper(false)
|
134
|
+
end
|
135
|
+
|
136
|
+
desc <<-DESC
|
137
|
+
Install extra ruby gems. Set 'gems' in rubber.yml to \
|
138
|
+
be an array of strings.
|
139
|
+
DESC
|
140
|
+
task :install_gems do
|
141
|
+
gem_helper(false)
|
142
|
+
end
|
143
|
+
|
144
|
+
desc <<-DESC
|
145
|
+
Add extra ruby gems sources. Set 'gemsources' in rubber.yml to \
|
146
|
+
be an array of URI strings.
|
147
|
+
DESC
|
148
|
+
task :add_gem_sources do
|
149
|
+
env = rubber_cfg.environment.bind()
|
150
|
+
if env.gemsources
|
151
|
+
env.gemsources.each { |source| sudo "gem sources -a #{source}"}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
desc <<-DESC
|
156
|
+
The ubuntu has /bin/sh linking to dash instead of bash, fix this
|
157
|
+
You can override this task if you don't want this to happen
|
158
|
+
DESC
|
159
|
+
task :link_bash do
|
160
|
+
sudo("ln -sf /bin/bash /bin/sh")
|
161
|
+
end
|
162
|
+
|
163
|
+
desc <<-DESC
|
164
|
+
Set the timezone using the value of the variable named timezone. \
|
165
|
+
Valid options for timezone can be determined by the contents of \
|
166
|
+
/usr/share/zoneinfo, which can be seen here: \
|
167
|
+
http://packages.ubuntu.com/cgi-bin/search_contents.pl?searchmode=filelist&word=tzdata&version=gutsy&arch=all&page=1&number=all \
|
168
|
+
Remove 'usr/share/zoneinfo/' from the filename, and use the last \
|
169
|
+
directory and file as the value. For example 'Africa/Abidjan' or \
|
170
|
+
'posix/GMT' or 'Canada/Eastern'.
|
171
|
+
DESC
|
172
|
+
task :set_timezone do
|
173
|
+
opts = get_host_options('timezone')
|
174
|
+
sudo "bash -c 'echo $CAPISTRANO:VAR$ > /etc/timezone'", opts
|
175
|
+
sudo "cp /usr/share/zoneinfo/$CAPISTRANO:VAR$ /etc/localtime", opts
|
176
|
+
# restart syslog so that times match timezone
|
177
|
+
sudo "/etc/init.d/sysklogd restart"
|
178
|
+
end
|
179
|
+
|
180
|
+
def update_dyndns(instance_item)
|
181
|
+
env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
|
182
|
+
if env.dns_provider
|
183
|
+
provider = Rubber::Dns::get_provider(env.dns_provider, env)
|
184
|
+
provider.update(instance_item.name, instance_item.external_ip)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def destroy_dyndns(instance_item)
|
189
|
+
env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
|
190
|
+
if env.dns_provider
|
191
|
+
provider = Rubber::Dns::get_provider(env.dns_provider, env)
|
192
|
+
provider.destroy(instance_item.name)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def package_helper(upgrade=false)
|
197
|
+
opts = get_host_options('packages') do |pkg_list|
|
198
|
+
expanded_pkg_list = []
|
199
|
+
pkg_list.each do |pkg_spec|
|
200
|
+
if pkg_spec.is_a?(Array)
|
201
|
+
expanded_pkg_list << "#{pkg_spec[0]}=#{pkg_spec[1]}"
|
202
|
+
else
|
203
|
+
expanded_pkg_list << pkg_spec
|
204
|
+
end
|
205
|
+
end
|
206
|
+
expanded_pkg_list.join(' ')
|
207
|
+
end
|
208
|
+
|
209
|
+
sudo "apt-get -q update"
|
210
|
+
if upgrade
|
211
|
+
sudo "/bin/sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get -q -y --force-yes dist-upgrade'"
|
212
|
+
else
|
213
|
+
sudo "/bin/sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get -q -y --force-yes install $CAPISTRANO:VAR$'", opts
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def custom_package(url_base, name, ver, install_test)
|
218
|
+
rubber.run_script "install_#{name}", <<-ENDSCRIPT
|
219
|
+
if [[ #{install_test} ]]; then
|
220
|
+
arch=`uname -m`
|
221
|
+
if [ "$arch" = "x86_64" ]; then
|
222
|
+
src="#{url_base}/#{name}_#{ver}_amd64.deb"
|
223
|
+
else
|
224
|
+
src="#{url_base}/#{name}_#{ver}_i386.deb"
|
225
|
+
fi
|
226
|
+
src_file="${src##*/}"
|
227
|
+
wget -qP /tmp ${src}
|
228
|
+
dpkg -i /tmp/${src_file}
|
229
|
+
fi
|
230
|
+
ENDSCRIPT
|
231
|
+
end
|
232
|
+
|
233
|
+
def handle_gem_prompt(ch, data, str)
|
234
|
+
ch[:data] ||= ""
|
235
|
+
ch[:data] << data
|
236
|
+
if data =~ />\s*$/
|
237
|
+
logger.info data
|
238
|
+
logger.info "The gem command is asking for a number:"
|
239
|
+
choice = STDIN.gets
|
240
|
+
ch.send_data(choice)
|
241
|
+
else
|
242
|
+
logger.info data
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Helper for installing gems,allows one to respond to prompts
|
247
|
+
def gem_helper(update=false)
|
248
|
+
cmd = update ? "update" : "install"
|
249
|
+
|
250
|
+
# when versions are provided for a gem, rubygems fails unless versions ae provided for all gems
|
251
|
+
#
|
252
|
+
# first do the gems that the user specified versions for
|
253
|
+
opts = get_host_options('gems') do |gem_list|
|
254
|
+
expanded_gem_list = []
|
255
|
+
gem_list.each do |gem_spec|
|
256
|
+
if gem_spec.is_a?(Array)
|
257
|
+
expanded_gem_list << "#{gem_spec[0]} -v #{gem_spec[1]}"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
expanded_gem_list.join(' ')
|
261
|
+
end
|
262
|
+
if opts.size > 0
|
263
|
+
sudo "gem #{cmd} $CAPISTRANO:VAR$ --no-rdoc --no-ri", opts do |ch, str, data|
|
264
|
+
handle_gem_prompt(ch, data, str)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# then do the gems without versions
|
269
|
+
opts = get_host_options('gems') do |gem_list|
|
270
|
+
expanded_gem_list = []
|
271
|
+
gem_list.each do |gem_spec|
|
272
|
+
if ! gem_spec.is_a?(Array)
|
273
|
+
expanded_gem_list << gem_spec
|
274
|
+
end
|
275
|
+
end
|
276
|
+
expanded_gem_list.join(' ')
|
277
|
+
end
|
278
|
+
if opts.size > 0
|
279
|
+
sudo "gem #{cmd} $CAPISTRANO:VAR$ --no-rdoc --no-ri", opts do |ch, str, data|
|
280
|
+
handle_gem_prompt(ch, data, str)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|