mdh-ec2onrails 0.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. data/CHANGELOG +180 -0
  2. data/COPYING +339 -0
  3. data/Manifest +162 -0
  4. data/README.textile +214 -0
  5. data/Rakefile +36 -0
  6. data/TODO +102 -0
  7. data/ec2onrails.gemspec +42 -0
  8. data/examples/Capfile +3 -0
  9. data/examples/deploy.rb +101 -0
  10. data/examples/s3.yml +9 -0
  11. data/lib/ec2onrails.rb +20 -0
  12. data/lib/ec2onrails/capistrano_utils.rb +43 -0
  13. data/lib/ec2onrails/recipes.rb +844 -0
  14. data/lib/ec2onrails/version.rb +31 -0
  15. data/server/build-ec2onrails.sh +44 -0
  16. data/server/files/etc/aliases +5 -0
  17. data/server/files/etc/aliases.db +0 -0
  18. data/server/files/etc/apache2/apache2.conf +295 -0
  19. data/server/files/etc/apache2/conf.d/app.proxy_cluster.conf +7 -0
  20. data/server/files/etc/apache2/conf.d/app.proxy_frontend.conf +10 -0
  21. data/server/files/etc/apache2/mods-available/proxy.conf +18 -0
  22. data/server/files/etc/apache2/sites-available/app.common +56 -0
  23. data/server/files/etc/apache2/sites-available/app.custom +0 -0
  24. data/server/files/etc/apache2/sites-available/default +14 -0
  25. data/server/files/etc/apache2/sites-available/default-ssl +19 -0
  26. data/server/files/etc/cron.d/backup_app_db_to_s3 +16 -0
  27. data/server/files/etc/cron.daily/app +9 -0
  28. data/server/files/etc/cron.daily/logrotate_post +19 -0
  29. data/server/files/etc/cron.hourly/app +10 -0
  30. data/server/files/etc/cron.monthly/app +10 -0
  31. data/server/files/etc/cron.weekly/app +10 -0
  32. data/server/files/etc/denyhosts.conf +628 -0
  33. data/server/files/etc/dpkg/dpkg.cfg +13 -0
  34. data/server/files/etc/ec2onrails/README +32 -0
  35. data/server/files/etc/ec2onrails/balancer_members +6 -0
  36. data/server/files/etc/ec2onrails/roles.yml +5 -0
  37. data/server/files/etc/environment +2 -0
  38. data/server/files/etc/god/app.god +35 -0
  39. data/server/files/etc/god/db.god +17 -0
  40. data/server/files/etc/god/examples/have_god_daemonize.god +18 -0
  41. data/server/files/etc/god/master.conf +35 -0
  42. data/server/files/etc/god/memcache.god +15 -0
  43. data/server/files/etc/god/notifications.god +14 -0
  44. data/server/files/etc/god/system.god +34 -0
  45. data/server/files/etc/god/web.god +36 -0
  46. data/server/files/etc/init.d/ec2-every-startup +29 -0
  47. data/server/files/etc/init.d/ec2-first-startup +36 -0
  48. data/server/files/etc/init.d/god +42 -0
  49. data/server/files/etc/init.d/nginx +78 -0
  50. data/server/files/etc/init.d/set_roles +3 -0
  51. data/server/files/etc/logrotate.d/apache2 +16 -0
  52. data/server/files/etc/logrotate.d/mongrel +11 -0
  53. data/server/files/etc/logrotate.d/nginx +11 -0
  54. data/server/files/etc/memcached.conf +47 -0
  55. data/server/files/etc/mongrel_cluster/app.yml +9 -0
  56. data/server/files/etc/motd.tail +13 -0
  57. data/server/files/etc/mysql/my.cnf +152 -0
  58. data/server/files/etc/nginx/nginx.conf +296 -0
  59. data/server/files/etc/postfix/main.cf +4 -0
  60. data/server/files/etc/rcS.d/S91ec2-first-startup +1 -0
  61. data/server/files/etc/rcS.d/S92ec2-every-startup +1 -0
  62. data/server/files/etc/rcS.d/S99set_roles +1 -0
  63. data/server/files/etc/ssh/sshd_config +94 -0
  64. data/server/files/etc/sudoers +1 -0
  65. data/server/files/etc/sudoers.full_access +26 -0
  66. data/server/files/etc/sudoers.restricted_access +28 -0
  67. data/server/files/etc/syslog.conf +69 -0
  68. data/server/files/usr/bin/god +26 -0
  69. data/server/files/usr/local/ec2onrails/COPYING +339 -0
  70. data/server/files/usr/local/ec2onrails/bin/archive_file.rb +44 -0
  71. data/server/files/usr/local/ec2onrails/bin/backup_app_db.rb +159 -0
  72. data/server/files/usr/local/ec2onrails/bin/ec2_meta_data.rb +80 -0
  73. data/server/files/usr/local/ec2onrails/bin/exec_runner +73 -0
  74. data/server/files/usr/local/ec2onrails/bin/init_services.rb +64 -0
  75. data/server/files/usr/local/ec2onrails/bin/optimize_mysql.rb +348 -0
  76. data/server/files/usr/local/ec2onrails/bin/rails_env +35 -0
  77. data/server/files/usr/local/ec2onrails/bin/rebundle.sh +70 -0
  78. data/server/files/usr/local/ec2onrails/bin/restore_app_db.rb +58 -0
  79. data/server/files/usr/local/ec2onrails/bin/set_rails_env +40 -0
  80. data/server/files/usr/local/ec2onrails/bin/set_roles.rb +87 -0
  81. data/server/files/usr/local/ec2onrails/bin/setup_web_proxy.rb +109 -0
  82. data/server/files/usr/local/ec2onrails/config +30 -0
  83. data/server/files/usr/local/ec2onrails/lib/aws_helper.rb +76 -0
  84. data/server/files/usr/local/ec2onrails/lib/god_helper.rb +129 -0
  85. data/server/files/usr/local/ec2onrails/lib/god_patch.rb +43 -0
  86. data/server/files/usr/local/ec2onrails/lib/mysql_helper.rb +101 -0
  87. data/server/files/usr/local/ec2onrails/lib/roles_helper.rb +151 -0
  88. data/server/files/usr/local/ec2onrails/lib/s3_helper.rb +99 -0
  89. data/server/files/usr/local/ec2onrails/lib/utils.rb +16 -0
  90. data/server/files/usr/local/ec2onrails/lib/vendor/ini.rb +268 -0
  91. data/server/files/usr/local/ec2onrails/startup-scripts/every-startup/get-hostname.sh +25 -0
  92. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/README +5 -0
  93. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/create-dirs.sh +39 -0
  94. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/generate-default-web-cert-and-key.sh +49 -0
  95. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/misc.sh +27 -0
  96. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/prepare-mysql-data-dir.sh +24 -0
  97. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/setup-credentials.sh +29 -0
  98. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/setup-file-permissions.sh +30 -0
  99. data/server/rakefile.rb +248 -0
  100. data/setup.rb +1585 -0
  101. data/test/autobench.conf +60 -0
  102. data/test/spec/lib/s3_helper_spec.rb +134 -0
  103. data/test/spec/lib/s3_old.yml +3 -0
  104. data/test/spec/test_files/test1 +0 -0
  105. data/test/spec/test_files/test2 +0 -0
  106. data/test/test_app/Capfile +3 -0
  107. data/test/test_app/README +182 -0
  108. data/test/test_app/Rakefile +10 -0
  109. data/test/test_app/app/controllers/application.rb +7 -0
  110. data/test/test_app/app/controllers/db_fast_controller.rb +6 -0
  111. data/test/test_app/app/controllers/fast_controller.rb +5 -0
  112. data/test/test_app/app/controllers/slow_controller.rb +6 -0
  113. data/test/test_app/app/controllers/very_slow_controller.rb +6 -0
  114. data/test/test_app/app/helpers/application_helper.rb +3 -0
  115. data/test/test_app/app/helpers/db_fast_helper.rb +2 -0
  116. data/test/test_app/app/helpers/fast_helper.rb +2 -0
  117. data/test/test_app/app/helpers/slow_helper.rb +2 -0
  118. data/test/test_app/app/helpers/very_slow_helper.rb +2 -0
  119. data/test/test_app/config/boot.rb +109 -0
  120. data/test/test_app/config/database.yml +19 -0
  121. data/test/test_app/config/deploy.rb +21 -0
  122. data/test/test_app/config/environment.rb +60 -0
  123. data/test/test_app/config/environments/development.rb +21 -0
  124. data/test/test_app/config/environments/production.rb +18 -0
  125. data/test/test_app/config/environments/test.rb +19 -0
  126. data/test/test_app/config/routes.rb +27 -0
  127. data/test/test_app/db/schema.rb +7 -0
  128. data/test/test_app/doc/README_FOR_APP +2 -0
  129. data/test/test_app/public/404.html +30 -0
  130. data/test/test_app/public/500.html +30 -0
  131. data/test/test_app/public/dispatch.cgi +10 -0
  132. data/test/test_app/public/dispatch.fcgi +24 -0
  133. data/test/test_app/public/dispatch.rb +10 -0
  134. data/test/test_app/public/favicon.ico +0 -0
  135. data/test/test_app/public/images/rails.png +0 -0
  136. data/test/test_app/public/javascripts/application.js +2 -0
  137. data/test/test_app/public/javascripts/controls.js +963 -0
  138. data/test/test_app/public/javascripts/dragdrop.js +972 -0
  139. data/test/test_app/public/javascripts/effects.js +1120 -0
  140. data/test/test_app/public/javascripts/prototype.js +4225 -0
  141. data/test/test_app/public/robots.txt +1 -0
  142. data/test/test_app/script/about +3 -0
  143. data/test/test_app/script/breakpointer +3 -0
  144. data/test/test_app/script/console +3 -0
  145. data/test/test_app/script/destroy +3 -0
  146. data/test/test_app/script/generate +3 -0
  147. data/test/test_app/script/performance/benchmarker +3 -0
  148. data/test/test_app/script/performance/profiler +3 -0
  149. data/test/test_app/script/performance/request +3 -0
  150. data/test/test_app/script/plugin +3 -0
  151. data/test/test_app/script/process/inspector +3 -0
  152. data/test/test_app/script/process/reaper +3 -0
  153. data/test/test_app/script/process/spawner +3 -0
  154. data/test/test_app/script/runner +3 -0
  155. data/test/test_app/script/server +3 -0
  156. data/test/test_app/test/functional/db_fast_controller_test.rb +18 -0
  157. data/test/test_app/test/functional/fast_controller_test.rb +18 -0
  158. data/test/test_app/test/functional/slow_controller_test.rb +18 -0
  159. data/test/test_app/test/functional/very_slow_controller_test.rb +18 -0
  160. data/test/test_app/test/test_helper.rb +28 -0
  161. data/test/test_ec2onrails.rb +11 -0
  162. data/test/test_helper.rb +2 -0
  163. metadata +274 -0
@@ -0,0 +1,42 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{ec2onrails}
3
+ s.version = "0.9.10"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Paul Dowman, Adam Greene"]
7
+ s.date = %q{2008-12-19}
8
+ s.description = %q{Client-side libraries (Capistrano tasks) for managing and deploying to EC2 on Rails servers.}
9
+ s.email = %q{paul@pauldowman.com}
10
+ s.extra_rdoc_files = ["CHANGELOG", "lib/ec2onrails/capistrano_utils.rb", "lib/ec2onrails/recipes.rb", "lib/ec2onrails/version.rb", "lib/ec2onrails.rb", "README.textile"]
11
+ s.files = ["CHANGELOG", "COPYING", "ec2onrails.gemspec", "examples/Capfile", "examples/deploy.rb", "examples/s3.yml", "lib/ec2onrails/capistrano_utils.rb", "lib/ec2onrails/recipes.rb", "lib/ec2onrails/version.rb", "lib/ec2onrails.rb", "Manifest", "Rakefile", "README.textile", "server/build-ec2onrails.sh", "server/files/etc/aliases", "server/files/etc/aliases.db", "server/files/etc/apache2/apache2.conf", "server/files/etc/apache2/conf.d/app.proxy_cluster.conf", "server/files/etc/apache2/conf.d/app.proxy_frontend.conf", "server/files/etc/apache2/mods-available/proxy.conf", "server/files/etc/apache2/sites-available/app.common", "server/files/etc/apache2/sites-available/app.custom", "server/files/etc/apache2/sites-available/default", "server/files/etc/apache2/sites-available/default-ssl", "server/files/etc/cron.d/backup_app_db_to_s3", "server/files/etc/cron.daily/app", "server/files/etc/cron.daily/logrotate_post", "server/files/etc/cron.hourly/app", "server/files/etc/cron.monthly/app", "server/files/etc/cron.weekly/app", "server/files/etc/denyhosts.conf", "server/files/etc/dpkg/dpkg.cfg", "server/files/etc/ec2onrails/balancer_members", "server/files/etc/ec2onrails/README", "server/files/etc/ec2onrails/roles.yml", "server/files/etc/environment", "server/files/etc/god/app.god", "server/files/etc/god/db.god", "server/files/etc/god/examples/have_god_daemonize.god", "server/files/etc/god/master.conf", "server/files/etc/god/memcache.god", "server/files/etc/god/notifications.god", "server/files/etc/god/system.god", "server/files/etc/god/web.god", "server/files/etc/init.d/ec2-every-startup", "server/files/etc/init.d/ec2-first-startup", "server/files/etc/init.d/god", "server/files/etc/init.d/nginx", "server/files/etc/init.d/set_roles", "server/files/etc/logrotate.d/apache2", "server/files/etc/logrotate.d/mongrel", "server/files/etc/logrotate.d/nginx", "server/files/etc/memcached.conf", "server/files/etc/mongrel_cluster/app.yml", "server/files/etc/motd.tail", "server/files/etc/mysql/my.cnf", "server/files/etc/nginx/nginx.conf", "server/files/etc/postfix/main.cf", "server/files/etc/rcS.d/S91ec2-first-startup", "server/files/etc/rcS.d/S92ec2-every-startup", "server/files/etc/rcS.d/S99set_roles", "server/files/etc/ssh/sshd_config", "server/files/etc/sudoers", "server/files/etc/sudoers.full_access", "server/files/etc/sudoers.restricted_access", "server/files/etc/syslog.conf", "server/files/usr/bin/god", "server/files/usr/local/ec2onrails/bin/archive_file.rb", "server/files/usr/local/ec2onrails/bin/backup_app_db.rb", "server/files/usr/local/ec2onrails/bin/ec2_meta_data.rb", "server/files/usr/local/ec2onrails/bin/exec_runner", "server/files/usr/local/ec2onrails/bin/init_services.rb", "server/files/usr/local/ec2onrails/bin/optimize_mysql.rb", "server/files/usr/local/ec2onrails/bin/rails_env", "server/files/usr/local/ec2onrails/bin/rebundle.sh", "server/files/usr/local/ec2onrails/bin/restore_app_db.rb", "server/files/usr/local/ec2onrails/bin/set_rails_env", "server/files/usr/local/ec2onrails/bin/set_roles.rb", "server/files/usr/local/ec2onrails/bin/setup_web_proxy.rb", "server/files/usr/local/ec2onrails/config", "server/files/usr/local/ec2onrails/COPYING", "server/files/usr/local/ec2onrails/lib/aws_helper.rb", "server/files/usr/local/ec2onrails/lib/god_helper.rb", "server/files/usr/local/ec2onrails/lib/god_patch.rb", "server/files/usr/local/ec2onrails/lib/mysql_helper.rb", "server/files/usr/local/ec2onrails/lib/roles_helper.rb", "server/files/usr/local/ec2onrails/lib/s3_helper.rb", "server/files/usr/local/ec2onrails/lib/utils.rb", "server/files/usr/local/ec2onrails/lib/vendor/ini.rb", "server/files/usr/local/ec2onrails/startup-scripts/every-startup/get-hostname.sh", "server/files/usr/local/ec2onrails/startup-scripts/first-startup/create-dirs.sh", "server/files/usr/local/ec2onrails/startup-scripts/first-startup/generate-default-web-cert-and-key.sh", "server/files/usr/local/ec2onrails/startup-scripts/first-startup/misc.sh", "server/files/usr/local/ec2onrails/startup-scripts/first-startup/prepare-mysql-data-dir.sh", "server/files/usr/local/ec2onrails/startup-scripts/first-startup/README", "server/files/usr/local/ec2onrails/startup-scripts/first-startup/setup-credentials.sh", "server/files/usr/local/ec2onrails/startup-scripts/first-startup/setup-file-permissions.sh", "server/rakefile.rb", "setup.rb", "test/autobench.conf", "test/spec/lib/s3_helper_spec.rb", "test/spec/lib/s3_old.yml", "test/spec/test_files/test1", "test/spec/test_files/test2", "test/test_app/app/controllers/application.rb", "test/test_app/app/controllers/db_fast_controller.rb", "test/test_app/app/controllers/fast_controller.rb", "test/test_app/app/controllers/slow_controller.rb", "test/test_app/app/controllers/very_slow_controller.rb", "test/test_app/app/helpers/application_helper.rb", "test/test_app/app/helpers/db_fast_helper.rb", "test/test_app/app/helpers/fast_helper.rb", "test/test_app/app/helpers/slow_helper.rb", "test/test_app/app/helpers/very_slow_helper.rb", "test/test_app/Capfile", "test/test_app/config/boot.rb", "test/test_app/config/database.yml", "test/test_app/config/deploy.rb", "test/test_app/config/environment.rb", "test/test_app/config/environments/development.rb", "test/test_app/config/environments/production.rb", "test/test_app/config/environments/test.rb", "test/test_app/config/routes.rb", "test/test_app/db/schema.rb", "test/test_app/doc/README_FOR_APP", "test/test_app/public/404.html", "test/test_app/public/500.html", "test/test_app/public/dispatch.cgi", "test/test_app/public/dispatch.fcgi", "test/test_app/public/dispatch.rb", "test/test_app/public/favicon.ico", "test/test_app/public/images/rails.png", "test/test_app/public/javascripts/application.js", "test/test_app/public/javascripts/controls.js", "test/test_app/public/javascripts/dragdrop.js", "test/test_app/public/javascripts/effects.js", "test/test_app/public/javascripts/prototype.js", "test/test_app/public/robots.txt", "test/test_app/Rakefile", "test/test_app/README", "test/test_app/script/about", "test/test_app/script/breakpointer", "test/test_app/script/console", "test/test_app/script/destroy", "test/test_app/script/generate", "test/test_app/script/performance/benchmarker", "test/test_app/script/performance/profiler", "test/test_app/script/performance/request", "test/test_app/script/plugin", "test/test_app/script/process/inspector", "test/test_app/script/process/reaper", "test/test_app/script/process/spawner", "test/test_app/script/runner", "test/test_app/script/server", "test/test_app/test/functional/db_fast_controller_test.rb", "test/test_app/test/functional/fast_controller_test.rb", "test/test_app/test/functional/slow_controller_test.rb", "test/test_app/test/functional/very_slow_controller_test.rb", "test/test_app/test/test_helper.rb", "test/test_ec2onrails.rb", "test/test_helper.rb", "TODO"]
12
+ s.has_rdoc = true
13
+ s.homepage = %q{http://ec2onrails.rubyforge.org}
14
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ec2onrails", "--main", "README.textile"]
15
+ s.require_paths = ["lib"]
16
+ s.rubyforge_project = %q{ec2onrails}
17
+ s.rubygems_version = %q{1.3.1}
18
+ s.summary = %q{Client-side libraries (Capistrano tasks) for managing and deploying to EC2 on Rails servers.}
19
+ s.test_files = ["test/test_app/test/functional/db_fast_controller_test.rb", "test/test_app/test/functional/fast_controller_test.rb", "test/test_app/test/functional/slow_controller_test.rb", "test/test_app/test/functional/very_slow_controller_test.rb", "test/test_app/test/test_helper.rb", "test/test_ec2onrails.rb", "test/test_helper.rb"]
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 2
24
+
25
+ if current_version >= 3 then
26
+ s.add_runtime_dependency(%q<capistrano>, [">= 0", "= 2.4.3"])
27
+ s.add_runtime_dependency(%q<archive-tar-minitar>, [">= 0", "= 0.5.2"])
28
+ s.add_runtime_dependency(%q<optiflag>, [">= 0", "= 0.6.5"])
29
+ s.add_development_dependency(%q<rake>, [">= 0.7.1"])
30
+ else
31
+ s.add_dependency(%q<capistrano>, [">= 0", "= 2.4.3"])
32
+ s.add_dependency(%q<archive-tar-minitar>, [">= 0", "= 0.5.2"])
33
+ s.add_dependency(%q<optiflag>, [">= 0", "= 0.6.5"])
34
+ s.add_dependency(%q<rake>, [">= 0.7.1"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<capistrano>, [">= 0", "= 2.4.3"])
38
+ s.add_dependency(%q<archive-tar-minitar>, [">= 0", "= 0.5.2"])
39
+ s.add_dependency(%q<optiflag>, [">= 0", "= 0.6.5"])
40
+ s.add_dependency(%q<rake>, [">= 0.7.1"])
41
+ end
42
+ end
data/examples/Capfile ADDED
@@ -0,0 +1,3 @@
1
+ load 'deploy' if respond_to?(:namespace) # cap2 differentiator
2
+ load 'config/deploy'
3
+ require 'ec2onrails/recipes'
@@ -0,0 +1,101 @@
1
+ # This is a sample Capistrano config file for EC2 on Rails.
2
+ # It should be edited and customized.
3
+
4
+ set :application, "yourapp"
5
+
6
+ set :repository, "http://svn.foo.com/svn/#{application}/trunk"
7
+
8
+ # NOTE: for some reason Capistrano requires you to have both the public and
9
+ # the private key in the same folder, the public key should have the
10
+ # extension ".pub".
11
+ ssh_options[:keys] = ["#{ENV['HOME']}/.ssh/your-ec2-key"]
12
+
13
+ # Your EC2 instances. Use the ec2-xxx....amazonaws.com hostname, not
14
+ # any other name (in case you have your own DNS alias) or it won't
15
+ # be able to resolve to the internal IP address.
16
+ role :web, "ec2-12-xx-xx-xx.z-1.compute-1.amazonaws.com"
17
+ role :app, "ec2-34-xx-xx-xx.z-1.compute-1.amazonaws.com"
18
+ role :memcache, "ec2-12-xx-xx-xx.z-1.compute-1.amazonaws.com"
19
+ role :db, "ec2-56-xx-xx-xx.z-1.compute-1.amazonaws.com", :primary => true
20
+ # role :db, "ec2-56-xx-xx-xx.z-1.compute-1.amazonaws.com", :primary => true, :ebs_vol_id => 'vol-12345abc'
21
+ # optinally, you can specify Amazon's EBS volume ID if the database is persisted
22
+ # via Amazon's EBS. See the main README for more information.
23
+
24
+ # Whatever you set here will be taken set as the default RAILS_ENV value
25
+ # on the server. Your app and your hourly/daily/weekly/monthly scripts
26
+ # will run with RAILS_ENV set to this value.
27
+ set :rails_env, "production"
28
+
29
+ # EC2 on Rails config.
30
+ # NOTE: Some of these should be omitted if not needed.
31
+ set :ec2onrails_config, {
32
+ # S3 bucket and "subdir" used by the ec2onrails:db:restore task
33
+ # NOTE: this only applies if you are not using EBS
34
+ :restore_from_bucket => "your-bucket",
35
+ :restore_from_bucket_subdir => "database",
36
+
37
+ # S3 bucket and "subdir" used by the ec2onrails:db:archive task
38
+ # This does not affect the automatic backup of your MySQL db to S3, it's
39
+ # just for manually archiving a db snapshot to a different bucket if
40
+ # desired.
41
+ # NOTE: this only applies if you are not using EBS
42
+ :archive_to_bucket => "your-other-bucket",
43
+ :archive_to_bucket_subdir => "db-archive/#{Time.new.strftime('%Y-%m-%d--%H-%M-%S')}",
44
+
45
+ # Set a root password for MySQL. Run "cap ec2onrails:db:set_root_password"
46
+ # to enable this. This is optional, and after doing this the
47
+ # ec2onrails:db:drop task won't work, but be aware that MySQL accepts
48
+ # connections on the public network interface (you should block the MySQL
49
+ # port with the firewall anyway).
50
+ # If you don't care about setting the mysql root password then remove this.
51
+ :mysql_root_password => "your-mysql-root-password",
52
+
53
+ # Any extra Ubuntu packages to install if desired
54
+ # If you don't want to install extra packages then remove this.
55
+ :packages => ["logwatch", "imagemagick"],
56
+
57
+ # Any extra RubyGems to install if desired: can be "gemname" or if a
58
+ # particular version is desired "gemname -v 1.0.1"
59
+ # If you don't want to install extra rubygems then remove this
60
+ # NOTE: if you are using rails 2.1, ec2onrails calls 'sudo rake gem:install',
61
+ # which will install gems defined in your rails configuration
62
+ :rubygems => ["rmagick", "rfacebook -v 0.9.7"],
63
+
64
+ # Defines the web proxy that will be used. Choices are :apache or :nginx
65
+ :web_proxy_server => :apache,
66
+
67
+ # extra security measures are taken if this is true, BUT it makes initial
68
+ # experimentation and setup a bit tricky. For example, if you do not
69
+ # have your ssh keys setup correctly, you will be locked out of your
70
+ # server after 3 attempts for upto 3 months.
71
+ :harden_server => false,
72
+
73
+ # Set the server timezone. run "cap -e ec2onrails:server:set_timezone" for
74
+ # details
75
+ :timezone => "UTC",
76
+
77
+ # Files to deploy to the server (they'll be owned by root). It's intended
78
+ # mainly for customized config files for new packages installed via the
79
+ # ec2onrails:server:install_packages task. Subdirectories and files inside
80
+ # here will be placed in the same structure relative to the root of the
81
+ # server's filesystem.
82
+ # If you don't need to deploy customized config files to the server then
83
+ # remove this.
84
+ :server_config_files_root => "../server_config",
85
+
86
+ # If config files are deployed, some services might need to be restarted.
87
+ # If you don't need to deploy customized config files to the server then
88
+ # remove this.
89
+ :services_to_restart => %w(postfix sysklogd),
90
+
91
+ # Set an email address to forward admin mail messages to. If you don't
92
+ # want to receive mail from the server (e.g. monit alert messages) then
93
+ # remove this.
94
+ :mail_forward_address => "you@yourdomain.com",
95
+
96
+ # Set this if you want SSL to be enabled on the web server. The SSL cert
97
+ # and key files need to exist on the server, The cert file should be in
98
+ # /etc/ssl/certs/default.pem and the key file should be in
99
+ # /etc/ssl/private/default.key (see :server_config_files_root).
100
+ :enable_ssl => true
101
+ }
data/examples/s3.yml ADDED
@@ -0,0 +1,9 @@
1
+ staging:
2
+ aws_access_key: ABC123
3
+ aws_secret_access_key: abc123abc123abc123abc123
4
+ bucket_base_name: yourbucket
5
+
6
+ production:
7
+ aws_access_key: DEF456
8
+ aws_secret_access_key: def456def456def456def456
9
+ bucket_base_name: yourbucket
data/lib/ec2onrails.rb ADDED
@@ -0,0 +1,20 @@
1
+ # This file is part of EC2 on Rails.
2
+ # http://rubyforge.org/projects/ec2onrails/
3
+ #
4
+ # Copyright 2007 Paul Dowman, http://pauldowman.com/
5
+ #
6
+ # EC2 on Rails is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # EC2 on Rails is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+
20
+ $:.unshift File.dirname(__FILE__)
@@ -0,0 +1,43 @@
1
+ module Ec2onrails
2
+ module CapistranoUtils
3
+ def run_local(command)
4
+ result = system command
5
+ raise("error: #{$?}") unless result
6
+ end
7
+
8
+ def run_init_script(script, arg)
9
+ # since init scripts might have the execute bit unset by the set_roles script we need to check
10
+ sudo "sh -c 'if [ -x /etc/init.d/#{script} ] ; then /etc/init.d/#{script} #{arg}; fi'"
11
+ end
12
+
13
+ # return hostnames for the role named role_sym that has the specified options
14
+ def hostnames_for_role(role_sym, options = {})
15
+ role = roles[role_sym]
16
+ unless role
17
+ return []
18
+ end
19
+ # make sure we match the server with all the passed in options, BUT the server can
20
+ # have additional options defined. e.g.: :primary => true and :ebs_vol_id => 'vol-1234abcd'
21
+ # but we want to select the server where :primary => true
22
+ role.select{|s|
23
+ match = true
24
+ options.each_pair{|k,v| match = false if s.options[k] != v}
25
+ }.collect{|s| s.host}
26
+ end
27
+
28
+ # Like the capture method, but does not print out error stream and swallows
29
+ # an exception if the process's exit code != 0
30
+ def quiet_capture(command, options={})
31
+ output = ""
32
+ invoke_command(command, options.merge(:once => true)) do |ch, stream, data|
33
+ case stream
34
+ when :out then output << data
35
+ # when :err then warn "[err :: #{ch[:server]}] #{data}"
36
+ end
37
+ end
38
+ ensure
39
+ return (output || '').strip
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,844 @@
1
+ # This file is part of EC2 on Rails.
2
+ # http://rubyforge.org/projects/ec2onrails/
3
+ #
4
+ # Copyright 2007 Paul Dowman, http://pauldowman.com/
5
+ #
6
+ # EC2 on Rails is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # EC2 on Rails is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require 'fileutils'
20
+ include FileUtils
21
+ require 'tmpdir'
22
+ require 'pp'
23
+ require 'zlib'
24
+ require 'archive/tar/minitar'
25
+ include Archive::Tar
26
+
27
+ require 'ec2onrails/version'
28
+ require 'ec2onrails/capistrano_utils'
29
+ include Ec2onrails::CapistranoUtils
30
+
31
+ Capistrano::Configuration.instance.load do
32
+
33
+ unless ec2onrails_config
34
+ raise "ec2onrails_config variable not set. (It should be a hash.)"
35
+ end
36
+
37
+ cfg = ec2onrails_config
38
+
39
+ #:apache or :nginx
40
+ cfg[:web_proxy_server] ||= :apache
41
+
42
+ set :ec2onrails_version, Ec2onrails::VERSION::STRING
43
+ set :image_id_32_bit, Ec2onrails::VERSION::AMI_ID_32_BIT
44
+ set :image_id_64_bit, Ec2onrails::VERSION::AMI_ID_64_BIT
45
+ set :deploy_to, "/mnt/app"
46
+ set :use_sudo, false
47
+ set :user, "app"
48
+
49
+ #in case any changes were made to the configs, like changing the number of mongrels
50
+ before "deploy:cold", "ec2onrails:server:grant_sudo_access"
51
+ after "deploy:symlink", "ec2onrails:server:set_roles", "ec2onrails:server:init_services"
52
+ after "deploy:cold", "ec2onrails:db:init_backup", "ec2onrails:db:optimize", "ec2onrails:server:restrict_sudo_access"
53
+ after "ec2onrails:server:install_gems", "ec2onrails:server:add_gem_sources"
54
+
55
+ #NOTE: some default setups (like engineyard's) do some symlinking of config files after
56
+ # deploy:update_code. The ordering here matters as we need to have those symlinks in place
57
+ # but we need to have the gems in place before the rails env is loaded up, or else it will
58
+ # fail. By adding it to the callback queue AFTER all the tasks have loaded up, we make sure
59
+ # it is done at the very end.
60
+ #
61
+ # *IF* you had tasks also triggered after update_code that run rake tasks
62
+ # (like compressing javascript and stylesheets), move those over to before "deploy:symlink"
63
+ # and you'll be set!
64
+ on :load do
65
+ after "deploy:update_code", "ec2onrails:server:run_rails_rake_gems_install"
66
+ end
67
+
68
+
69
+ # override default start/stop/restart tasks
70
+ namespace :deploy do
71
+ desc <<-DESC
72
+ Overrides the default Capistrano deploy:start, uses \
73
+ 'god start app'
74
+ DESC
75
+ task :start, :roles => :app do
76
+ sudo "god start app"
77
+ # sudo "god monitor app"
78
+ end
79
+
80
+ desc <<-DESC
81
+ Overrides the default Capistrano deploy:stop, uses \
82
+ 'god stop app'
83
+ DESC
84
+ task :stop, :roles => :app do
85
+ # sudo "god unmonitor app"
86
+ sudo "god stop app"
87
+ end
88
+
89
+ desc <<-DESC
90
+ Overrides the default Capistrano deploy:restart, uses \
91
+ 'god restart app'
92
+ DESC
93
+ task :restart, :roles => :app do
94
+ sudo "god restart app"
95
+ end
96
+ end
97
+
98
+ namespace :ec2onrails do
99
+ desc <<-DESC
100
+ Show the AMI id's of the current images for this version of \
101
+ EC2 on Rails.
102
+ DESC
103
+ task :ami_ids do
104
+ puts "32-bit server image for EC2 on Rails #{ec2onrails_version}: #{image_id_32_bit}"
105
+ puts "64-bit server image for EC2 on Rails #{ec2onrails_version}: #{image_id_64_bit}"
106
+ end
107
+
108
+ desc <<-DESC
109
+ Copies the public key from the server using the external "ssh"
110
+ command because Net::SSH, which is used by Capistrano, needs it.
111
+ This will only work if you have an ssh command in the path.
112
+ If Capistrano can successfully connect to your EC2 instance you
113
+ don't need to do this. It will copy from the first server in the
114
+ :app role, this can be overridden by specifying the HOST
115
+ environment variable
116
+ DESC
117
+ task :get_public_key_from_server do
118
+ host = find_servers_for_task(current_task).first.host
119
+ privkey = ssh_options[:keys][0]
120
+ pubkey = "#{privkey}.pub"
121
+ msg = <<-MSG
122
+ Your first key in ssh_options[:keys] is #{privkey}, presumably that's
123
+ your EC2 private key. The public key will be copied from the server
124
+ named '#{host}' and saved locally as #{pubkey}. Continue? [y/n]
125
+ MSG
126
+ choice = nil
127
+ while choice != "y" && choice != "n"
128
+ choice = Capistrano::CLI.ui.ask(msg).downcase
129
+ msg = "Please enter 'y' or 'n'."
130
+ end
131
+ if choice == "y"
132
+ run_local "scp -i '#{privkey}' app@#{host}:.ssh/authorized_keys #{pubkey}"
133
+ end
134
+ end
135
+
136
+ desc <<-DESC
137
+ Prepare a newly-started instance for a cold deploy.
138
+ DESC
139
+ task :setup do
140
+ ec2onrails.server.allow_sudo do
141
+ server.set_mail_forward_address
142
+ server.set_timezone
143
+ server.install_packages
144
+ server.install_gems
145
+ server.deploy_files
146
+ server.setup_web_proxy
147
+ server.set_roles
148
+ server.enable_ssl if cfg[:enable_ssl]
149
+ server.set_rails_env
150
+ server.restart_services
151
+ deploy.setup
152
+ db.create
153
+ server.harden_server
154
+ db.enable_ebs
155
+ end
156
+ end
157
+
158
+ desc <<-DESC
159
+ Deploy and restore database from S3
160
+ DESC
161
+ task :restore_db_and_deploy do
162
+ db.recreate
163
+ deploy.update_code
164
+ deploy.symlink
165
+ db.restore
166
+ deploy.migrations
167
+ end
168
+
169
+ namespace :ec2 do
170
+ desc <<-DESC
171
+ DESC
172
+ task :configure_firewall do
173
+ # TODO
174
+ end
175
+ end
176
+
177
+ namespace :db do
178
+ desc <<-DESC
179
+ [internal] Load configuration info for the database from
180
+ config/database.yml, and start mysql (it must be running
181
+ in order to interact with it).
182
+ DESC
183
+ task :load_config do
184
+ unless hostnames_for_role(:db, :primary => true).empty?
185
+ db_config = YAML::load(ERB.new(File.read("config/database.yml")).result)[rails_env.to_s] || {}
186
+ cfg[:db_name] ||= db_config['database']
187
+ cfg[:db_user] ||= db_config['username'] || db_config['user']
188
+ cfg[:db_password] ||= db_config['password']
189
+ cfg[:db_host] ||= db_config['host']
190
+ cfg[:db_port] ||= db_config['port']
191
+ cfg[:db_socket] ||= db_config['socket']
192
+
193
+ if (cfg[:db_host].nil? || cfg[:db_host].empty?) && (cfg[:db_socket].nil? || cfg[:db_socket].empty?)
194
+ raise "ERROR: missing database config. Make sure database.yml contains a '#{rails_env}' section with either 'host: hostname' or 'socket: /var/run/mysqld/mysqld.sock'."
195
+ end
196
+
197
+ [cfg[:db_name], cfg[:db_user], cfg[:db_password]].each do |s|
198
+ if s.nil? || s.empty?
199
+ raise "ERROR: missing database config. Make sure database.yml contains a '#{rails_env}' section with a database name, user, and password."
200
+ elsif s.match(/['"]/)
201
+ raise "ERROR: database config string '#{s}' contains quotes."
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ desc <<-DESC
208
+ Create the MySQL database. Assumes there is no MySQL root \
209
+ password. To create a MySQL root password create a task that's run \
210
+ after this task using an after hook.
211
+ DESC
212
+ task :create, :roles => :db do
213
+ on_rollback { drop }
214
+ load_config
215
+ start
216
+ sleep(5) #make sure the db has some time to start up!
217
+
218
+
219
+ # remove the default test database, though sometimes it doesn't exist (perhaps it isn't there anymore?)
220
+ run %{mysql -u root -e "drop database if exists test; flush privileges;"}
221
+
222
+ # removing anonymous mysql accounts
223
+ run %{mysql -u root -D mysql -e "delete from db where User = ''; flush privileges;"}
224
+ run %{mysql -u root -D mysql -e "delete from user where User = ''; flush privileges;"}
225
+
226
+ # qoting of database names allows special characters eg (the-database-name)
227
+ # the quotes need to be double escaped. Once for capistrano and once for the host shell
228
+ run %{mysql -u root -e "create database if not exists \\`#{cfg[:db_name]}\\`;"}
229
+ run %{mysql -u root -e "grant all on \\`#{cfg[:db_name]}\\`.* to '#{cfg[:db_user]}'@'%' identified by '#{cfg[:db_password]}';"}
230
+ run %{mysql -u root -e "grant reload on *.* to '#{cfg[:db_user]}'@'%' identified by '#{cfg[:db_password]}';"}
231
+ run %{mysql -u root -e "grant super on *.* to '#{cfg[:db_user]}'@'%' identified by '#{cfg[:db_password]}';"}
232
+ end
233
+
234
+ desc <<-DESC
235
+ Move the MySQL database to Amazon's Elastic Block Store (EBS), \
236
+ which is a persistant data store for the cloud.
237
+ OPTIONAL PARAMETERS:
238
+ * SIZE: Pass in num in gigs, like 10, to set the size, otherwise it will \
239
+ default to 10 gigs.
240
+ * VOLUME_ID: The volume_id to use for the mysql database
241
+ NOTE: keep track of the volume ID, as you'll want to keep this for your \
242
+ records and probably add it to the :db role in your deploy.rb file \
243
+ (see the ec2onrails sample deploy.rb file for additional information)
244
+ DESC
245
+ task :enable_ebs, :roles => :db, :only => { :primary => true } do
246
+ # based off of Eric's work:
247
+ # http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1663&categoryID=100
248
+ #
249
+ # EXPLAINATION:
250
+ # There is a lot going on here! At the end, the setup should be:
251
+ # * create EBS volume if run outside of the ec2onrails:setup and
252
+ # VOLUME_ID is not passed in when the cap task is called
253
+ # * EBS volume attached to /dev/sdh
254
+ # * format to xfs if new or do a xfs_check if previously existed
255
+ # * mounted on /var/local and update /etc/fstab
256
+ # * move /mnt/mysql_data -> /var/local/mysql_data
257
+ # * move /mnt/log/mysql -> /var/local/log/mysql
258
+ # * change mysql configs by writing /etc/mysql/conf.d/mysql-ec2-ebs.cnf
259
+ # * keep a copy of the mysql configs with the EBS volume, and if that volume is hooked into
260
+ # another instance, make sure the mysql configs that go with that volume are symlinked to /etc/mysql
261
+ # * update the file locations of the mysql binary logs in /mnt/log/mysql/mysql-bin.index
262
+ # * symlink the moved folders to their old position... makes the move to EBS transparent
263
+ # * Amazon doesn't contain EBS information in the meta-data API (yet). So write
264
+ # /etc/ec2onrails/ebs_info.yml
265
+ # to contain the meta-data information that we need
266
+ #
267
+ # DESIGN CONSIDERATIONS
268
+ # * only moving mysql data to EBS. seems the most obvious, and if we move over other components
269
+ # we will have to share that bandwidth (1 Gbps pipe to SAN). So limiting to what we really need
270
+ # * not moving all mysql logic over (tmp scratch space stays local). Again, this is to limit
271
+ # unnecessary bandwidth usage, PLUS, we are charged per million IO to EBS
272
+ #
273
+ # TODO:
274
+ # * make sure if we have a predefined ebs_vol_id, that we error out with a nice msg IF the zones do not match
275
+ # * can we move more of the mysql cache files back to the local disk and off of EBS, like the innodb table caches?
276
+ # * right now we force this task to only be run on one server; that works for db :primary => true
277
+ # But what is the best way to make this work if it needs to setup multiple servers (like db slaves)?
278
+ # I need to figure out how to do a direct mapping from a server definition to a ebs_vol_id
279
+ # * when we enable slaves and we setup ebs volumes on them, make it transparent to the user.
280
+ # have the slave create a snapshot of the db.master volume, and then use that to mount from
281
+ # * need to do a rollback that if the volume is created but something fails, lets uncreate it?
282
+ # carefull though! If it fails towards the end when information is copied over, it could cause information
283
+ # to be lost!
284
+ #
285
+
286
+ mysql_dir_root = '/var/local'
287
+ block_mnt = '/dev/sdh'
288
+ servers = find_servers_for_task(current_task)
289
+
290
+ if servers.empty?
291
+ raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
292
+ elsif servers.size > 1
293
+ raise Capistrano::Error, "`#{task.fully_qualified_name}' is can only be run on one server, not #{server.size}"
294
+ end
295
+
296
+ vol_id = ENV['VOLUME_ID'] || servers.first.options[:ebs_vol_id]
297
+
298
+ #HACK! capistrano doesn't allow arguments to be passed in if we call this task as a method, like 'db.enable_ebs'
299
+ # the places where we do call it like that, we don't want to force a move to ebs, so....
300
+ # if the call frame is > 1 (ie, another task called it), do NOT force the ebs move
301
+ no_force = task_call_frames.size > 1
302
+ prev_created = !(vol_id.nil? || vol_id.empty?)
303
+ #no vol_id was passed in, but perhaps it is already mounted...?
304
+ prev_created = true if !quiet_capture("mount | grep -inr '#{mysql_dir_root}' || echo ''").empty?
305
+
306
+ unless no_force && (vol_id.nil? || vol_id.empty?)
307
+ zone = quiet_capture("/usr/local/ec2onrails/bin/ec2_meta_data.rb -key 'placement/availability-zone'")
308
+ instance_id = quiet_capture("/usr/local/ec2onrails/bin/ec2_meta_data.rb -key 'instance-id'")
309
+
310
+ unless prev_created
311
+ puts "creating new ebs volume...."
312
+ size = ENV["SIZE"] || "10"
313
+ cmd = "ec2-create-volume -s #{size} -z #{zone} 2>&1"
314
+ puts "running: #{cmd}"
315
+ output = `#{cmd}`
316
+ puts output
317
+ vol_id = (output =~ /^VOLUME\t(.+?)\t/ && $1)
318
+ puts "NOTE: remember that vol_id"
319
+ sleep(2)
320
+ end
321
+ vol_id.strip! if vol_id
322
+ if quiet_capture("mount | grep -inr '#{block_mnt}' || echo ''").empty?
323
+ cmd = "ec2-attach-volume -d #{block_mnt} -i #{instance_id} #{vol_id} 2>&1"
324
+ puts "running: #{cmd}"
325
+ output = `#{cmd}`
326
+ puts output
327
+ if output =~ /Client.InvalidVolume.ZoneMismatch/i
328
+ raise Exception, "The volume you are trying to attach does not reside in the zone of your instance. Stopping!"
329
+ end
330
+
331
+
332
+ sleep(10)
333
+ end
334
+
335
+ ec2onrails.server.allow_sudo do
336
+ # try to format the volume... if it is already formatted, lets run a check on
337
+ # it to make sure it is ok, and then continue on
338
+ # if errors, the device is busy...something else is going on here and it is already mounted... skip!
339
+ if prev_created
340
+ # Stop the db (mysql server) for cases where this is being run after the original run
341
+ # If EBS partiion is already mounted and being used by mysql, it will fail when umount is run
342
+ god_status = quiet_capture("sudo god status")
343
+ god_status = god_status.empty? ? {} : YAML::load(god_status)
344
+ start_stop_db = false
345
+ start_stop_db = god_status['db']['mysql'] == 'up'
346
+ if start_stop_db
347
+ stop
348
+ puts "Waiting for mysql to stop"
349
+ sleep(10)
350
+ end
351
+ quiet_capture("sudo umount #{mysql_dir_root}") #unmount if need to
352
+ sudo "xfs_check #{block_mnt}"
353
+ # Restart the db if it
354
+ start if start_stop_db
355
+ else
356
+ sudo "mkfs.xfs #{block_mnt}"
357
+ end
358
+
359
+ # if not added to /etc/fstab, lets do so
360
+ sudo "sh -c \"grep -iqn '#{mysql_dir_root}' /etc/fstab || echo '#{block_mnt} #{mysql_dir_root} xfs noatime 0 0' >> /etc/fstab\""
361
+ sudo "mkdir -p #{mysql_dir_root}"
362
+ #if not already mounted, lets mount it
363
+ sudo "sh -c \"mount | grep -iqn '#{mysql_dir_root}' || mount '#{mysql_dir_root}'\""
364
+
365
+ #ok, now lets move the mysql stuff off of /mnt -> mysql_dir_root
366
+ stop rescue nil #already stopped
367
+ sudo "mkdir -p #{mysql_dir_root}/log"
368
+ #move the data over, but keep a symlink to the new location for backwards compatibility
369
+ #and do not do it if /mnt/mysql_data has already been moved
370
+ quiet_capture("sudo sh -c 'test ! -d #{mysql_dir_root}/mysql_data && mv /mnt/mysql_data #{mysql_dir_root}/'")
371
+ sudo "mv /mnt/mysql_data /mnt/mysql_data_old 2>/dev/null || echo"
372
+ sudo "ln -fs #{mysql_dir_root}/mysql_data /mnt/mysql_data"
373
+
374
+ #but keep the tmpdir on mnt
375
+ sudo "sh -c 'mkdir -p /mnt/tmp/mysql && chown mysql:mysql /mnt/tmp/mysql'"
376
+ #move the logs over, but keep a symlink to the new location for backwards compatibility
377
+ #and do not do it if the logs have already been moved
378
+ quiet_capture("sudo sh -c 'test ! -d #{mysql_dir_root}/log/mysql_data && mv /mnt/log/mysql #{mysql_dir_root}/log/'")
379
+ sudo "ln -fs #{mysql_dir_root}/log/mysql /mnt/log/mysql"
380
+ quiet_capture("sudo sh -c \"test -f #{mysql_dir_root}/log/mysql/mysql-bin.index && \
381
+ perl -pi -e 's%/mnt/log/%#{mysql_dir_root}/log/%' #{mysql_dir_root}/log/mysql/mysql-bin.index\"") rescue false
382
+
383
+ if quiet_capture("test -d /var/local/etc/mysql && echo 'yes'").empty?
384
+ txt = <<-FILE
385
+ [mysqld]
386
+ datadir = #{mysql_dir_root}/mysql_data
387
+ tmpdir = /mnt/tmp/mysql
388
+ log_bin = #{mysql_dir_root}/log/mysql/mysql-bin.log
389
+ log_slow_queries = #{mysql_dir_root}/log/mysql/mysql-slow.log
390
+ FILE
391
+ put txt, '/tmp/mysql-ec2-ebs.cnf'
392
+ sudo 'mv /tmp/mysql-ec2-ebs.cnf /etc/mysql/conf.d/mysql-ec2-ebs.cnf'
393
+
394
+ #keep a copy
395
+ sudo "rsync -aR /etc/mysql #{mysql_dir_root}/"
396
+ end
397
+ # lets use the mysql configs on the EBS volume
398
+ sudo "mv /etc/mysql /etc/mysql.orig 2>/dev/null"
399
+ sudo "ln -sf #{mysql_dir_root}/etc/mysql /etc/mysql"
400
+
401
+ #just put a README on the drive so we know what this volume is for!
402
+ txt = <<-FILE
403
+ This volume is setup to be used by Ec2onRails in conjunction with Amazon's EBS, for primary MySql database persistence.
404
+ RAILS_ENV: #{fetch(:rails_env, 'undefined')}
405
+ DOMAIN: #{fetch(:domain, 'undefined')}
406
+
407
+ Modify this volume at your own risk
408
+ FILE
409
+
410
+ put txt, "/tmp/VOLUME-README"
411
+ sudo "mv /tmp/VOLUME-README #{mysql_dir_root}/VOLUME-README"
412
+ #update the list of ebs volumes
413
+ #TODO: abstract this away into a helper method!!
414
+ #TODO: this first touch should *not* be needed... quiet_capture should return an empty string
415
+ # if the cat on a non-existant file fails (as it should). this isn't causing issues
416
+ # for me, but a few users have complained.... bad gemspec or something?
417
+ # COMMENTING OUT for now to see if the recent gemspec update improved things...
418
+ # ebs_info = quiet_capture("touch /etc/ec2onrails/ebs_info.yml")
419
+ ebs_info = quiet_capture("cat /etc/ec2onrails/ebs_info.yml")
420
+ ebs_info = ebs_info.empty? ? {} : YAML::load(ebs_info)
421
+ ebs_info[mysql_dir_root] = {'block_loc' => block_mnt, 'volume_id' => vol_id}
422
+ put(ebs_info.to_yaml, "/tmp/ebs_info.yml")
423
+ sudo "mv /tmp/ebs_info.yml /etc/ec2onrails/ebs_info.yml"
424
+ #lets start it back up
425
+ start
426
+ end #end of sudo
427
+ end
428
+ end
429
+
430
+
431
+ desc <<-DESC
432
+ [internal] Make sure the MySQL server has been started, just in case the db role
433
+ hasn't been set, e.g. when called from ec2onrails:setup.
434
+ (But don't enable monitoring on it.)
435
+ DESC
436
+ task :start, :roles => :db do
437
+ sudo "god start db"
438
+ # sudo "god monitor db"
439
+ end
440
+
441
+ task :stop, :roles => :db do
442
+ # sudo "god unmonitor db"
443
+ sudo "god stop db"
444
+ end
445
+
446
+
447
+ desc <<-DESC
448
+ Drop the MySQL database. Assumes there is no MySQL root \
449
+ password. If there is a MySQL root password, create a task that removes \
450
+ it and run that task before this one using a before hook.
451
+ DESC
452
+ task :drop, :roles => :db do
453
+ load_config
454
+ run %{mysql -u root -e "drop database if exists \\`#{cfg[:db_name]}\\`;"}
455
+ end
456
+
457
+ desc <<-DESC
458
+ db:drop and db:create.
459
+ DESC
460
+ task :recreate, :roles => :db do
461
+ drop
462
+ create
463
+ end
464
+
465
+ desc <<-DESC
466
+ Set a root password for MySQL, using the variable mysql_root_password \
467
+ if it is set. If this is done db:drop won't work.
468
+ DESC
469
+ task :set_root_password, :roles => :db do
470
+ if cfg[:mysql_root_password]
471
+ run %{mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('#{cfg[:mysql_root_password]}') WHERE User='root'; FLUSH PRIVILEGES;"}
472
+ end
473
+ end
474
+
475
+ desc <<-DESC
476
+ Dump the MySQL database to the S3 bucket specified by \
477
+ ec2onrails_config[:archive_to_bucket]. The filename will be \
478
+ "database-archive/<timestamp>/dump.sql.gz".
479
+ DESC
480
+ task :archive, :roles => :db do
481
+ run "/usr/local/ec2onrails/bin/backup_app_db.rb --bucket #{cfg[:archive_to_bucket]} --dir #{cfg[:archive_to_bucket_subdir]}"
482
+ end
483
+
484
+ desc <<-DESC
485
+ Restore the MySQL database from the S3 bucket specified by \
486
+ ec2onrails_config[:restore_from_bucket]. The archive filename is \
487
+ expected to be the default, "mysqldump.sql.gz".
488
+ DESC
489
+ task :restore, :roles => :db do
490
+ run "/usr/local/ec2onrails/bin/restore_app_db.rb --bucket #{cfg[:restore_from_bucket]} --dir #{cfg[:restore_from_bucket_subdir]}"
491
+ end
492
+
493
+ desc <<-DESC
494
+ [internal] Initialize the default backup folder on S3 (i.e. do a full
495
+ backup of the newly-created db so the automatic incremental backups
496
+ make sense).
497
+ DESC
498
+ task :init_backup, :roles => :db do
499
+ server.allow_sudo do
500
+ sudo "/usr/local/ec2onrails/bin/backup_app_db.rb --reset"
501
+ end
502
+ end
503
+
504
+ # do NOT run if the flag does not exist. This is placed by a startup script
505
+ # and it is only run on the first-startup. This means after the db has been
506
+ # optimized, this task will not work again.
507
+ #
508
+ # Of course you can overload it or call the file directly
509
+ task :optimize, :roles => :db do
510
+ if !quiet_capture("test -e /tmp/optimize_db_flag && echo 'file exists'").empty?
511
+ begin
512
+ sudo "/usr/local/ec2onrails/bin/optimize_mysql.rb"
513
+ ensure
514
+ sudo "rm -rf /tmp/optimize_db_flag" #remove so we cannot run again
515
+ end
516
+ else
517
+ puts "skipping as it looks like this task has already been run"
518
+ end
519
+ end
520
+
521
+ end
522
+
523
+ namespace :server do
524
+ desc <<-DESC
525
+ Tell the servers what roles they are in. This configures them with \
526
+ the appropriate settings for each role, and starts and/or stops the \
527
+ relevant services.
528
+ DESC
529
+ task :set_roles do
530
+ # TODO generate this based on the roles that actually exist so arbitrary new ones can be added
531
+ roles = {
532
+ :web => hostnames_for_role(:web),
533
+ :app => hostnames_for_role(:app),
534
+ :db_primary => hostnames_for_role(:db, :primary => true),
535
+ # doing th ebelow can cause errors elsewhere unless :db is populated.
536
+ # :db => hostnames_for_role(:db),
537
+ :memcache => hostnames_for_role(:memcache)
538
+ }
539
+ roles_yml = YAML::dump(roles)
540
+ put roles_yml, "/tmp/roles.yml"
541
+ server.allow_sudo do
542
+ sudo "cp /tmp/roles.yml /etc/ec2onrails"
543
+ #we want everyone to be able to read to it
544
+ sudo "chmod a+r /etc/ec2onrails/roles.yml"
545
+ sudo "/usr/local/ec2onrails/bin/set_roles.rb"
546
+ end
547
+ end
548
+
549
+ task :init_services do
550
+ server.allow_sudo do
551
+ sudo "/usr/local/ec2onrails/bin/init_services.rb"
552
+ end
553
+ end
554
+
555
+ task :setup_web_proxy, :roles => :web do
556
+ sudo "/usr/local/ec2onrails/bin/setup_web_proxy.rb --mode #{cfg[:web_proxy_server].to_s}"
557
+ end
558
+
559
+ desc <<-DESC
560
+ Change the default value of RAILS_ENV on the server. Technically
561
+ this changes the server's mongrel config to use a different value
562
+ for "environment". The value is specified in :rails_env.
563
+ Be sure to do deploy:restart after this.
564
+ DESC
565
+ task :set_rails_env do
566
+ rails_env = fetch(:rails_env, "production")
567
+ sudo "/usr/local/ec2onrails/bin/set_rails_env #{rails_env}"
568
+ end
569
+
570
+ desc <<-DESC
571
+ Upgrade to the newest versions of all Ubuntu packages.
572
+ DESC
573
+ task :upgrade_packages do
574
+ sudo "aptitude -q update"
575
+ sudo "sh -c 'export DEBIAN_FRONTEND=noninteractive; aptitude -q -y safe-upgrade'"
576
+ end
577
+
578
+ desc <<-DESC
579
+ Upgrade to the newest versions of all rubygems.
580
+ DESC
581
+ task :upgrade_gems do
582
+ sudo "gem update --system --no-rdoc --no-ri"
583
+ sudo "gem update --no-rdoc --no-ri" do |ch, str, data|
584
+ ch[:data] ||= ""
585
+ ch[:data] << data
586
+ if data =~ />\s*$/
587
+ puts data
588
+ choice = Capistrano::CLI.ui.ask("The gem command is asking for a number:")
589
+ ch.send_data("#{choice}\n")
590
+ else
591
+ puts data
592
+ end
593
+ end
594
+ end
595
+
596
+ desc <<-DESC
597
+ Install extra Ubuntu packages. Set ec2onrails_config[:packages], it \
598
+ should be an array of strings.
599
+ NOTE: the package installation will be non-interactive, if the packages \
600
+ require configuration either set ec2onrails_config[:interactive_packages] \
601
+ like you would for ec2onrails_config[:packages] (we'll flood the server \
602
+ with 'Y' inputs), or log in as 'root' and run \
603
+ 'dpkg-reconfigure packagename' or replace the package's config files \
604
+ using the 'ec2onrails:server:deploy_files' task.
605
+ DESC
606
+ task :install_packages do
607
+ sudo "aptitude -q update"
608
+ if cfg[:packages] && cfg[:packages].any?
609
+ sudo "sh -c 'export DEBIAN_FRONTEND=noninteractive; aptitude -q -y install #{cfg[:packages].join(' ')}'"
610
+ end
611
+ if cfg[:interactive_packages] && cfg[:interactive_packages].any?
612
+ # sudo "aptitude install #{cfg[:interactive_packages].join(' ')}", {:env => {'DEBIAN_FRONTEND' => 'readline'} }
613
+ #trying to pick WHEN to send a Y is a bit tricky...it totally depends on the
614
+ #interactive package you want to install. FLOODING it with 'Y'... but not sure how
615
+ #'correct' or robust this is
616
+ cmd = "sudo sh -c 'export DEBIAN_FRONTEND=readline; aptitude -y -q install #{cfg[:interactive_packages].join(' ')}'"
617
+ run(cmd) do |channel, stream, data|
618
+ channel.send_data "Y\n"
619
+ end
620
+ end
621
+ end
622
+
623
+ desc <<-DESC
624
+ Provide extra security measures. Set ec2onrails_config[:harden_server] = true \
625
+ to allow the hardening of the server.
626
+ These security measures are those which can make initial setup and playing around
627
+ with Ec2onRails tricky. For example, you can be logged out of your server forever
628
+ DESC
629
+ task :harden_server do
630
+ #NOTES: for those security features that will get in the way of ease-of-use
631
+ # hook them in here
632
+ if cfg[:harden_server]
633
+ #lets install some extra packages:
634
+ # denyhosts: sshd security tool. config file is already installed...
635
+ #
636
+ security_pkgs = %w{denyhosts}
637
+ sudo "sh -c 'export DEBIAN_FRONTEND=noninteractive; aptitude -q -y install #{security_pkgs.join(' ')}'"
638
+ end
639
+ end
640
+
641
+ desc <<-DESC
642
+ Install extra rubygems. Set ec2onrails_config[:rubygems], it should \
643
+ be with an array of strings.
644
+ DESC
645
+ task :install_gems do
646
+ if cfg[:rubygems]
647
+ cfg[:rubygems].each do |gem|
648
+ sudo "gem install #{gem} --no-rdoc --no-ri" do |ch, str, data|
649
+ ch[:data] ||= ""
650
+ ch[:data] << data
651
+ if data =~ />\s*$/
652
+ puts data
653
+ choice = Capistrano::CLI.ui.ask("The gem command is asking for a number:")
654
+ ch.send_data("#{choice}\n")
655
+ else
656
+ puts data
657
+ end
658
+ end
659
+ end
660
+ end
661
+ end
662
+
663
+ task :run_rails_rake_gems_install do
664
+ #if running under Rails 2.1, lets trigger 'rake gems:install', but in such a way
665
+ #so it fails gracefully if running rails < 2.1
666
+ # ALSO, this might be the first time rake is run, and running it as sudo means that
667
+ # if any plugins are loaded and create directories... like what image_science does for
668
+ # ruby_inline, then the dirs will be created as root. so trigger the rails loading
669
+ # very quickly before the sudo is called
670
+ # run "cd #{release_path} && rake RAILS_ENV=#{rails_env} -T 1>/dev/null && sudo rake RAILS_ENV=#{rails_env} gems:install"
671
+ ec2onrails.server.allow_sudo do
672
+ output = quiet_capture "cd #{release_path} && rake RAILS_ENV=#{rails_env} db:version 2>&1 1>/dev/null || sudo rake RAILS_ENV=#{rails_env} gems:install"
673
+ puts output
674
+ end
675
+ end
676
+
677
+ desc <<-DESC
678
+ Add extra gem sources to rubygems (to able to fetch gems from for example gems.github.com).
679
+ Set ec2onrails_config[:rubygems_sources], it should be with an array of strings.
680
+ DESC
681
+ task :add_gem_sources do
682
+ if cfg[:rubygems_sources]
683
+ cfg[:rubygems_sources].each do |gem_source|
684
+ sudo "gem sources -a #{gem_source}"
685
+ end
686
+ end
687
+ end
688
+
689
+ desc <<-DESC
690
+ A convenience task to upgrade existing packages and gems and install \
691
+ specified new ones.
692
+ DESC
693
+ task :upgrade_and_install_all do
694
+ upgrade_packages
695
+ upgrade_gems
696
+ install_packages
697
+ install_gems
698
+ end
699
+
700
+ desc <<-DESC
701
+ Set the timezone using the value of the variable named timezone. \
702
+ Valid options for timezone can be determined by the contents of \
703
+ /usr/share/zoneinfo, which can be seen here: \
704
+ http://packages.ubuntu.com/cgi-bin/search_contents.pl?searchmode=filelist&word=tzdata&version=gutsy&arch=all&page=1&number=all \
705
+ Remove 'usr/share/zoneinfo/' from the filename, and use the last \
706
+ directory and file as the value. For example 'Africa/Abidjan' or \
707
+ 'posix/GMT' or 'Canada/Eastern'.
708
+ DESC
709
+ task :set_timezone do
710
+ if cfg[:timezone]
711
+ ec2onrails.server.allow_sudo do
712
+ sudo "bash -c 'echo #{cfg[:timezone]} > /etc/timezone'"
713
+ sudo "cp /usr/share/zoneinfo/#{cfg[:timezone]} /etc/localtime"
714
+ end
715
+ end
716
+ end
717
+
718
+ desc <<-DESC
719
+ Deploy a set of config files to the server, the files will be owned by \
720
+ root. This doesn't delete any files from the server. This is intended
721
+ mainly for customized config files for new packages installed via the \
722
+ ec2onrails:server:install_packages task. Subdirectories and files \
723
+ inside here will be placed within the same directory structure \
724
+ relative to the root of the server's filesystem.
725
+ DESC
726
+ task :deploy_files do
727
+ if cfg[:server_config_files_root]
728
+ begin
729
+ filename = "config_files.tar"
730
+ local_file = "#{Dir.tmpdir}/#{filename}"
731
+ remote_file = "/tmp/#{filename}"
732
+ FileUtils.cd(cfg[:server_config_files_root]) do
733
+ File.open(local_file, 'wb') { |tar| Minitar.pack(".", tar) }
734
+ end
735
+ put File.read(local_file), remote_file
736
+ sudo "tar xvf #{remote_file} -o -C /"
737
+ ensure
738
+ rm_rf local_file
739
+ sudo "rm -f #{remote_file}"
740
+ end
741
+ end
742
+ end
743
+
744
+ desc <<-DESC
745
+ Restart a set of services. Set ec2onrails_config[:services_to_restart] \
746
+ to an array of strings. It's assumed that each service has a script \
747
+ in /etc/init.d
748
+ DESC
749
+ task :restart_services do
750
+ if cfg[:services_to_restart] && cfg[:services_to_restart].any?
751
+ cfg[:services_to_restart].each do |service|
752
+ run_init_script(service, "restart")
753
+ end
754
+ end
755
+ end
756
+
757
+ desc <<-DESC
758
+ Set the email address that mail to the app user forwards to.
759
+ DESC
760
+ task :set_mail_forward_address do
761
+ run "echo '#{cfg[:mail_forward_address]}' >> /home/app/.forward" if cfg[:mail_forward_address]
762
+ # put cfg[:admin_mail_forward_address], "/home/admin/.forward" if cfg[:admin_mail_forward_address]
763
+ end
764
+
765
+ desc <<-DESC
766
+ Enable ssl for the web server. The SSL cert file should be in
767
+ /etc/ssl/certs/default.pem and the SSL key file should be in
768
+ /etc/ssl/private/default.key (use the deploy_files task).
769
+ DESC
770
+ task :enable_ssl, :roles => :web do
771
+ #TODO: enable for nginx
772
+ sudo "a2enmod ssl"
773
+ sudo "a2enmod headers" # the headers module is necessary to forward a header so that rails can detect it is handling an SSL connection. NPG 7/11/08
774
+ sudo "a2ensite default-ssl"
775
+ run_init_script("web_proxy", "restart")
776
+ end
777
+
778
+ desc <<-DESC
779
+ Restrict the main user's sudo access.
780
+ Defaults the user to only be able to \
781
+ sudo to god
782
+ DESC
783
+ task :restrict_sudo_access do
784
+ old_user = fetch(:user)
785
+ begin
786
+ set :user, 'root'
787
+ sessions.clear #clear out sessions cache..... this way the ssh connections are reinitialized
788
+ sudo "cp -f /etc/sudoers.restricted_access /etc/sudoers"
789
+ # run "ln -sf /etc/sudoers.restricted_access /etc/sudoers"
790
+ ensure
791
+ set :user, old_user
792
+ sessions.clear
793
+ end
794
+ end
795
+
796
+ desc <<-DESC
797
+ Grant *FULL* sudo access to the main user.
798
+ DESC
799
+ task :grant_sudo_access do
800
+ allow_sudo
801
+ end
802
+
803
+ @within_sudo = 0
804
+ def allow_sudo
805
+ begin
806
+ @within_sudo += 1
807
+ old_user = fetch(:user)
808
+ if @within_sudo > 1
809
+ yield if block_given?
810
+ true
811
+ elsif capture("ls -l /etc/sudoers /etc/sudoers.full_access | awk '{print $5}'").split.uniq.size == 1
812
+ yield if block_given?
813
+ false
814
+ else
815
+ begin
816
+ # need to cheet and temporarily set the user to ROOT so we
817
+ # can (re)grant full sudo access.
818
+ # we can do this because the root and app user have the same
819
+ # ssh login preferences....
820
+ #
821
+ # TODO:
822
+ # do not escalate priv. to root...use another user like 'admin' that has full sudo access
823
+ set :user, 'root'
824
+ sessions.clear #clear out sessions cache..... this way the ssh connections are reinitialized
825
+ run "cp -f /etc/sudoers.full_access /etc/sudoers"
826
+ set :user, old_user
827
+ sessions.clear
828
+ yield if block_given?
829
+ ensure
830
+ server.restrict_sudo_access if block_given?
831
+ set :user, old_user
832
+ sessions.clear
833
+ true
834
+ end
835
+ end
836
+ ensure
837
+ @within_sudo -= 1
838
+ end
839
+ end
840
+ end
841
+
842
+ end
843
+ end
844
+