wr0ngway-rubber 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. data/CHANGELOG +34 -0
  2. data/COPYING +339 -0
  3. data/README +6 -0
  4. data/TODO +7 -0
  5. data/VERSION +1 -0
  6. data/bin/vulcanize +41 -0
  7. data/generators/vulcanize/USAGE +6 -0
  8. data/generators/vulcanize/templates/apache/config/rubber/deploy-apache.rb +51 -0
  9. data/generators/vulcanize/templates/apache/config/rubber/role/apache/deflate.conf +10 -0
  10. data/generators/vulcanize/templates/apache/config/rubber/role/apache/expires.conf +9 -0
  11. data/generators/vulcanize/templates/apache/config/rubber/role/apache/headers.conf +6 -0
  12. data/generators/vulcanize/templates/apache/config/rubber/role/apache/monit-apache.conf +8 -0
  13. data/generators/vulcanize/templates/apache/config/rubber/role/apache/ports.conf +5 -0
  14. data/generators/vulcanize/templates/apache/config/rubber/role/apache/setenvif.conf +52 -0
  15. data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-apache-vhost.conf +62 -0
  16. data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-apache.auth +7 -0
  17. data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-index.html +30 -0
  18. data/generators/vulcanize/templates/apache/config/rubber/rubber-apache.yml +7 -0
  19. data/generators/vulcanize/templates/apache/templates.yml +1 -0
  20. data/generators/vulcanize/templates/base/Capfile +14 -0
  21. data/generators/vulcanize/templates/base/config/deploy.rb +55 -0
  22. data/generators/vulcanize/templates/base/config/rubber/common/crontab +16 -0
  23. data/generators/vulcanize/templates/base/config/rubber/common/profile.rc +9 -0
  24. data/generators/vulcanize/templates/base/config/rubber/deploy-setup.rb +104 -0
  25. data/generators/vulcanize/templates/base/config/rubber/rubber.yml +241 -0
  26. data/generators/vulcanize/templates/base/lib/tasks/rubber.rake +15 -0
  27. data/generators/vulcanize/templates/base/script/cron-rake +18 -0
  28. data/generators/vulcanize/templates/base/script/cron-runner +18 -0
  29. data/generators/vulcanize/templates/base/script/cron-sh +67 -0
  30. data/generators/vulcanize/templates/base/templates.yml +1 -0
  31. data/generators/vulcanize/templates/complete_mongrel_mysql/config/rubber/role/haproxy/haproxy-mongrel.conf +23 -0
  32. data/generators/vulcanize/templates/complete_mongrel_mysql/config/rubber/role/nginx/nginx-mongrel.conf +113 -0
  33. data/generators/vulcanize/templates/complete_mongrel_mysql/config/rubber/rubber-complete.yml +41 -0
  34. data/generators/vulcanize/templates/complete_mongrel_mysql/templates.yml +6 -0
  35. data/generators/vulcanize/templates/complete_passenger_mysql/config/rubber/role/haproxy/haproxy-passenger.conf +19 -0
  36. data/generators/vulcanize/templates/complete_passenger_mysql/config/rubber/rubber-complete.yml +40 -0
  37. data/generators/vulcanize/templates/complete_passenger_mysql/templates.yml +10 -0
  38. data/generators/vulcanize/templates/cruise/config/rubber/deploy-cruise.rb +72 -0
  39. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/cruise +40 -0
  40. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/my.cnf +165 -0
  41. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/production.rb +8 -0
  42. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/site_config.rb +76 -0
  43. data/generators/vulcanize/templates/cruise/config/rubber/role/web_tools/cruise-nginx.conf +11 -0
  44. data/generators/vulcanize/templates/cruise/config/rubber/rubber-cruise.yml +18 -0
  45. data/generators/vulcanize/templates/cruise/templates.yml +1 -0
  46. data/generators/vulcanize/templates/haproxy/config/rubber/deploy-haproxy.rb +45 -0
  47. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy-base.conf +26 -0
  48. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy-default.conf +8 -0
  49. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/monit-haproxy.conf +9 -0
  50. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslog-haproxy.conf +6 -0
  51. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslogd-default.conf +17 -0
  52. data/generators/vulcanize/templates/haproxy/config/rubber/role/web_tools/haproxy-nginx.conf +10 -0
  53. data/generators/vulcanize/templates/haproxy/config/rubber/rubber-haproxy.yml +7 -0
  54. data/generators/vulcanize/templates/haproxy/templates.yml +1 -0
  55. data/generators/vulcanize/templates/memcached/config/memcached.yml +28 -0
  56. data/generators/vulcanize/templates/memcached/config/rubber/common/memcached.yml +14 -0
  57. data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached.conf +52 -0
  58. data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached_munin_plugin +249 -0
  59. data/generators/vulcanize/templates/memcached/config/rubber/rubber-memcached.yml +7 -0
  60. data/generators/vulcanize/templates/memcached/templates.yml +1 -0
  61. data/generators/vulcanize/templates/minimal_mysql/templates.yml +7 -0
  62. data/generators/vulcanize/templates/minimal_nodb/templates.yml +6 -0
  63. data/generators/vulcanize/templates/mongrel/config/rubber/deploy-mongrel.rb +75 -0
  64. data/generators/vulcanize/templates/mongrel/config/rubber/role/mongrel/mongrel_cluster.yml +12 -0
  65. data/generators/vulcanize/templates/mongrel/config/rubber/role/mongrel/monit-mongrel.conf +20 -0
  66. data/generators/vulcanize/templates/mongrel/config/rubber/rubber-mongrel.yml +9 -0
  67. data/generators/vulcanize/templates/mongrel/templates.yml +1 -0
  68. data/generators/vulcanize/templates/monit/config/rubber/common/monit-default.conf +15 -0
  69. data/generators/vulcanize/templates/monit/config/rubber/common/monit.conf +251 -0
  70. data/generators/vulcanize/templates/monit/config/rubber/deploy-monit.rb +32 -0
  71. data/generators/vulcanize/templates/monit/config/rubber/role/web_tools/monit-admin-nginx.conf +10 -0
  72. data/generators/vulcanize/templates/monit/config/rubber/rubber-monit.yml +6 -0
  73. data/generators/vulcanize/templates/monit/templates.yml +1 -0
  74. data/generators/vulcanize/templates/munin/config/rubber/common/monit-munin.conf +8 -0
  75. data/generators/vulcanize/templates/munin/config/rubber/common/munin-node.conf +48 -0
  76. data/generators/vulcanize/templates/munin/config/rubber/deploy-munin.rb +46 -0
  77. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-nginx.conf +8 -0
  78. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-plugins.conf +31 -0
  79. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin.conf +80 -0
  80. data/generators/vulcanize/templates/munin/config/rubber/rubber-munin.yml +8 -0
  81. data/generators/vulcanize/templates/munin/script/munin/example_mysql_query.rb +57 -0
  82. data/generators/vulcanize/templates/munin/script/munin/example_simple.rb +24 -0
  83. data/generators/vulcanize/templates/munin/templates.yml +1 -0
  84. data/generators/vulcanize/templates/mysql/config/rubber/common/database.yml +11 -0
  85. data/generators/vulcanize/templates/mysql/config/rubber/deploy-mysql.rb +156 -0
  86. data/generators/vulcanize/templates/mysql/config/rubber/role/db/crontab +14 -0
  87. data/generators/vulcanize/templates/mysql/config/rubber/role/db/monit-mysql.cnf +10 -0
  88. data/generators/vulcanize/templates/mysql/config/rubber/role/db/my.cnf +167 -0
  89. data/generators/vulcanize/templates/mysql/config/rubber/role/mysql_slave/mysql_slave_munin_plugin +51 -0
  90. data/generators/vulcanize/templates/mysql/config/rubber/rubber-mysql.yml +46 -0
  91. data/generators/vulcanize/templates/mysql/templates.yml +1 -0
  92. data/generators/vulcanize/templates/mysql_cluster/config/rubber/common/mysql_cluster_migrations.rb +13 -0
  93. data/generators/vulcanize/templates/mysql_cluster/config/rubber/deploy-mysql_cluster.rb +173 -0
  94. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_data/my.cnf +15 -0
  95. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_mgm/ndb_mgmd.cnf +39 -0
  96. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/monit-mysql_cluster_sql.cnf +10 -0
  97. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/my.cnf +23 -0
  98. data/generators/vulcanize/templates/mysql_cluster/config/rubber/rubber-mysql_cluster.yml +32 -0
  99. data/generators/vulcanize/templates/mysql_cluster/templates.yml +1 -0
  100. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/database.yml +16 -0
  101. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/monit-mysql_proxy.cnf +10 -0
  102. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy +153 -0
  103. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.conf +10 -0
  104. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.lua +5 -0
  105. data/generators/vulcanize/templates/mysql_proxy/config/rubber/deploy-mysql_proxy.rb +52 -0
  106. data/generators/vulcanize/templates/mysql_proxy/config/rubber/rubber-mysql_proxy.yml +11 -0
  107. data/generators/vulcanize/templates/mysql_proxy/templates.yml +1 -0
  108. data/generators/vulcanize/templates/nginx/config/rubber/deploy-nginx.rb +45 -0
  109. data/generators/vulcanize/templates/nginx/config/rubber/role/nginx/crontab +9 -0
  110. data/generators/vulcanize/templates/nginx/config/rubber/role/nginx/monit-nginx.conf +8 -0
  111. data/generators/vulcanize/templates/nginx/config/rubber/role/nginx/nginx.conf +42 -0
  112. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/nginx-tools.conf +55 -0
  113. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/tools-index.html +30 -0
  114. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/tools-nginx.auth +7 -0
  115. data/generators/vulcanize/templates/nginx/config/rubber/rubber-nginx.yml +10 -0
  116. data/generators/vulcanize/templates/nginx/templates.yml +1 -0
  117. data/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +37 -0
  118. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/munin-passenger-sudoers.conf +6 -0
  119. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/munin-passenger.conf +47 -0
  120. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/passenger-apache-vhost.conf +46 -0
  121. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/passenger.conf +10 -0
  122. data/generators/vulcanize/templates/passenger/config/rubber/rubber-passenger.yml +12 -0
  123. data/generators/vulcanize/templates/passenger/templates.yml +1 -0
  124. data/generators/vulcanize/templates/sphinx/config/rubber/common/sphinx.yml +46 -0
  125. data/generators/vulcanize/templates/sphinx/config/rubber/deploy-sphinx.rb +112 -0
  126. data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/crontab +11 -0
  127. data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/monit-sphinx.conf +10 -0
  128. data/generators/vulcanize/templates/sphinx/config/rubber/rubber-sphinx.yml +6 -0
  129. data/generators/vulcanize/templates/sphinx/templates.yml +1 -0
  130. data/generators/vulcanize/vulcanize_generator.rb +67 -0
  131. data/lib/capistrano/hostcmd.rb +12 -0
  132. data/lib/rubber/capistrano.rb +1 -0
  133. data/lib/rubber/cloud/aws.rb +305 -0
  134. data/lib/rubber/cloud/base.rb +16 -0
  135. data/lib/rubber/cloud.rb +13 -0
  136. data/lib/rubber/configuration.rb +47 -0
  137. data/lib/rubber/dns/base.rb +69 -0
  138. data/lib/rubber/dns/dyndns.rb +63 -0
  139. data/lib/rubber/dns/nettica.rb +56 -0
  140. data/lib/rubber/dns/zerigo.rb +121 -0
  141. data/lib/rubber/dns.rb +13 -0
  142. data/lib/rubber/environment.rb +161 -0
  143. data/lib/rubber/generator.rb +197 -0
  144. data/lib/rubber/instance.rb +165 -0
  145. data/lib/rubber/recipes/rubber/bundles.rb +28 -0
  146. data/lib/rubber/recipes/rubber/deploy.rb +90 -0
  147. data/lib/rubber/recipes/rubber/instances.rb +348 -0
  148. data/lib/rubber/recipes/rubber/load_balancers.rb +44 -0
  149. data/lib/rubber/recipes/rubber/security_groups.rb +189 -0
  150. data/lib/rubber/recipes/rubber/setup.rb +357 -0
  151. data/lib/rubber/recipes/rubber/static_ips.rb +107 -0
  152. data/lib/rubber/recipes/rubber/utils.rb +203 -0
  153. data/lib/rubber/recipes/rubber/volumes.rb +264 -0
  154. data/lib/rubber/recipes/rubber.rb +89 -0
  155. data/lib/rubber/tasks/rubber.rb +221 -0
  156. data/lib/rubber/util.rb +37 -0
  157. data/lib/rubber.rb +38 -0
  158. data/test/environment_test.rb +118 -0
  159. data/test/generator_test.rb +323 -0
  160. data/test/instance_test.rb +93 -0
  161. data/test/test_helper.rb +4 -0
  162. data/test/util_test.rb +16 -0
  163. metadata +273 -0
@@ -0,0 +1,357 @@
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
+ upgrade_packages
10
+ install_packages
11
+ setup_volumes
12
+ setup_gem_sources
13
+ install_gems
14
+ deploy.setup
15
+ end
16
+
17
+ desc <<-DESC
18
+ Sets up aliases for instance hostnames based on contents of instance.yml.
19
+ Generates /etc/hosts for local/remote machines and sets hostname on
20
+ remote instances, and sets values in dynamic dns entries
21
+ DESC
22
+ required_task :setup_aliases do
23
+ setup_local_aliases
24
+ setup_remote_aliases
25
+ setup_dns_aliases
26
+ end
27
+
28
+ desc <<-DESC
29
+ Sets up local aliases for instance hostnames based on contents of instance.yml.
30
+ Generates/etc/hosts for local machine
31
+ DESC
32
+ required_task :setup_local_aliases do
33
+ hosts_file = '/etc/hosts'
34
+
35
+ # Generate /etc/hosts contents for the local machine from instance config
36
+ delim = "## rubber config #{rubber_env.domain} #{RUBBER_ENV}"
37
+ local_hosts = delim + "\n"
38
+ rubber_instances.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_instances.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_instances.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_instances.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 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 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
+ Install ruby gems defined in the rails environment.rb
146
+ DESC
147
+ after "deploy:symlink", "rubber:install_rails_gems" if Rubber::Util.is_rails?
148
+ task :install_rails_gems do
149
+ sudo "sh -c 'cd #{current_path} && RAILS_ENV=#{RUBBER_ENV} rake gems:install'"
150
+ end
151
+
152
+ desc <<-DESC
153
+ Setup ruby gems sources. Set 'gemsources' in rubber.yml to \
154
+ be an array of URI strings.
155
+ DESC
156
+ task :setup_gem_sources do
157
+ if rubber_env.gemsources
158
+ script = prepare_script 'gem_sources_helper', <<-'ENDSCRIPT'
159
+ ruby - $@ <<-'EOF'
160
+
161
+ sources = ARGV
162
+
163
+ installed = []
164
+ `gem sources -l`.grep(/^[^*]/) do |line|
165
+ line = line.strip
166
+ installed << line if line.size > 0
167
+ end
168
+
169
+ to_install = sources - installed
170
+ to_remove = installed - sources
171
+
172
+ if to_install.size > 0
173
+ to_install.each do |source|
174
+ system "gem sources -a #{source}"
175
+ fail "Unable to add gem sources" if $?.exitstatus > 0
176
+ end
177
+ end
178
+ if to_remove.size > 0
179
+ to_remove.each do |source|
180
+ system "gem sources -r #{source}"
181
+ fail "Unable to remove gem sources" if $?.exitstatus > 0
182
+ end
183
+ end
184
+
185
+ 'EOF'
186
+ ENDSCRIPT
187
+
188
+ sudo "sh #{script} #{rubber_env.gemsources.join(' ')}"
189
+ end
190
+ end
191
+
192
+ desc <<-DESC
193
+ The ubuntu has /bin/sh linking to dash instead of bash, fix this
194
+ You can override this task if you don't want this to happen
195
+ DESC
196
+ task :link_bash do
197
+ sudo("ln -sf /bin/bash /bin/sh")
198
+ end
199
+
200
+ desc <<-DESC
201
+ Set the timezone using the value of the variable named timezone. \
202
+ Valid options for timezone can be determined by the contents of \
203
+ /usr/share/zoneinfo, which can be seen here: \
204
+ http://packages.ubuntu.com/cgi-bin/search_contents.pl?searchmode=filelist&word=tzdata&version=gutsy&arch=all&page=1&number=all \
205
+ Remove 'usr/share/zoneinfo/' from the filename, and use the last \
206
+ directory and file as the value. For example 'Africa/Abidjan' or \
207
+ 'posix/GMT' or 'Canada/Eastern'.
208
+ DESC
209
+ task :set_timezone do
210
+ opts = get_host_options('timezone')
211
+ sudo "bash -c 'echo $CAPISTRANO:VAR$ > /etc/timezone'", opts
212
+ sudo "cp /usr/share/zoneinfo/$CAPISTRANO:VAR$ /etc/localtime", opts
213
+ # restart syslog so that times match timezone
214
+ sudo "/etc/init.d/sysklogd restart"
215
+ end
216
+
217
+ def update_dyndns(instance_item)
218
+ env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
219
+ if env.dns_provider
220
+ provider = Rubber::Dns::get_provider(env.dns_provider, env)
221
+ provider.update(instance_item.name, instance_item.external_ip)
222
+ end
223
+ end
224
+
225
+ def destroy_dyndns(instance_item)
226
+ env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
227
+ if env.dns_provider
228
+ provider = Rubber::Dns::get_provider(env.dns_provider, env)
229
+ provider.destroy(instance_item.name)
230
+ end
231
+ end
232
+
233
+ def package_helper(upgrade=false)
234
+ opts = get_host_options('packages') do |pkg_list|
235
+ expanded_pkg_list = []
236
+ pkg_list.each do |pkg_spec|
237
+ if pkg_spec.is_a?(Array)
238
+ expanded_pkg_list << "#{pkg_spec[0]}=#{pkg_spec[1]}"
239
+ else
240
+ expanded_pkg_list << pkg_spec
241
+ end
242
+ end
243
+ expanded_pkg_list.join(' ')
244
+ end
245
+
246
+ sudo "apt-get -q update"
247
+ if upgrade
248
+ sudo "/bin/sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get -q -y --force-yes dist-upgrade'"
249
+ else
250
+ sudo "/bin/sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get -q -y --force-yes install $CAPISTRANO:VAR$'", opts
251
+ end
252
+ end
253
+
254
+ def custom_package(url_base, name, ver, install_test)
255
+ rubber.run_script "install_#{name}", <<-ENDSCRIPT
256
+ if [[ #{install_test} ]]; then
257
+ arch=`uname -m`
258
+ if [ "$arch" = "x86_64" ]; then
259
+ src="#{url_base}/#{name}_#{ver}_amd64.deb"
260
+ else
261
+ src="#{url_base}/#{name}_#{ver}_i386.deb"
262
+ fi
263
+ src_file="${src##*/}"
264
+ wget -qP /tmp ${src}
265
+ dpkg -i /tmp/${src_file}
266
+ fi
267
+ ENDSCRIPT
268
+ end
269
+
270
+ def handle_gem_prompt(ch, data, str)
271
+ ch[:data] ||= ""
272
+ ch[:data] << data
273
+ if data =~ />\s*$/
274
+ logger.info data
275
+ logger.info "The gem command is asking for a number:"
276
+ choice = STDIN.gets
277
+ ch.send_data(choice)
278
+ else
279
+ logger.info data
280
+ end
281
+ end
282
+
283
+ # Helper for installing gems,allows one to respond to prompts
284
+ def gem_helper(update=false)
285
+ cmd = update ? "update" : "install"
286
+
287
+
288
+ opts = get_host_options('gems') do |gem_list|
289
+ expanded_gem_list = []
290
+ gem_list.each do |gem_spec|
291
+ if gem_spec.is_a?(Array)
292
+ expanded_gem_list << "#{gem_spec[0]}:#{gem_spec[1]}"
293
+ else
294
+ expanded_gem_list << gem_spec
295
+ end
296
+ end
297
+ expanded_gem_list.join(' ')
298
+ end
299
+
300
+ if opts.size > 0
301
+ # Rubygems always installs even if the gem is already installed
302
+ # When providing versions, rubygems fails unless versions are provided for all gems
303
+ # This helper script works around these issues by installing gems only if they
304
+ # aren't already installed, and separates versioned/unversioned into two separate
305
+ # calls to rubygems
306
+ script = prepare_script 'gem_helper', <<-'ENDSCRIPT'
307
+ ruby - $@ <<-'EOF'
308
+
309
+ gem_cmd = ARGV[0]
310
+ gems = ARGV[1..-1]
311
+ cmd = "gem #{gem_cmd} --no-rdoc --no-ri"
312
+
313
+ to_install = {}
314
+ to_install_ver = {}
315
+ # gem list passed in, possibly with versions, as "gem1 gem2:1.2 gem3"
316
+ gems.each do |gem_spec|
317
+ parts = gem_spec.split(':')
318
+ if parts[1]
319
+ to_install_ver[parts[0]] = parts[1]
320
+ else
321
+ to_install[parts[0]] = true
322
+ end
323
+ end
324
+
325
+ installed = {}
326
+ `gem list --local`.each do |line|
327
+ parts = line.scan(/(.*) \((.*)\)/).first
328
+ next unless parts && parts.size == 2
329
+ installed[parts[0]] = parts[1].split(",")
330
+ end
331
+
332
+ to_install.delete_if {|g, v| installed.has_key?(g) } if gem_cmd == 'install'
333
+ to_install_ver.delete_if {|g, v| installed.has_key?(g) && installed[g].include?(v) }
334
+
335
+ # rubygems can only do asingle versioned gem at a time so we need
336
+ # to do the two groups separately
337
+ # install versioned ones first so unversioned don't pull in a newer version
338
+ to_install_ver.each do |g, v|
339
+ system "#{cmd} #{g} -v #{v}"
340
+ fail "Unable to install versioned gem #{g}:#{v}" if $?.exitstatus > 0
341
+ end
342
+ if to_install.size > 0
343
+ gem_list = to_install.keys.join(' ')
344
+ system "#{cmd} #{gem_list}"
345
+ fail "Unable to install gems" if $?.exitstatus > 0
346
+ end
347
+
348
+ 'EOF'
349
+ ENDSCRIPT
350
+
351
+ sudo "sh #{script} #{cmd} $CAPISTRANO:VAR$", opts do |ch, str, data|
352
+ handle_gem_prompt(ch, data, str)
353
+ end
354
+ end
355
+ end
356
+
357
+ end
@@ -0,0 +1,107 @@
1
+ namespace :rubber do
2
+
3
+
4
+ desc <<-DESC
5
+ Sets up static IPs for the instances configured to have them
6
+ DESC
7
+ required_task :setup_static_ips do
8
+ rubber_instances.each do |ic|
9
+ env = rubber_cfg.environment.bind(ic.role_names, ic.name)
10
+ if env.use_static_ip
11
+ artifacts = rubber_instances.artifacts
12
+ ip = artifacts['static_ips'][ic.name] rescue nil
13
+
14
+ # first allocate the static ip if we don't have a global record (artifacts) for it
15
+ if ! ip
16
+ logger.info "Allocating static IP for #{ic.full_name}"
17
+ ip = allocate_static_ip()
18
+ artifacts['static_ips'][ic.name] = ip
19
+ rubber_instances.save
20
+ end
21
+
22
+ # then, associate it if we don't have a record (on instance) of association
23
+ if ! ic.static_ip
24
+ logger.info "Associating static ip #{ip} with #{ic.full_name}"
25
+ associate_static_ip(ip, ic.instance_id)
26
+
27
+ instance = cloud.describe_instances(ic.instance_id).first
28
+ ic.external_host = instance[:external_host]
29
+ ic.internal_host = instance[:internal_host]
30
+ ic.external_ip = ip
31
+ ic.static_ip = ip
32
+ rubber_instances.save()
33
+
34
+ logger.info "Waiting for static ip to associate"
35
+ while true do
36
+ task :_wait_for_static_ip, :hosts => ip do
37
+ run "echo"
38
+ end
39
+ begin
40
+ _wait_for_static_ip
41
+ rescue ConnectionError
42
+ sleep 2
43
+ logger.info "Failed to connect to static ip #{ip}, retrying"
44
+ retry
45
+ end
46
+ break
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+
54
+ desc <<-DESC
55
+ Shows the configured static IPs
56
+ DESC
57
+ required_task :describe_static_ips do
58
+ results = []
59
+ format = "%-10s %-15s %-30s"
60
+ results << format % %w[InstanceID IP Alias]
61
+
62
+ ips = cloud.describe_static_ips()
63
+ ips.each do |ip_data|
64
+ instance_id = ip_data[:instance_id]
65
+ ip = ip_data[:ip]
66
+
67
+ local_alias = find_alias(ip, instance_id, false)
68
+
69
+ results << format % [instance_id || "Unassigned", ip, local_alias || "Unknown"]
70
+ end
71
+
72
+ results.each {|r| logger.info r}
73
+ end
74
+
75
+ desc <<-DESC
76
+ Deallocates the given static ip
77
+ DESC
78
+ required_task :destroy_static_ip do
79
+ ip = get_env('IP', "Static IP (run rubber:describe_static_ips for a list)", true)
80
+ destroy_static_ip(ip)
81
+ end
82
+
83
+ def allocate_static_ip()
84
+ ip = cloud.create_static_ip()
85
+ fatal "Failed to allocate static ip" if ip.nil?
86
+ return ip
87
+ end
88
+
89
+ def associate_static_ip(ip, instance_id)
90
+ success = cloud.attach_static_ip(ip, instance_id)
91
+ fatal "Failed to associate static ip" unless success
92
+ end
93
+
94
+ def destroy_static_ip(ip)
95
+ logger.info "Releasing static ip: #{ip}"
96
+ cloud.destroy_static_ip(ip) rescue logger.info("IP was not attached")
97
+
98
+ logger.info "Removing ip #{ip} from rubber instances file"
99
+ artifacts = rubber_instances.artifacts
100
+ artifacts['static_ips'].delete_if {|k,v| v == ip}
101
+ rubber_instances.each do |ic|
102
+ ic.static_ip = nil if ic.static_ip == ip
103
+ end
104
+ rubber_instances.save
105
+ end
106
+
107
+ end
@@ -0,0 +1,203 @@
1
+ namespace :rubber do
2
+
3
+ desc <<-DESC
4
+ Convenience task for creating a staging instance for the given RUBBER_ENV/RAILS_ENV.
5
+ By default this task assigns all known roles when creating the instance,
6
+ but you can specify a different default in rubber.yml:staging_roles
7
+ At the end, the instance will be up and running
8
+ e.g. RUBBER_ENV=matt cap create_staging
9
+ DESC
10
+ required_task :create_staging do
11
+ if rubber_instances.size > 0
12
+ value = Capistrano::CLI.ui.ask("The #{RUBBER_ENV} environment already has instances, Are you SURE you want to create a staging instance that may interact with them [y/N]?: ")
13
+ fatal("Exiting", 0) if value !~ /^y/
14
+ end
15
+ instance_alias = ENV['ALIAS'] = rubber.get_env("ALIAS", "Hostname to use for staging instance", true, RUBBER_ENV)
16
+ default_roles = rubber_env.staging_roles || "*"
17
+ roles = ENV['ROLES'] = rubber.get_env("ROLES", "Roles to use for staging instance", true, default_roles)
18
+
19
+ # some bootstraps update code (bootstrap_db) but if you don't have that role, need to do it here
20
+ # Since release directory variable gets reused by cap, we have to just do the symlink here - doing
21
+ # a update again will fail
22
+ set :rubber_code_was_updated, false
23
+ after "deploy:update_code" do
24
+ set :rubber_code_was_updated, true
25
+ end
26
+
27
+ if rubber_instances[instance_alias]
28
+ logger.info "Instance already exists, skipping to bootstrap"
29
+ else
30
+ rubber.create
31
+ end
32
+ rubber.bootstrap
33
+ # stop everything in case we have a bundled instance with monit, etc starting at boot
34
+ deploy.stop rescue nil
35
+ if ! rubber_code_was_updated
36
+ deploy.update_code
37
+ end
38
+ deploy.symlink
39
+ deploy.migrate
40
+ deploy.start
41
+ end
42
+
43
+ desc <<-DESC
44
+ Destroy the staging instance for the given RUBBER_ENV.
45
+ DESC
46
+ task :destroy_staging do
47
+ ENV['ALIAS'] = rubber.get_env("ALIAS", "Hostname of staging instance to be destroyed", true, RUBBER_ENV)
48
+ rubber.destroy
49
+ end
50
+
51
+ desc <<-DESC
52
+ Live tail of rails log files for all machines
53
+ By default tails the rails logs for the current RUBBER_ENV, but one can
54
+ set FILE=/path/file.*.glob to tails a different set
55
+ DESC
56
+ task :tail_logs, :roles => :app do
57
+ log_file_glob = rubber.get_env("FILE", "Log files to tail", true, "#{current_path}/log/#{RUBBER_ENV}*.log")
58
+ run "tail -qf #{log_file_glob}" do |channel, stream, data|
59
+ puts # for an extra line break before the host name
60
+ puts data
61
+ break if stream == :err
62
+ end
63
+ end
64
+
65
+ # Use instead of task to define a capistrano task that runs serially instead of in parallel
66
+ # The :groups option specifies how many groups to partition the servers into so that we can
67
+ # do the task for N (= total/groups) servers at a time. When multiple roles are supplied,
68
+ # this tries to be intelligent and slice up each role independently, but runs the slices together
69
+ # so that things don't take too long, e.g. adding an :api role to some :app servers, when restarting
70
+ # you don't want to do the api first, then the others as this would take a long time, so instead
71
+ # it does some :api and some :app, then some more of each
72
+ #
73
+ def serial_task(ns, name, options = {}, &block)
74
+ # first figure out server names for the passed in roles - when no roles
75
+ # are passed in, use all servers
76
+ serial_roles = Array(options[:roles])
77
+ servers = {}
78
+ if serial_roles.empty?
79
+ all_servers = []
80
+ self.roles.each do |rolename, serverdefs|
81
+ all_servers += serverdefs.collect {|server| server.host}
82
+ end
83
+ servers[:_serial_all] = all_servers.uniq.sort
84
+ else
85
+ # get servers for each role
86
+ self.roles.each do |rolename, serverdefs|
87
+ if serial_roles.include?(rolename)
88
+ servers[rolename] ||= []
89
+ servers[rolename] += serverdefs.collect {|server| server.host}
90
+ end
91
+ end
92
+
93
+ # Remove duplication of servers - roles which come first in list
94
+ # have precedence, so the servers show up in that group
95
+ serial_roles.each_with_index do |rolename, i|
96
+ servers[rolename] ||= []
97
+ serial_roles[i+1..-1].each do |r|
98
+ servers[r] -= servers[rolename]
99
+ end
100
+ servers[rolename] = servers[rolename].uniq.sort
101
+ end
102
+ end
103
+
104
+ # group each role's servers into slices, but combine slices across roles
105
+ slices = []
106
+ servers.each do |rolename, svrs|
107
+ next if svrs.size == 0
108
+ # figure out size of each slice by deviding server count by # of groups
109
+ slice_size = svrs.size / (options.delete(:groups) || 2)
110
+ slice_size = 1 if slice_size == 0
111
+ slice_idx = 0
112
+ svrs.each_slice(slice_size) do |srv_slice|
113
+ slices[slice_idx] ||= []
114
+ slices[slice_idx] += srv_slice
115
+ slice_idx += 1
116
+ end
117
+ end
118
+ # for each slice, define a new task specific to the hosts in that slice
119
+ task_syms = []
120
+ slices.each do |server_group|
121
+ servers = server_group.map{|s| s.gsub(/\..*/, '')}.join("_")
122
+ task_sym = "_serial_task_#{name.to_s}_#{servers}".to_sym
123
+ task_syms << task_sym
124
+ ns.task task_sym, options.merge(:hosts => server_group), &block
125
+ end
126
+
127
+ # create the top level task that calls all the serial ones
128
+ ns.task name, options do
129
+ task_syms.each do |t|
130
+ ns.send t
131
+ end
132
+ end
133
+ end
134
+
135
+ def find_alias(ip, instance_id, do_connect=true)
136
+ if instance_id
137
+ instance = rubber_instances.find {|i| i.instance_id == instance_id }
138
+ local_alias = instance.full_name if instance
139
+ end
140
+ local_alias ||= File.read("/etc/hosts").grep(/#{ip}/).first.split[1] rescue nil
141
+ if ! local_alias && do_connect
142
+ task :_get_ip, :hosts => ip do
143
+ local_alias = "* " + capture("hostname").strip
144
+ end
145
+ _get_ip rescue ConnectionError
146
+ end
147
+ return local_alias
148
+ end
149
+
150
+ def prepare_script(name, contents)
151
+ script = "/tmp/#{name}"
152
+ # this lets us abort a script if a command in the middle of it errors out
153
+ contents = "#{rubber_env.stop_on_error_cmd}\n#{contents}" if rubber_env.stop_on_error_cmd
154
+ put(contents, script)
155
+ return script
156
+ end
157
+
158
+ def run_script(name, contents)
159
+ script = prepare_script(name, contents)
160
+ run "sh #{script}"
161
+ end
162
+
163
+ def sudo_script(name, contents)
164
+ script = prepare_script(name, contents)
165
+ sudo "sh #{script}"
166
+ end
167
+
168
+ def get_env(name, desc, required=false, default=nil)
169
+ value = ENV.delete(name)
170
+ msg = "#{desc}"
171
+ msg << " [#{default}]" if default
172
+ msg << ": "
173
+ value = Capistrano::CLI.ui.ask(msg) unless value
174
+ value = value.size == 0 ? default : value
175
+ fatal "#{name} is required, pass using environment or enter at prompt" if required && ! value
176
+ return value
177
+ end
178
+
179
+ def fatal(msg, code=1)
180
+ logger.info msg
181
+ exit code
182
+ end
183
+
184
+ # Returns a map of "hostvar_<hostname>" => value for the given config value for each instance host
185
+ # This is used to run capistrano tasks scoped to the correct role/host so that a config value
186
+ # specific to a role/host will only be used for that role/host, e.g. the list of packages to
187
+ # be installed.
188
+ def get_host_options(cfg_name, &block)
189
+ opts = {}
190
+ rubber_instances.each do | ic|
191
+ env = rubber_cfg.environment.bind(ic.role_names, ic.name)
192
+ cfg_value = env[cfg_name]
193
+ if cfg_value
194
+ if block
195
+ cfg_value = block.call(cfg_value)
196
+ end
197
+ opts["hostvar_#{ic.full_name}"] = cfg_value if cfg_value && cfg_value.strip.size > 0
198
+ end
199
+ end
200
+ return opts
201
+ end
202
+
203
+ end