hennk-ec2onrails 0.9.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG +0 -0
  2. data/COPYING +339 -0
  3. data/Manifest +148 -0
  4. data/README.textile +214 -0
  5. data/Rakefile +36 -0
  6. data/TODO +5 -0
  7. data/ec2onrails.gemspec +44 -0
  8. data/lib/ec2onrails.rb +20 -0
  9. data/lib/ec2onrails/capistrano_utils.rb +33 -0
  10. data/lib/ec2onrails/recipes.rb +460 -0
  11. data/lib/ec2onrails/version.rb +32 -0
  12. data/server/build-ec2onrails.sh +44 -0
  13. data/server/files/etc/aliases +6 -0
  14. data/server/files/etc/aliases.db +0 -0
  15. data/server/files/etc/apache2/apache2.conf +295 -0
  16. data/server/files/etc/apache2/conf.d/app.proxy_cluster.conf +7 -0
  17. data/server/files/etc/apache2/conf.d/app.proxy_frontend.conf +10 -0
  18. data/server/files/etc/apache2/mods-available/proxy.conf +18 -0
  19. data/server/files/etc/apache2/sites-available/app.common +58 -0
  20. data/server/files/etc/apache2/sites-available/app.custom +0 -0
  21. data/server/files/etc/apache2/sites-available/default +14 -0
  22. data/server/files/etc/apache2/sites-available/default-ssl +18 -0
  23. data/server/files/etc/cron.d/backup_app_db_to_s3 +6 -0
  24. data/server/files/etc/cron.daily/app +5 -0
  25. data/server/files/etc/cron.daily/logrotate_post +27 -0
  26. data/server/files/etc/cron.hourly/app +5 -0
  27. data/server/files/etc/cron.monthly/app +5 -0
  28. data/server/files/etc/cron.weekly/app +5 -0
  29. data/server/files/etc/denyhosts.conf +628 -0
  30. data/server/files/etc/dpkg/dpkg.cfg +13 -0
  31. data/server/files/etc/ec2onrails/balancer_members +6 -0
  32. data/server/files/etc/ec2onrails/roles.yml +5 -0
  33. data/server/files/etc/environment +2 -0
  34. data/server/files/etc/event.d/monit +13 -0
  35. data/server/files/etc/init.d/ec2-every-startup +29 -0
  36. data/server/files/etc/init.d/ec2-first-startup +36 -0
  37. data/server/files/etc/init.d/mongrel +91 -0
  38. data/server/files/etc/init.d/set_roles +3 -0
  39. data/server/files/etc/logrotate.d/apache2 +13 -0
  40. data/server/files/etc/logrotate.d/mysql-server +23 -0
  41. data/server/files/etc/logrotate.d/rails +7 -0
  42. data/server/files/etc/memcached.conf +47 -0
  43. data/server/files/etc/mongrel_cluster/app.yml +9 -0
  44. data/server/files/etc/monit/app.monitrc +71 -0
  45. data/server/files/etc/monit/db_primary.monitrc +10 -0
  46. data/server/files/etc/monit/memcache.monitrc +8 -0
  47. data/server/files/etc/monit/monitrc +13 -0
  48. data/server/files/etc/monit/system.monitrc +15 -0
  49. data/server/files/etc/monit/web.monitrc +10 -0
  50. data/server/files/etc/motd.tail +13 -0
  51. data/server/files/etc/mysql/my.cnf +149 -0
  52. data/server/files/etc/postfix/main.cf +4 -0
  53. data/server/files/etc/rc0.d/K10mongrel +1 -0
  54. data/server/files/etc/rc1.d/K10mongrel +1 -0
  55. data/server/files/etc/rc2.d/S90mongrel +1 -0
  56. data/server/files/etc/rc3.d/S90mongrel +1 -0
  57. data/server/files/etc/rc4.d/S90mongrel +1 -0
  58. data/server/files/etc/rc5.d/S90mongrel +1 -0
  59. data/server/files/etc/rc6.d/K10mongrel +1 -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 +24 -0
  65. data/server/files/etc/syslog.conf +69 -0
  66. data/server/files/usr/local/ec2onrails/COPYING +339 -0
  67. data/server/files/usr/local/ec2onrails/bin/archive_file.rb +44 -0
  68. data/server/files/usr/local/ec2onrails/bin/backup_app_db.rb +83 -0
  69. data/server/files/usr/local/ec2onrails/bin/backup_files.rb +51 -0
  70. data/server/files/usr/local/ec2onrails/bin/mongrel_start +8 -0
  71. data/server/files/usr/local/ec2onrails/bin/mongrel_stop +8 -0
  72. data/server/files/usr/local/ec2onrails/bin/rails_env +35 -0
  73. data/server/files/usr/local/ec2onrails/bin/rebundle.sh +70 -0
  74. data/server/files/usr/local/ec2onrails/bin/restore_app_db.rb +58 -0
  75. data/server/files/usr/local/ec2onrails/bin/restore_files.rb +59 -0
  76. data/server/files/usr/local/ec2onrails/bin/set_rails_env +40 -0
  77. data/server/files/usr/local/ec2onrails/bin/set_roles.rb +156 -0
  78. data/server/files/usr/local/ec2onrails/config +30 -0
  79. data/server/files/usr/local/ec2onrails/lib/mysql_helper.rb +101 -0
  80. data/server/files/usr/local/ec2onrails/lib/s3_helper.rb +126 -0
  81. data/server/files/usr/local/ec2onrails/lib/utils.rb +16 -0
  82. data/server/files/usr/local/ec2onrails/startup-scripts/every-startup/get-hostname.sh +25 -0
  83. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/create-dirs.sh +39 -0
  84. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/generate-default-web-cert-and-key.sh +49 -0
  85. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/misc.sh +30 -0
  86. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/prepare-mysql-data-dir.sh +24 -0
  87. data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/setup_credentials.sh +33 -0
  88. data/server/rakefile.rb +246 -0
  89. data/setup.rb +1585 -0
  90. data/test/autobench.conf +60 -0
  91. data/test/spec/lib/s3_helper_spec.rb +134 -0
  92. data/test/spec/lib/s3_old.yml +3 -0
  93. data/test/spec/test_files/test1 +0 -0
  94. data/test/spec/test_files/test2 +0 -0
  95. data/test/test_app/Capfile +3 -0
  96. data/test/test_app/README +182 -0
  97. data/test/test_app/Rakefile +10 -0
  98. data/test/test_app/app/controllers/application.rb +7 -0
  99. data/test/test_app/app/controllers/db_fast_controller.rb +6 -0
  100. data/test/test_app/app/controllers/fast_controller.rb +5 -0
  101. data/test/test_app/app/controllers/slow_controller.rb +6 -0
  102. data/test/test_app/app/controllers/very_slow_controller.rb +6 -0
  103. data/test/test_app/app/helpers/application_helper.rb +3 -0
  104. data/test/test_app/app/helpers/db_fast_helper.rb +2 -0
  105. data/test/test_app/app/helpers/fast_helper.rb +2 -0
  106. data/test/test_app/app/helpers/slow_helper.rb +2 -0
  107. data/test/test_app/app/helpers/very_slow_helper.rb +2 -0
  108. data/test/test_app/config/boot.rb +109 -0
  109. data/test/test_app/config/database.yml +36 -0
  110. data/test/test_app/config/deploy.rb +21 -0
  111. data/test/test_app/config/environment.rb +60 -0
  112. data/test/test_app/config/environments/development.rb +21 -0
  113. data/test/test_app/config/environments/production.rb +18 -0
  114. data/test/test_app/config/environments/test.rb +19 -0
  115. data/test/test_app/config/routes.rb +27 -0
  116. data/test/test_app/db/schema.rb +7 -0
  117. data/test/test_app/doc/README_FOR_APP +2 -0
  118. data/test/test_app/public/404.html +30 -0
  119. data/test/test_app/public/500.html +30 -0
  120. data/test/test_app/public/dispatch.cgi +10 -0
  121. data/test/test_app/public/dispatch.fcgi +24 -0
  122. data/test/test_app/public/dispatch.rb +10 -0
  123. data/test/test_app/public/favicon.ico +0 -0
  124. data/test/test_app/public/images/rails.png +0 -0
  125. data/test/test_app/public/javascripts/application.js +2 -0
  126. data/test/test_app/public/javascripts/controls.js +963 -0
  127. data/test/test_app/public/javascripts/dragdrop.js +972 -0
  128. data/test/test_app/public/javascripts/effects.js +1120 -0
  129. data/test/test_app/public/javascripts/prototype.js +4225 -0
  130. data/test/test_app/public/robots.txt +1 -0
  131. data/test/test_app/script/about +3 -0
  132. data/test/test_app/script/breakpointer +3 -0
  133. data/test/test_app/script/console +3 -0
  134. data/test/test_app/script/destroy +3 -0
  135. data/test/test_app/script/generate +3 -0
  136. data/test/test_app/script/performance/benchmarker +3 -0
  137. data/test/test_app/script/performance/profiler +3 -0
  138. data/test/test_app/script/performance/request +3 -0
  139. data/test/test_app/script/plugin +3 -0
  140. data/test/test_app/script/process/inspector +3 -0
  141. data/test/test_app/script/process/reaper +3 -0
  142. data/test/test_app/script/process/spawner +3 -0
  143. data/test/test_app/script/runner +3 -0
  144. data/test/test_app/script/server +3 -0
  145. data/test/test_app/test/functional/db_fast_controller_test.rb +18 -0
  146. data/test/test_app/test/functional/fast_controller_test.rb +18 -0
  147. data/test/test_app/test/functional/slow_controller_test.rb +18 -0
  148. data/test/test_app/test/functional/very_slow_controller_test.rb +18 -0
  149. data/test/test_app/test/test_helper.rb +28 -0
  150. metadata +259 -0
data/README.textile ADDED
@@ -0,0 +1,214 @@
1
+ h1. EC2 on Rails
2
+
3
+ h2. Deploy a Ruby on Rails app on EC2 in five minutes
4
+
5
+ Main Page: "https://ec2onrails.rubyforge.org":https://ec2onrails.rubyforge.org
6
+
7
+ Code on Github: "https://github.com/pauldowman/ec2onrails":https://github.com/pauldowman/ec2onrails
8
+
9
+ EC2 on Rails is an Ubuntu Linux server image for "Amazon's EC2 hosting service":http://www.amazon.com/b/ref=sc_fe_l_2/102-6342260-7987311?ie=UTF8&node=201590011&no=3435361 that's ready to run a standard Ruby on Rails application with little or no customization. It's a Ruby on Rails "virtual appliance":http://en.wikipedia.org/wiki/Virtual_appliance.
10
+
11
+ If you have an EC2 account and can start EC2 instances you're five minutes away from deploying your Rails app.
12
+
13
+ EC2 on Rails is "opinionated software":http://gettingreal.37signals.com/ch04_Make_Opinionated_Software.php: the opinion is that for many rails apps the server setup can be generalized and shared the same way as the web application framework itself. For many people (Twitter, this isn't for you) the server image can be treated the same way as other shared libraries. And if the day comes when your needs areunique enough that EC2 on Rails can't be configured to work for you then you can bundle your own image from it or fork the build source and customize it.
14
+
15
+ But until then, why spend your time configuring servers?
16
+
17
+ Features of the EC2 image:
18
+
19
+ * Ready to deploy a Rails app with little or no configuration of the server required
20
+ * Optional Amazon Elastic Block Store (EBS) setup and support for MySQL database persistence.
21
+ * Automatic backup of MySQL database to S3 (EBS enabled: snapshots taken every 2 hrs; Non-EBS enabled: full backup nightly + incremental backup using binary logs every 5 minutes if not using )
22
+ * Capistrano tasks to customize the server image, archive and restore the database to/from S3, and more (available as a rubygem)
23
+ * Mongrel_cluster behind Apache 2.2, configured according to
24
+ "Coda Hale's excellent guide":http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/
25
+ * Ruby on Rails 2.1.0, 2.0.2 and 1.2.6
26
+ * Ruby 1.8.6
27
+ * MySQL 5
28
+ * "memcached":http://www.danga.com/memcached/
29
+ * "monit":http://www.tildeslash.com/monit/ configured to monitor apache, mongrel, mysql, memcached, drive space and system load
30
+ * Ubuntu 8.04 LTS "Hardy" base image built using "Eric Hammond's EC2 Ubuntu script":http://alestic.com/
31
+ * SSL support
32
+ * Amazon AMI tools installed
33
+ * Apache or Nginx web proxies
34
+ * MySQL, Apache/Nginx, and syslog configured to use /mnt for data and logging so you don't fill up EC2's small root filesystem
35
+ * Automatically archives Rails and Apache logs to S3 nightly.
36
+ * 32-bit and 64-bit images available (supports all instance types, small to extra large).
37
+ * Created using a build file, full source is "available":http://rubyforge.org/scm/?group_id=4552 (the EC2 on Rails script is run from "Eric Hammond's EC2 Ubuntu script":http://alestic.com/)
38
+ * Can be used as a clustered Rails app running on multiple instances
39
+ * Automatically runs hourly, daily, weekly and monthly scripts if they exist in Rails application's script directory
40
+ * Local "Postfix":http://www.postfix.org/ SMTP mail server (only available from within the instance, not listening on external network interfaces)
41
+
42
+
43
+ h2. Using the image
44
+
45
+ This documentation will be improved soon, for now hopefully this covers the basics.
46
+
47
+ The current AMI id's are:
48
+ * ami-c9bc58a0 (32-bit)
49
+ * ami-cbbc58a2 (64-bit)
50
+
51
+ _I will keep these images available for as long as possible, they will not be deleted for at least a few years._
52
+
53
+
54
+ h4. 1. Install the gem
55
+
56
+ <pre>sudo gem install ec2onrails</pre>
57
+
58
+ h4. 2. Add the config files to your Rails app
59
+
60
+ You will need to place "Capfile":http://github.com/pauldowman/ec2onrails/tree/master/examples/Capfile?raw=true in the root of your rails folder, and put "deploy.rb":http://github.com/pauldowman/ec2onrails/tree/master/examples/deploy.rb?raw=true and "s3.yml":http://github.com/pauldowman/ec2onrails/tree/master/examples/s3.yml?raw=true in the config folder.
61
+
62
+ Within your rails directory, run
63
+ <code>
64
+ wget -q -O Capfile http://github.com/pauldowman/ec2onrails/tree/master/examples/Capfile?raw=true
65
+ wget -q -O config/deploy.rb http://github.com/pauldowman/ec2onrails/tree/master/examples/deploy.rb?raw=true
66
+ wget -q -O config/s3.yml http://github.com/pauldowman/ec2onrails/tree/master/examples/s3.yml?raw=true
67
+ </code>
68
+
69
+
70
+ _Be sure to customize those files and read the comments._
71
+
72
+ Also, use the hostname "db_primary" in your database.yml file. After running "cap ec2onrails:server:set_roles" it will resolve to the instance defined in your Capistrano "db" role.
73
+
74
+ h4. 3. Start up one or more instances of the image.
75
+
76
+ There is nothing EC2 on Rails-specific here yet (though soon there will be a Capistrano task to do this for you), if you've started EC2 instances before you can skip this section. Otherwise, I'm not going to lie, this part is complicated and will take a lot more than 5 minutes the first time.
77
+
78
+ Read the "running an instance section":http://docs.amazonwebservices.com/AWSEC2/2007-08-29/GettingStartedGuide/running-an-instance.html in Amazon's getting started guide.
79
+
80
+ For the AMI id's of the current images do <code>cap ec2onrails:ami_ids</code> from within the app that you configured in the previous step (they're also listed earlier on this page).
81
+
82
+ _NOTE: Only use the images that match the current version of the gem._
83
+
84
+ Please see the "change log":http://ec2onrails.rubyforge.org/svn/trunk/gem/CHANGELOG for release notes, and see the "list of open issues":http://rubyforge.org/tracker/?atid=17558&group_id=4552&func=browse.
85
+
86
+ As is "standard for public AMI's":http://docs.amazonwebservices.com/AWSEC2/2007-08-29/DeveloperGuide/public-ami-guidelines.html, password-based logins are disabled. You log in with your own "public/private keypair":http://docs.amazonwebservices.com/AWSEC2/2007-08-29/GettingStartedGuide/running-an-instance.html.
87
+
88
+ Most basic things can be configured automatically by the Capistrano tasks, but if you want to you can login by ssh as a user named "admin" (has sudo ability) or as "app" (the user that the app runs as, does not have sudo ability). The Capistrano tasks automatically use the app user to deploy the app, and the admin user for server admin tasks that require sudo.
89
+
90
+ IMPORTANT: Double-check "your firewall settings":http://docs.amazonwebservices.com/AWSEC2/2007-08-29/GettingStartedGuide/running-an-instance.html. Be sure that you haven't allowed public access to any ports other than TCP 22 and TCP 80 (and possibly TCP 443 if you're going to enable HTTPS). If you're using multiple instances, be sure to allow them network access to each other.
91
+
92
+
93
+ h4. 4. Copy your public key from the server to keep Capistrano happy
94
+
95
+ This is a workaround for a quirk in Capistrano. Technically all you should need to connect to the server is the private key file, the public key is on the server. But for some reason "Capistrano requires that you have both the public key and the private key files together on the client":http://groups.google.com/group/capistrano/browse_thread/thread/1102208ff925d18.
96
+
97
+ There is a Capistrano task that tries to fix this for you. From within the root of your rails app do:
98
+
99
+ <pre>cap ec2onrails:get_public_key_from_server</pre>
100
+
101
+ Note, this will only work if you have an external ssh command in the path, it won't work for most Windows users.
102
+
103
+
104
+ h4. 5. Deploy the app with Capistrano
105
+
106
+ Now that the gem is installed, your deploy.rb is configured and you can start and stop EC2 instances, this is the only thing you'll need to do from now on.
107
+
108
+ <pre>
109
+ cap ec2onrails:setup
110
+ cap deploy:cold
111
+ </pre>
112
+
113
+ Yes, it's that easy! The setup task will set the server's timezone, install any gems and Ubuntu packages that you specified in the config file, and create your database.
114
+
115
+ That's it, your app is now running on EC2!!
116
+
117
+
118
+ h2. Capistrano tasks
119
+
120
+ "Capistrano":http://capify.org is the most commonly used Rails deployment tool. It comes with many standard "tasks", and the EC2 on Rails gem includes Capistrano tasks specifically for configuring the server instance.
121
+
122
+ Capistrano is run from the command-line using the "cap" command, with a task name given as an argument.
123
+
124
+ h3. Commonly-used tasks
125
+
126
+ You'll mostly need just the following Capistrano tasks:
127
+
128
+ * <code>cap ec2onrails:ami_ids</code> Shows the AMI id's of the images that match the current version of the gem.
129
+
130
+ * <code>cap ec2onrails:setup</code> This task configures a newly-launched instance. This is the first thing you should do after starting a new instance. It can be run more than once without ill effect. After running "cap ec2onrails:setup" the next thing to do is run "cap deploy:cold"
131
+
132
+ * <code>cap ec2onrails:db:enable_ebs</code> This task will move the _primary_ mysql database onto an Amazon Elastic Storage Block (EBS) volume. You can call this task with the optional SIZE parameter defined (defaults to 10 gigs) like <pre>cap ec2onrails:db:enable_ebs SIZE=10</pre>
133
+
134
+ You should then specify your own volume (or the one created by this task) in your capistrano deploy.rb file like so: <pre>role :db, "ec2-xx-xxx-xx-xxx.compute-1.amazonaws.com", :primary => true, :ebs_vol_id => 'vol-12345abc'</pre>
135
+
136
+ *NOTE* MySQL EBS is not enabled by default. You may call this task at anytime to move your MySQL over to EBS, but just make sure you keep track of the volume-id that is printed out by this task and use it to modify your deploy.rb file
137
+
138
+ * <code>cap ec2onrails:server:set_roles</code> Customizes each instance for it's role(s) (as defined in your Capistrano deploy.rb file). Run this after starting or stopping instances. For now this just makes sure that only the appropriate services (Apache, Mongrel, and/or MySQL) are running. Eventually this will customize settings for the running services also. Note that an instance can have more than one role. If there's only one instance it will have all roles.
139
+
140
+ Note that due to the way that Capistrano works all tasks are run against all hosts that are currently defined in the deploy.rb file. So if you start a new instance then add it to your deploy.rb you will need to run "cap ec2onrails:setup" again which will be run on all existing instances.
141
+
142
+
143
+ h3. Database management tasks
144
+
145
+ * <code>cap ec2onrails:db:archive</code> Archive the MySQL database to the bucket specified in your deploy.rb. This is for archiving a snapshot of your database into any S3 bucket. For example, you might want to do this before deploying.
146
+
147
+ * <code>cap ec2onrails:db:restore</code> Restore the MySQL database from the bucket specified in your deploy.rb For example, I use this to restore the current production data (from my actual production backup bucket) onto a staging server that has the current production version of my app. I then deploy the new version which tests migrations exactly as they'll run on the production server.
148
+
149
+ To get a full list of the Capistrano tasks at any time type <code>cap -T</code> from with your rails app root.
150
+
151
+ h2. Building the image
152
+
153
+ Building the image is not required, most people will simply use the prebuilt public image, but there is also a build script that builds the image. It's meant to be called by "Eric Hammond's EC2 Ubuntu script":http://alestic.com/.
154
+
155
+ Here is how you go about setting it up:
156
+
157
+
158
+ h4. Notes
159
+
160
+ * amazon-keypair is your amazon keypair, which in this case has has had the public and private keys copied into the ~/.ssh folder
161
+ * we need to copy the ec2onrails source folder onto the image instance
162
+ * HOST_PUBLIC_INSTANCE is the hostname of the instance that you will soon be creating. run <code>ec2-describe-instances</code> to find this value. It will look something like <code>ec2-xxx-xxx-xxx-xxx.compute-x.amazonaws.com</code>
163
+
164
+ h4. Getting started...
165
+
166
+ * launch one of Eric's default images (see "Eric Hammond's":http://alestic.com/ page for the most recent ami-images): <code>ec2-run-instances ami-179e7a7e -k amazon-keypair</code> (for a 64-bit image, launch: <code>ec2-run-instances ami-f89d7991 -k amazon-keypair --instance-type m1.large</code>)
167
+ * lets get your amazon keypair up onto the instance: <code>scp -i ~/.ssh/id_rsa-amazon-keypair ~/.ec2/{cert,pk}-*.pem root@HOST_PUBLIC_ADDRESS:/mnt/</code>
168
+ * ditto for getting the ec2onrails server code up onto your new instance: <code>scp -rp -i ~/.ssh/id_rsa-amazon-keypair ~/your/copy/of/ec2onrails/. root@HOST_PUBLIC_ADDRESS:/mnt/ec2onrails</code>
169
+ * time to log into your instance: <code>ssh -i ~/.ssh/id_rsa-amazon-keypair root@HOST_PUBLIC_ADDRESS</code>
170
+ * get the most recent ec2ubuntu script: <code>curl -Lo /mnt/ec2ubuntu-build-ami http://ec2ubuntu-build-ami.notlong.com</code>
171
+ * time to get the instance ready for ec2onrails. The script will end with a command you need to run to finish creating an amazon ami-image. <pre>bash /mnt/ec2ubuntu-build-ami \
172
+ --codename hardy \
173
+ --bucket YOURNAME_ec2onrails \
174
+ --prefix ec2onrails \
175
+ --user YOUR_AMAZON_USER_ID \
176
+ --access-key AMAZON_ACCESS_KEY \
177
+ --secret-key AMAZON_SECRET_KEY \
178
+ --private-key /mnt/pk-*.pem \
179
+ --cert /mnt/cert-*.pem \
180
+ --script /mnt/ec2onrails/server/build-ec2onrails.sh</pre>
181
+
182
+ h2. Mailing lists
183
+
184
+ There are two Google groups, one for "announcements":http://groups.google.com/group/ec2-on-rails-announce (usually just new release announcements) and one for "discussion":http://groups.google.com/group/ec2-on-rails-discuss.
185
+
186
+
187
+ h2. Comments
188
+
189
+ Comments are welcome. Send an email to "Paul Dowman":http://pauldowman.com/contact/ or to the "Google group":http://groups.google.com/group/ec2-on-rails-discuss. If you find bugs please file them "here":http://rubyforge.org/tracker/?atid=17558&group_id=4552&func=browse or send me an "email":http://pauldowman.com/contact/.
190
+
191
+
192
+ h2. Change log
193
+
194
+ See the "change log":http://ec2onrails.rubyforge.org/svn/trunk/gem/CHANGELOG.
195
+
196
+
197
+ h2. How to submit patches
198
+
199
+ Pleae read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/. The source code can be checked out anonymously using:
200
+ <pre>
201
+ svn checkout http://ec2onrails.rubyforge.org/svn/trunk ec2onrails
202
+ </pre>
203
+
204
+ Code on Github: "https://github.com/pauldowman/ec2onrails":https://github.com/pauldowman/ec2onrails
205
+
206
+ Patches can be submitted to the "RubyForge Tracker":http://rubyforge.org/tracker/?atid=17560&group_id=4552&func=browse or "emailed directly to me":http://pauldowman.com/contact/ .
207
+
208
+ h2. License
209
+
210
+ This code is free to use under the terms of the GPL v2.
211
+
212
+ If you find EC2 on Rails useful please "recommend Paul Dowman":http://www.workingwithrails.com/person/10131-paul-dowman at Working With Rails.
213
+
214
+ Copyright 2007 Paul Dowman, http://pauldowman.com/ This is free software, and you are welcome to redistribute it under certain conditions. This software comes with ABSOLUTELY NO WARRANTY. See the file named COPYING for details.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require "./lib/ec2onrails/version"
2
+
3
+ begin
4
+ require 'echoe'
5
+ rescue LoadError
6
+ abort "You'll need to have `echoe' installed to use ec2onrails' Rakefile"
7
+ end
8
+
9
+ version = Ec2onrails::VERSION::STRING.dup
10
+
11
+ Echoe.new('ec2onrails', version) do |p|
12
+ p.changelog = "CHANGELOG"
13
+
14
+ p.author = ['Paul Dowman', 'Adam Greene']
15
+ p.email = "paul@pauldowman.com"
16
+
17
+ p.summary = <<-DESC.strip.gsub(/\n\s+/, " ")
18
+ Client-side libraries (Capistrano tasks) for managing and
19
+ deploying to EC2 on Rails servers.
20
+ DESC
21
+
22
+ #OTHER helpful options
23
+ # p.install_message = "perhaps telling them where to find the example docs?"
24
+ # p.rdoc_pattern
25
+ p.url = "http://ec2onrails.rubyforge.org"
26
+ p.need_zip = true
27
+ p.rdoc_pattern = /^(lib|README.textile|CHANGELOG)/
28
+
29
+ p.dependencies = [
30
+ 'capistrano >= 2.4.3',
31
+ 'archive-tar-minitar >= 0.5.1',
32
+ 'optiflag >= 0.6.5']
33
+
34
+ p.development_dependencies = ['rake >=0.7.1']
35
+
36
+ end
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ FUTURE CHANGES
2
+ [ ] Merge multi_app work when done
3
+ [ ] Add munin
4
+ - See http://onrails.org/articles/2007/08/31/monitoring-rails-performance-with-munin-and-a-mongrel for a munin plugin to show Rails response times
5
+ [ ] Check if EBS is a viable alternative for app file storage
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ec2onrails}
5
+ s.version = "0.9.9.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Paul Dowman, Adam Greene"]
9
+ s.date = %q{2008-11-16}
10
+ s.description = %q{Client-side libraries (Capistrano tasks) for managing and deploying to EC2 on Rails servers.}
11
+ s.email = %q{paul@pauldowman.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/ec2onrails/capistrano_utils.rb", "lib/ec2onrails/recipes.rb", "lib/ec2onrails/version.rb", "lib/ec2onrails.rb", "README.textile"]
13
+ s.files = ["CHANGELOG", "COPYING", "lib/ec2onrails/capistrano_utils.rb", "lib/ec2onrails/recipes.rb", "lib/ec2onrails/version.rb", "lib/ec2onrails.rb", "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/roles.yml", "server/files/etc/environment", "server/files/etc/event.d/monit", "server/files/etc/init.d/ec2-every-startup", "server/files/etc/init.d/ec2-first-startup", "server/files/etc/init.d/mongrel", "server/files/etc/init.d/set_roles", "server/files/etc/logrotate.d/apache2", "server/files/etc/logrotate.d/mysql-server", "server/files/etc/logrotate.d/rails", "server/files/etc/memcached.conf", "server/files/etc/mongrel_cluster/app.yml", "server/files/etc/monit/app.monitrc", "server/files/etc/monit/db_primary.monitrc", "server/files/etc/monit/memcache.monitrc", "server/files/etc/monit/monitrc", "server/files/etc/monit/system.monitrc", "server/files/etc/monit/web.monitrc", "server/files/etc/motd.tail", "server/files/etc/mysql/my.cnf", "server/files/etc/postfix/main.cf", "server/files/etc/rc0.d/K10mongrel", "server/files/etc/rc1.d/K10mongrel", "server/files/etc/rc2.d/S90mongrel", "server/files/etc/rc3.d/S90mongrel", "server/files/etc/rc4.d/S90mongrel", "server/files/etc/rc5.d/S90mongrel", "server/files/etc/rc6.d/K10mongrel", "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/syslog.conf", "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/backup_files.rb", "server/files/usr/local/ec2onrails/bin/mongrel_start", "server/files/usr/local/ec2onrails/bin/mongrel_stop", "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/restore_files.rb", "server/files/usr/local/ec2onrails/bin/set_rails_env", "server/files/usr/local/ec2onrails/bin/set_roles.rb", "server/files/usr/local/ec2onrails/config", "server/files/usr/local/ec2onrails/COPYING", "server/files/usr/local/ec2onrails/lib/mysql_helper.rb", "server/files/usr/local/ec2onrails/lib/s3_helper.rb", "server/files/usr/local/ec2onrails/lib/utils.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/setup_credentials.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", "TODO", "Manifest", "ec2onrails.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://ec2onrails.rubyforge.org}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ec2onrails", "--main", "README.textile"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{ec2onrails}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Client-side libraries (Capistrano tasks) for managing and deploying to EC2 on Rails servers.}
21
+ 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"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<capistrano>, [">= 0", "= 2.4.3"])
29
+ s.add_runtime_dependency(%q<archive-tar-minitar>, [">= 0", "= 0.5.1"])
30
+ s.add_runtime_dependency(%q<optiflag>, [">= 0", "= 0.6.5"])
31
+ s.add_development_dependency(%q<rake>, [">= 0.7.1"])
32
+ else
33
+ s.add_dependency(%q<capistrano>, [">= 0", "= 2.4.3"])
34
+ s.add_dependency(%q<archive-tar-minitar>, [">= 0", "= 0.5.1"])
35
+ s.add_dependency(%q<optiflag>, [">= 0", "= 0.6.5"])
36
+ s.add_dependency(%q<rake>, [">= 0.7.1"])
37
+ end
38
+ else
39
+ s.add_dependency(%q<capistrano>, [">= 0", "= 2.4.3"])
40
+ s.add_dependency(%q<archive-tar-minitar>, [">= 0", "= 0.5.1"])
41
+ s.add_dependency(%q<optiflag>, [">= 0", "= 0.6.5"])
42
+ s.add_dependency(%q<rake>, [">= 0.7.1"])
43
+ end
44
+ end
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,33 @@
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
+ def make_admin_role_for(role)
14
+ newrole = "#{role.to_s}_admin".to_sym
15
+ roles[role].each do |srv_def|
16
+ options = srv_def.options.dup
17
+ options[:user] = "admin"
18
+ options[:port] = srv_def.port
19
+ options[:no_release] = true
20
+ role newrole, srv_def.host, options
21
+ end
22
+ end
23
+
24
+ # return hostnames for the role named role_sym that has the specified options
25
+ def hostnames_for_role(role_sym, options = {})
26
+ role = roles[role_sym]
27
+ unless role
28
+ return []
29
+ end
30
+ role.select{|s| s.options == options}.collect{|s| s.host}
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,460 @@
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
+ set :ec2onrails_version, Ec2onrails::VERSION::STRING
40
+ set :image_id_32_bit, Ec2onrails::VERSION::AMI_ID_32_BIT
41
+ set :image_id_64_bit, Ec2onrails::VERSION::AMI_ID_64_BIT
42
+ set :deploy_to, "/mnt/app"
43
+ set :use_sudo, false
44
+ set :user, "app"
45
+
46
+ # make an "admin" role for each role, and create arrays containing
47
+ # the names of admin roles and non-admin roles for convenience
48
+ set :all_admin_role_names, []
49
+ set :all_non_admin_role_names, []
50
+ roles.keys.clone.each do |name|
51
+ make_admin_role_for(name)
52
+ all_non_admin_role_names << name
53
+ all_admin_role_names << "#{name.to_s}_admin".to_sym
54
+ end
55
+
56
+ after "deploy:symlink", "ec2onrails:server:set_roles"
57
+ after "deploy:cold", "ec2onrails:db:init_backup"
58
+
59
+ # override default start/stop/restart tasks
60
+ namespace :deploy do
61
+ desc <<-DESC
62
+ Overrides the default Capistrano deploy:restart, uses \
63
+ /etc/init.d/mongrel
64
+ DESC
65
+ task :start, :roles => :app_admin do
66
+ run_init_script("mongrel", "start")
67
+ run "sleep 30" # give the service 30 seconds to start before attempting to monitor it
68
+ sudo "monit -g app monitor all"
69
+ end
70
+
71
+ desc <<-DESC
72
+ Overrides the default Capistrano deploy:restart, uses \
73
+ /etc/init.d/mongrel
74
+ DESC
75
+ task :stop, :roles => :app_admin do
76
+ sudo "monit -g app unmonitor all"
77
+ run_init_script("mongrel", "stop")
78
+ end
79
+
80
+ desc <<-DESC
81
+ Overrides the default Capistrano deploy:restart, uses \
82
+ /etc/init.d/mongrel
83
+ DESC
84
+ task :restart, :roles => :app_admin do
85
+ deploy.stop
86
+ deploy.start
87
+ end
88
+ end
89
+
90
+ namespace :ec2onrails do
91
+ desc <<-DESC
92
+ Show the AMI id's of the current images for this version of \
93
+ EC2 on Rails.
94
+ DESC
95
+ task :ami_ids do
96
+ puts "32-bit server image for EC2 on Rails #{ec2onrails_version}: #{image_id_32_bit}"
97
+ puts "64-bit server image for EC2 on Rails #{ec2onrails_version}: #{image_id_64_bit}"
98
+ end
99
+
100
+ desc <<-DESC
101
+ Copies the public key from the server using the external "ssh"
102
+ command because Net::SSH, which is used by Capistrano, needs it.
103
+ This will only work if you have an ssh command in the path.
104
+ If Capistrano can successfully connect to your EC2 instance you
105
+ don't need to do this. It will copy from the first server in the
106
+ :app role, this can be overridden by specifying the HOST
107
+ environment variable
108
+ DESC
109
+ task :get_public_key_from_server do
110
+ host = find_servers_for_task(current_task).first.host
111
+ privkey = ssh_options[:keys][0]
112
+ pubkey = "#{privkey}.pub"
113
+ msg = <<-MSG
114
+ Your first key in ssh_options[:keys] is #{privkey}, presumably that's
115
+ your EC2 private key. The public key will be copied from the server
116
+ named '#{host}' and saved locally as #{pubkey}. Continue? [y/n]
117
+ MSG
118
+ choice = nil
119
+ while choice != "y" && choice != "n"
120
+ choice = Capistrano::CLI.ui.ask(msg).downcase
121
+ msg = "Please enter 'y' or 'n'."
122
+ end
123
+ if choice == "y"
124
+ run_local "scp -i '#{privkey}' app@#{host}:.ssh/authorized_keys #{pubkey}"
125
+ end
126
+ end
127
+
128
+ desc <<-DESC
129
+ Prepare a newly-started instance for a cold deploy.
130
+ DESC
131
+ task :setup, :roles => all_admin_role_names do
132
+ server.set_admin_mail_forward_address
133
+ server.set_timezone
134
+ server.install_packages
135
+ server.install_gems
136
+ server.deploy_files
137
+ server.enable_ssl if cfg[:enable_ssl]
138
+ server.set_rails_env
139
+ server.restart_services
140
+ deploy.setup
141
+ db.create
142
+ end
143
+
144
+ desc <<-DESC
145
+ Deploy and restore database from S3
146
+ DESC
147
+ task :restore_db_and_deploy do
148
+ db.recreate
149
+ deploy.update_code
150
+ deploy.symlink
151
+ db.restore
152
+ deploy.migrations
153
+ end
154
+
155
+ namespace :ec2 do
156
+ desc <<-DESC
157
+ DESC
158
+ task :configure_firewall do
159
+ # TODO
160
+ end
161
+ end
162
+
163
+ namespace :db do
164
+ desc <<-DESC
165
+ [internal] Load configuration info for the database from
166
+ config/database.yml, and start mysql (it must be running
167
+ in order to interact with it).
168
+ DESC
169
+ task :load_config do
170
+ unless hostnames_for_role(:db, :primary => true).empty?
171
+ db_config = YAML::load(ERB.new(File.read("config/database.yml")).result)[rails_env.to_s]
172
+ cfg[:db_name] = db_config['database']
173
+ cfg[:db_user] = db_config['username'] || db_config['user']
174
+ cfg[:db_password] = db_config['password']
175
+ cfg[:db_host] = db_config['host']
176
+ cfg[:db_socket] = db_config['socket']
177
+
178
+ if (cfg[:db_host].nil? || cfg[:db_host].empty?) && (cfg[:db_socket].nil? || cfg[:db_socket].empty?)
179
+ 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'."
180
+ end
181
+
182
+ [cfg[:db_name], cfg[:db_user], cfg[:db_password]].each do |s|
183
+ if s.nil? || s.empty?
184
+ raise "ERROR: missing database config. Make sure database.yml contains a '#{rails_env}' section with a database name, user, and password."
185
+ elsif s.match(/['"]/)
186
+ raise "ERROR: database config string '#{s}' contains quotes."
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ desc <<-DESC
193
+ Create the MySQL database. Assumes there is no MySQL root \
194
+ password. To create a MySQL root password create a task that's run \
195
+ after this task using an after hook.
196
+ DESC
197
+ task :create, :roles => :db do
198
+ on_rollback { drop }
199
+ load_config
200
+ start
201
+
202
+ # For some reason the default db on Hardy contains users with '' as the name.
203
+ # This causes authentication problems when connecting from localhost
204
+ run %{mysql -u root -D mysql -e "delete from user where User = ''; flush privileges;"}
205
+
206
+ run %{mysql -u root -e "create database if not exists #{cfg[:db_name]};"}
207
+ run %{mysql -u root -e "grant all on #{cfg[:db_name]}.* to '#{cfg[:db_user]}'@'%' identified by '#{cfg[:db_password]}';"}
208
+ run %{mysql -u root -e "grant reload on *.* to '#{cfg[:db_user]}'@'%' identified by '#{cfg[:db_password]}';"}
209
+ run %{mysql -u root -e "grant super on *.* to '#{cfg[:db_user]}'@'%' identified by '#{cfg[:db_password]}';"}
210
+ end
211
+
212
+ desc <<-DESC
213
+ [internal] Make sure the MySQL server has been started, just in case the db role
214
+ hasn't been set, e.g. when called from ec2onrails:setup.
215
+ (But don't enable monitoring on it.)
216
+ DESC
217
+ task :start, :roles => :db_admin do
218
+ sudo "chmod a+x /etc/init.d/mysql"
219
+ # The mysql init script can fail on the first startup if mysql takes too long
220
+ # to create the logfiles, so try again
221
+ sudo "sh -c '/etc/init.d/mysql start || (sleep 10 && /etc/init.d/mysql start)'"
222
+ end
223
+
224
+ desc <<-DESC
225
+ Drop the MySQL database. Assumes there is no MySQL root \
226
+ password. If there is a MySQL root password, create a task that removes \
227
+ it and run that task before this one using a before hook.
228
+ DESC
229
+ task :drop, :roles => :db do
230
+ load_config
231
+ run %{mysql -u root -e "drop database if exists #{cfg[:db_name]};"}
232
+ end
233
+
234
+ desc <<-DESC
235
+ db:drop and db:create.
236
+ DESC
237
+ task :recreate, :roles => :db do
238
+ drop
239
+ create
240
+ end
241
+
242
+ desc <<-DESC
243
+ Set a root password for MySQL, using the variable mysql_root_password \
244
+ if it is set. If this is done db:drop won't work.
245
+ DESC
246
+ task :set_root_password, :roles => :db do
247
+ if cfg[:mysql_root_password]
248
+ run %{mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('#{cfg[:mysql_root_password]}') WHERE User='root'; FLUSH PRIVILEGES;"}
249
+ end
250
+ end
251
+
252
+ desc <<-DESC
253
+ Dump the MySQL database to the S3 bucket specified by \
254
+ ec2onrails_config[:archive_to_bucket]. The filename will be \
255
+ "database-archive/<timestamp>/dump.sql.gz".
256
+ DESC
257
+ task :archive, :roles => :db do
258
+ run "/usr/local/ec2onrails/bin/backup_app_db.rb --bucket #{cfg[:archive_to_bucket]} --dir #{cfg[:archive_to_bucket_subdir]}"
259
+ end
260
+
261
+ desc <<-DESC
262
+ Restore the MySQL database from the S3 bucket specified by \
263
+ ec2onrails_config[:restore_from_bucket]. The archive filename is \
264
+ expected to be the default, "mysqldump.sql.gz".
265
+ DESC
266
+ task :restore, :roles => :db do
267
+ run "/usr/local/ec2onrails/bin/restore_app_db.rb --bucket #{cfg[:restore_from_bucket]} --dir #{cfg[:restore_from_bucket_subdir]}"
268
+ end
269
+
270
+ desc <<-DESC
271
+ [internal] Initialize the default backup folder on S3 (i.e. do a full
272
+ backup of the newly-created db so the automatic incremental backups
273
+ make sense).
274
+ DESC
275
+ task :init_backup, :roles => :db do
276
+ run "/usr/local/ec2onrails/bin/backup_app_db.rb --reset"
277
+ end
278
+ end
279
+
280
+ namespace :server do
281
+ desc <<-DESC
282
+ Tell the servers what roles they are in. This configures them with \
283
+ the appropriate settings for each role, and starts and/or stops the \
284
+ relevant services.
285
+ DESC
286
+ task :set_roles, :roles => all_admin_role_names do
287
+ # TODO generate this based on the roles that actually exist so arbitrary new ones can be added
288
+ roles = {
289
+ :web => hostnames_for_role(:web),
290
+ :app => hostnames_for_role(:app),
291
+ :db_primary => hostnames_for_role(:db, :primary => true),
292
+ :memcache => hostnames_for_role(:memcache)
293
+ }
294
+ roles_yml = YAML::dump(roles)
295
+ put roles_yml, "/tmp/roles.yml"
296
+ sudo "cp /tmp/roles.yml /etc/ec2onrails"
297
+ sudo "/usr/local/ec2onrails/bin/set_roles.rb"
298
+ end
299
+
300
+ desc <<-DESC
301
+ Change the default value of RAILS_ENV on the server. Technically
302
+ this changes the server's mongrel config to use a different value
303
+ for "environment". The value is specified in :rails_env.
304
+ Be sure to do deploy:restart after this.
305
+ DESC
306
+ task :set_rails_env, :roles => all_admin_role_names do
307
+ rails_env = fetch(:rails_env, "production")
308
+ sudo "/usr/local/ec2onrails/bin/set_rails_env #{rails_env}"
309
+ end
310
+
311
+ desc <<-DESC
312
+ Upgrade to the newest versions of all Ubuntu packages.
313
+ DESC
314
+ task :upgrade_packages, :roles => all_admin_role_names do
315
+ sudo "aptitude -q update"
316
+ run "export DEBIAN_FRONTEND=noninteractive; sudo aptitude -q -y safe-upgrade"
317
+ end
318
+
319
+ desc <<-DESC
320
+ Upgrade to the newest versions of all rubygems.
321
+ DESC
322
+ task :upgrade_gems, :roles => all_admin_role_names do
323
+ sudo "gem update --system --no-rdoc --no-ri"
324
+ sudo "gem update --no-rdoc --no-ri" do |ch, str, data|
325
+ ch[:data] ||= ""
326
+ ch[:data] << data
327
+ if data =~ />\s*$/
328
+ puts data
329
+ choice = Capistrano::CLI.ui.ask("The gem command is asking for a number:")
330
+ ch.send_data("#{choice}\n")
331
+ else
332
+ puts data
333
+ end
334
+ end
335
+
336
+ end
337
+
338
+ desc <<-DESC
339
+ Install extra Ubuntu packages. Set ec2onrails_config[:packages], it \
340
+ should be an array of strings.
341
+ NOTE: the package installation will be non-interactive, if the packages \
342
+ require configuration either log in as 'admin' and run \
343
+ 'dpkg-reconfigure packagename' or replace the package's config files \
344
+ using the 'ec2onrails:server:deploy_files' task.
345
+ DESC
346
+ task :install_packages, :roles => all_admin_role_names do
347
+ if cfg[:packages] && cfg[:packages].any?
348
+ run "export DEBIAN_FRONTEND=noninteractive; sudo aptitude -q -y install #{cfg[:packages].join(' ')}"
349
+ end
350
+ end
351
+
352
+ desc <<-DESC
353
+ Install extra rubygems. Set ec2onrails_config[:rubygems], it should \
354
+ be with an array of strings.
355
+ DESC
356
+ task :install_gems, :roles => all_admin_role_names do
357
+ if cfg[:rubygems]
358
+ cfg[:rubygems].each do |gem|
359
+ sudo "gem install #{gem} --no-rdoc --no-ri" do |ch, str, data|
360
+ ch[:data] ||= ""
361
+ ch[:data] << data
362
+ if data =~ />\s*$/
363
+ puts data
364
+ choice = Capistrano::CLI.ui.ask("The gem command is asking for a number:")
365
+ ch.send_data("#{choice}\n")
366
+ else
367
+ puts data
368
+ end
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ desc <<-DESC
375
+ A convenience task to upgrade existing packages and gems and install \
376
+ specified new ones.
377
+ DESC
378
+ task :upgrade_and_install_all, :roles => all_admin_role_names do
379
+ upgrade_packages
380
+ upgrade_gems
381
+ install_packages
382
+ install_gems
383
+ end
384
+
385
+ desc <<-DESC
386
+ Set the timezone using the value of the variable named timezone. \
387
+ Valid options for timezone can be determined by the contents of \
388
+ /usr/share/zoneinfo, which can be seen here: \
389
+ http://packages.ubuntu.com/cgi-bin/search_contents.pl?searchmode=filelist&word=tzdata&version=gutsy&arch=all&page=1&number=all \
390
+ Remove 'usr/share/zoneinfo/' from the filename, and use the last \
391
+ directory and file as the value. For example 'Africa/Abidjan' or \
392
+ 'posix/GMT' or 'Canada/Eastern'.
393
+ DESC
394
+ task :set_timezone, :roles => all_admin_role_names do
395
+ if cfg[:timezone]
396
+ sudo "bash -c 'echo #{cfg[:timezone]} > /etc/timezone'"
397
+ sudo "cp /usr/share/zoneinfo/#{cfg[:timezone]} /etc/localtime"
398
+ end
399
+ end
400
+
401
+ desc <<-DESC
402
+ Deploy a set of config files to the server, the files will be owned by \
403
+ root. This doesn't delete any files from the server. This is intended
404
+ mainly for customized config files for new packages installed via the \
405
+ ec2onrails:server:install_packages task. Subdirectories and files \
406
+ inside here will be placed within the same directory structure \
407
+ relative to the root of the server's filesystem.
408
+ DESC
409
+ task :deploy_files, :roles => all_admin_role_names do
410
+ if cfg[:server_config_files_root]
411
+ begin
412
+ filename = "config_files.tar"
413
+ local_file = "#{Dir.tmpdir}/#{filename}"
414
+ remote_file = "/tmp/#{filename}"
415
+ FileUtils.cd(cfg[:server_config_files_root]) do
416
+ File.open(local_file, 'wb') { |tar| Minitar.pack(".", tar) }
417
+ end
418
+ put File.read(local_file), remote_file
419
+ sudo "tar xvf #{remote_file} -o -C /"
420
+ ensure
421
+ rm_rf local_file
422
+ run "rm -f #{remote_file}"
423
+ end
424
+ end
425
+ end
426
+
427
+ desc <<-DESC
428
+ Restart a set of services. Set ec2onrails_config[:services_to_restart] \
429
+ to an array of strings. It's assumed that each service has a script \
430
+ in /etc/init.d
431
+ DESC
432
+ task :restart_services, :roles => all_admin_role_names do
433
+ if cfg[:services_to_restart] && cfg[:services_to_restart].any?
434
+ cfg[:services_to_restart].each do |service|
435
+ run_init_script(service, "restart")
436
+ end
437
+ end
438
+ end
439
+
440
+ desc <<-DESC
441
+ Set the email address that mail to the admin user forwards to.
442
+ DESC
443
+ task :set_admin_mail_forward_address, :roles => all_admin_role_names do
444
+ put cfg[:admin_mail_forward_address], "/home/admin/.forward" if cfg[:admin_mail_forward_address]
445
+ end
446
+
447
+ desc <<-DESC
448
+ Enable ssl for the web server. The SSL cert file should be in
449
+ /etc/ssl/certs/default.pem and the SSL key file should be in
450
+ /etc/ssl/private/default.key (use the deploy_files task).
451
+ DESC
452
+ task :enable_ssl, :roles => :web_admin do
453
+ sudo "a2enmod ssl"
454
+ sudo "a2ensite default-ssl"
455
+ run_init_script("apache2", "restart")
456
+ end
457
+ end
458
+
459
+ end
460
+ end