skippy-ec2onrails 0.9.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +159 -0
- data/COPYING +339 -0
- data/Manifest +162 -0
- data/README.textile +214 -0
- data/Rakefile +36 -0
- data/TODO +102 -0
- data/ec2onrails.gemspec +42 -0
- data/examples/Capfile +3 -0
- data/examples/deploy.rb +101 -0
- data/examples/s3.yml +9 -0
- data/lib/ec2onrails/capistrano_utils.rb +43 -0
- data/lib/ec2onrails/recipes.rb +844 -0
- data/lib/ec2onrails/version.rb +31 -0
- data/lib/ec2onrails.rb +20 -0
- data/server/build-ec2onrails.sh +44 -0
- data/server/files/etc/aliases +5 -0
- data/server/files/etc/aliases.db +0 -0
- data/server/files/etc/apache2/apache2.conf +295 -0
- data/server/files/etc/apache2/conf.d/app.proxy_cluster.conf +7 -0
- data/server/files/etc/apache2/conf.d/app.proxy_frontend.conf +10 -0
- data/server/files/etc/apache2/mods-available/proxy.conf +18 -0
- data/server/files/etc/apache2/sites-available/app.common +56 -0
- data/server/files/etc/apache2/sites-available/app.custom +0 -0
- data/server/files/etc/apache2/sites-available/default +14 -0
- data/server/files/etc/apache2/sites-available/default-ssl +19 -0
- data/server/files/etc/cron.d/backup_app_db_to_s3 +16 -0
- data/server/files/etc/cron.daily/app +9 -0
- data/server/files/etc/cron.daily/logrotate_post +19 -0
- data/server/files/etc/cron.hourly/app +10 -0
- data/server/files/etc/cron.monthly/app +10 -0
- data/server/files/etc/cron.weekly/app +10 -0
- data/server/files/etc/denyhosts.conf +628 -0
- data/server/files/etc/dpkg/dpkg.cfg +13 -0
- data/server/files/etc/ec2onrails/README +32 -0
- data/server/files/etc/ec2onrails/balancer_members +6 -0
- data/server/files/etc/ec2onrails/roles.yml +5 -0
- data/server/files/etc/environment +2 -0
- data/server/files/etc/god/app.god +35 -0
- data/server/files/etc/god/db.god +17 -0
- data/server/files/etc/god/examples/have_god_daemonize.god +18 -0
- data/server/files/etc/god/master.conf +35 -0
- data/server/files/etc/god/memcache.god +15 -0
- data/server/files/etc/god/notifications.god +14 -0
- data/server/files/etc/god/system.god +34 -0
- data/server/files/etc/god/web.god +36 -0
- data/server/files/etc/init.d/ec2-every-startup +29 -0
- data/server/files/etc/init.d/ec2-first-startup +36 -0
- data/server/files/etc/init.d/god +42 -0
- data/server/files/etc/init.d/nginx +78 -0
- data/server/files/etc/init.d/set_roles +3 -0
- data/server/files/etc/logrotate.d/apache2 +16 -0
- data/server/files/etc/logrotate.d/mongrel +11 -0
- data/server/files/etc/logrotate.d/nginx +11 -0
- data/server/files/etc/memcached.conf +47 -0
- data/server/files/etc/mongrel_cluster/app.yml +9 -0
- data/server/files/etc/motd.tail +13 -0
- data/server/files/etc/mysql/my.cnf +149 -0
- data/server/files/etc/nginx/nginx.conf +296 -0
- data/server/files/etc/postfix/main.cf +4 -0
- data/server/files/etc/rcS.d/S91ec2-first-startup +1 -0
- data/server/files/etc/rcS.d/S92ec2-every-startup +1 -0
- data/server/files/etc/rcS.d/S99set_roles +1 -0
- data/server/files/etc/ssh/sshd_config +94 -0
- data/server/files/etc/sudoers +1 -0
- data/server/files/etc/sudoers.full_access +26 -0
- data/server/files/etc/sudoers.restricted_access +28 -0
- data/server/files/etc/syslog.conf +69 -0
- data/server/files/usr/bin/god +26 -0
- data/server/files/usr/local/ec2onrails/COPYING +339 -0
- data/server/files/usr/local/ec2onrails/bin/archive_file.rb +44 -0
- data/server/files/usr/local/ec2onrails/bin/backup_app_db.rb +159 -0
- data/server/files/usr/local/ec2onrails/bin/ec2_meta_data.rb +80 -0
- data/server/files/usr/local/ec2onrails/bin/exec_runner +73 -0
- data/server/files/usr/local/ec2onrails/bin/init_services.rb +64 -0
- data/server/files/usr/local/ec2onrails/bin/optimize_mysql.rb +348 -0
- data/server/files/usr/local/ec2onrails/bin/rails_env +35 -0
- data/server/files/usr/local/ec2onrails/bin/rebundle.sh +70 -0
- data/server/files/usr/local/ec2onrails/bin/restore_app_db.rb +58 -0
- data/server/files/usr/local/ec2onrails/bin/set_rails_env +40 -0
- data/server/files/usr/local/ec2onrails/bin/set_roles.rb +87 -0
- data/server/files/usr/local/ec2onrails/bin/setup_web_proxy.rb +109 -0
- data/server/files/usr/local/ec2onrails/config +30 -0
- data/server/files/usr/local/ec2onrails/lib/aws_helper.rb +76 -0
- data/server/files/usr/local/ec2onrails/lib/god_helper.rb +129 -0
- data/server/files/usr/local/ec2onrails/lib/god_patch.rb +43 -0
- data/server/files/usr/local/ec2onrails/lib/mysql_helper.rb +101 -0
- data/server/files/usr/local/ec2onrails/lib/roles_helper.rb +151 -0
- data/server/files/usr/local/ec2onrails/lib/s3_helper.rb +99 -0
- data/server/files/usr/local/ec2onrails/lib/utils.rb +16 -0
- data/server/files/usr/local/ec2onrails/lib/vendor/ini.rb +268 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/every-startup/get-hostname.sh +25 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/README +5 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/create-dirs.sh +39 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/generate-default-web-cert-and-key.sh +49 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/misc.sh +27 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/prepare-mysql-data-dir.sh +24 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/setup-credentials.sh +29 -0
- data/server/files/usr/local/ec2onrails/startup-scripts/first-startup/setup-file-permissions.sh +30 -0
- data/server/rakefile.rb +242 -0
- data/setup.rb +1585 -0
- data/test/autobench.conf +60 -0
- data/test/spec/lib/s3_helper_spec.rb +134 -0
- data/test/spec/lib/s3_old.yml +3 -0
- data/test/spec/test_files/test1 +0 -0
- data/test/spec/test_files/test2 +0 -0
- data/test/test_app/Capfile +3 -0
- data/test/test_app/README +182 -0
- data/test/test_app/Rakefile +10 -0
- data/test/test_app/app/controllers/application.rb +7 -0
- data/test/test_app/app/controllers/db_fast_controller.rb +6 -0
- data/test/test_app/app/controllers/fast_controller.rb +5 -0
- data/test/test_app/app/controllers/slow_controller.rb +6 -0
- data/test/test_app/app/controllers/very_slow_controller.rb +6 -0
- data/test/test_app/app/helpers/application_helper.rb +3 -0
- data/test/test_app/app/helpers/db_fast_helper.rb +2 -0
- data/test/test_app/app/helpers/fast_helper.rb +2 -0
- data/test/test_app/app/helpers/slow_helper.rb +2 -0
- data/test/test_app/app/helpers/very_slow_helper.rb +2 -0
- data/test/test_app/config/boot.rb +109 -0
- data/test/test_app/config/database.yml +19 -0
- data/test/test_app/config/deploy.rb +21 -0
- data/test/test_app/config/environment.rb +60 -0
- data/test/test_app/config/environments/development.rb +21 -0
- data/test/test_app/config/environments/production.rb +18 -0
- data/test/test_app/config/environments/test.rb +19 -0
- data/test/test_app/config/routes.rb +27 -0
- data/test/test_app/db/schema.rb +7 -0
- data/test/test_app/doc/README_FOR_APP +2 -0
- data/test/test_app/public/404.html +30 -0
- data/test/test_app/public/500.html +30 -0
- data/test/test_app/public/dispatch.cgi +10 -0
- data/test/test_app/public/dispatch.fcgi +24 -0
- data/test/test_app/public/dispatch.rb +10 -0
- data/test/test_app/public/favicon.ico +0 -0
- data/test/test_app/public/images/rails.png +0 -0
- data/test/test_app/public/javascripts/application.js +2 -0
- data/test/test_app/public/javascripts/controls.js +963 -0
- data/test/test_app/public/javascripts/dragdrop.js +972 -0
- data/test/test_app/public/javascripts/effects.js +1120 -0
- data/test/test_app/public/javascripts/prototype.js +4225 -0
- data/test/test_app/public/robots.txt +1 -0
- data/test/test_app/script/about +3 -0
- data/test/test_app/script/breakpointer +3 -0
- data/test/test_app/script/console +3 -0
- data/test/test_app/script/destroy +3 -0
- data/test/test_app/script/generate +3 -0
- data/test/test_app/script/performance/benchmarker +3 -0
- data/test/test_app/script/performance/profiler +3 -0
- data/test/test_app/script/performance/request +3 -0
- data/test/test_app/script/plugin +3 -0
- data/test/test_app/script/process/inspector +3 -0
- data/test/test_app/script/process/reaper +3 -0
- data/test/test_app/script/process/spawner +3 -0
- data/test/test_app/script/runner +3 -0
- data/test/test_app/script/server +3 -0
- data/test/test_app/test/functional/db_fast_controller_test.rb +18 -0
- data/test/test_app/test/functional/fast_controller_test.rb +18 -0
- data/test/test_app/test/functional/slow_controller_test.rb +18 -0
- data/test/test_app/test/functional/very_slow_controller_test.rb +18 -0
- data/test/test_app/test/test_helper.rb +28 -0
- data/test/test_ec2onrails.rb +11 -0
- data/test/test_helper.rb +2 -0
- metadata +274 -0
@@ -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
|
+
|