mdh-ec2onrails 0.9.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +180 -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.rb +20 -0
- data/lib/ec2onrails/capistrano_utils.rb +43 -0
- data/lib/ec2onrails/recipes.rb +844 -0
- data/lib/ec2onrails/version.rb +31 -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 +152 -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 +248 -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,129 @@
|
|
1
|
+
module GodHelper
|
2
|
+
require '/usr/local/ec2onrails/lib/roles_helper'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
def default_configurations(w)
|
6
|
+
w.interval = 30.seconds
|
7
|
+
w.grace = 30.seconds
|
8
|
+
|
9
|
+
|
10
|
+
w.behavior(:clean_pid_file)
|
11
|
+
|
12
|
+
w.start_if do |start|
|
13
|
+
start.condition(:process_running) do |c|
|
14
|
+
c.notify = {:contacts => ['default'], :category => 'process not started...starting'}
|
15
|
+
c.interval = 5.seconds
|
16
|
+
c.running = false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# w.start_if do |start|
|
21
|
+
# start.condition(:process_running) do |c|
|
22
|
+
# c.interval = 5.seconds
|
23
|
+
# c.running = false
|
24
|
+
# c.notify = {:contacts => ['default'], :category => 'process exited...restarting'}
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
|
28
|
+
# determine when process has finished starting
|
29
|
+
# w.transition([:start, :restart], :up) do |on|
|
30
|
+
# on.condition(:process_running) do |c|
|
31
|
+
# c.running = true
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # failsafe
|
35
|
+
# on.condition(:tries) do |c|
|
36
|
+
# c.times = 8
|
37
|
+
# c.within = 2.minutes
|
38
|
+
# c.transition = :start
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# # start if process is not running
|
43
|
+
# w.transition(:up, :start) do |on|
|
44
|
+
# on.condition(:process_exits) do |c|
|
45
|
+
# c.notify = {:contacts => ['default'], :category => 'process exited...restarting'}
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
end
|
49
|
+
|
50
|
+
def restart_if_resource_hog(w, options={})
|
51
|
+
options = {:memory_usage => 175.megabytes, :cpu_usage => 50.percent}.merge(options)
|
52
|
+
w.restart_if do |restart|
|
53
|
+
if options[:memory_usage]
|
54
|
+
restart.condition(:memory_usage) do |c|
|
55
|
+
c.notify = {:contacts => ['default'], :category => "process over #{options[:memory_usage]/1.megabyte}MB. restarting"}
|
56
|
+
c.above = options[:memory_usage]
|
57
|
+
c.times = [3,5]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if options[:cpu_usage]
|
62
|
+
restart.condition(:cpu_usage) do |c|
|
63
|
+
c.notify = {:contacts => ['default'], :category => "process over #{options[:cpu_usage]*100}%. restarting"}
|
64
|
+
c.above = options[:cpu_usage]
|
65
|
+
c.times = 5
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
yield restart if block_given?
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_pid_dir(w)
|
75
|
+
pid_dir = File.dirname(w.pid_file)
|
76
|
+
return if File.exist?(pid_dir)
|
77
|
+
|
78
|
+
#we need to make sure it is writable...but include all the directories we created...
|
79
|
+
starting_dir = pid_dir
|
80
|
+
starting_dir = File.dirname(starting_dir) until File.exist?(File.dirname(starting_dir))
|
81
|
+
|
82
|
+
FileUtils.mkdir_p(pid_dir)
|
83
|
+
FileUtils.chown_R(w.uid, w.gid, starting_dir)
|
84
|
+
end
|
85
|
+
|
86
|
+
def monitor_lifecycle(w)
|
87
|
+
# w.transition(:up, :unmonitored) do |on|
|
88
|
+
w.lifecycle do |on|
|
89
|
+
on.condition(:flapping) do |c|
|
90
|
+
c.notify = {:contacts => ['default'], :category => 'process flapping...restarting'}
|
91
|
+
c.to_state = [:start, :restart]
|
92
|
+
c.times = 5
|
93
|
+
c.within = 5.minutes
|
94
|
+
c.transition = :unmonitored
|
95
|
+
c.retry_in = 10.minutes
|
96
|
+
c.retry_times = 5
|
97
|
+
c.retry_within = 2.hours
|
98
|
+
end
|
99
|
+
end
|
100
|
+
# w.lifecycle do |on|
|
101
|
+
# on.condition(:flapping) do |c|
|
102
|
+
# c.notify = {:contacts => ['default'], :category => 'process flapping...restarting'}
|
103
|
+
# c.to_state = [:start, :restart]
|
104
|
+
# c.times = 5
|
105
|
+
# c.within = 60.seconds
|
106
|
+
# c.retry_in = 10.minutes
|
107
|
+
# c.retry_times = 5
|
108
|
+
# c.retry_within = 2.hours
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
|
112
|
+
# w.lifecycle do |on|
|
113
|
+
# on.condition(:flapping) do |c|
|
114
|
+
# c.to_state = [:start, :restart]
|
115
|
+
# c.times = 5
|
116
|
+
# c.within = 5.minutes
|
117
|
+
# c.transition = :unmonitored
|
118
|
+
# c.retry_in = 10.minutes
|
119
|
+
# c.retry_times = 5
|
120
|
+
# c.retry_within = 2.hours
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
end
|
124
|
+
|
125
|
+
class Configs
|
126
|
+
include Ec2onrails::RolesHelper
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'god'
|
3
|
+
|
4
|
+
# this is a hack to put the bin directory back at the top of the load path....
|
5
|
+
# the /usr/bin/god script will try to load 'god', which is in the bin path of the gem
|
6
|
+
# but is also the name of the module.... it should really be called something like god_bin
|
7
|
+
# or god_cli, so then it would have no problem being found.
|
8
|
+
$:.unshift File.join($:[0], *%w[.. .. bin])
|
9
|
+
|
10
|
+
module God
|
11
|
+
def self.control(name, command)
|
12
|
+
# get the list of items
|
13
|
+
items = Array(self.watches[name] || self.groups[name]).dup
|
14
|
+
|
15
|
+
jobs = []
|
16
|
+
# do the command
|
17
|
+
case command
|
18
|
+
when "start", "monitor"
|
19
|
+
items.each { |w| jobs << Thread.new { w.monitor if w.state != :up } }
|
20
|
+
when "restart"
|
21
|
+
items.each { |w| jobs << Thread.new { w.move(:restart) } }
|
22
|
+
when "stop"
|
23
|
+
# items.each { |w| jobs << Thread.new { w.unmonitor.action(:stop) if w.state != :unmonitored } }
|
24
|
+
items.each do |w|
|
25
|
+
jobs << Thread.new do
|
26
|
+
w.unmonitor if w.state != :unmonitored
|
27
|
+
w.action(:stop) if w.alive?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
when "unmonitor"
|
31
|
+
items.each { |w| jobs << Thread.new { w.unmonitor if w.state != :unmonitored } }
|
32
|
+
when "remove"
|
33
|
+
items.each { |w| self.unwatch(w) }
|
34
|
+
else
|
35
|
+
raise InvalidCommandError.new
|
36
|
+
end
|
37
|
+
|
38
|
+
jobs.each { |j| j.join }
|
39
|
+
|
40
|
+
items.map { |x| x.name }
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,101 @@
|
|
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 'rubygems'
|
20
|
+
require 'aws/s3'
|
21
|
+
require 'yaml'
|
22
|
+
require 'erb'
|
23
|
+
require 'fileutils'
|
24
|
+
require "#{File.dirname(__FILE__)}/utils"
|
25
|
+
|
26
|
+
module Ec2onrails
|
27
|
+
class MysqlHelper
|
28
|
+
|
29
|
+
DEFAULT_CONFIG_FILE = "/mnt/app/current/config/database.yml"
|
30
|
+
|
31
|
+
attr_accessor :database
|
32
|
+
attr_accessor :user
|
33
|
+
attr_accessor :password
|
34
|
+
|
35
|
+
def initialize(config_file = DEFAULT_CONFIG_FILE, rails_env = Utils.rails_env)
|
36
|
+
@rails_env = rails_env
|
37
|
+
load_db_config(config_file)
|
38
|
+
end
|
39
|
+
|
40
|
+
def load_db_config(config_file)
|
41
|
+
db_config = YAML::load(ERB.new(File.read(config_file)).result)
|
42
|
+
if db_config && db_config[@rails_env].nil?
|
43
|
+
puts "the rails environment '#{@rails_env}' was not found in this db onfig file: #{config_file}"
|
44
|
+
end
|
45
|
+
db_config = db_config[@rails_env]
|
46
|
+
@database = db_config['database']
|
47
|
+
@user = db_config['username']
|
48
|
+
@password = db_config['password']
|
49
|
+
end
|
50
|
+
|
51
|
+
def execute_sql(sql)
|
52
|
+
raise "@user not set" unless @user
|
53
|
+
raise "sql not given" unless sql
|
54
|
+
cmd = %{mysql -u #{@user} -e "#{sql}"}
|
55
|
+
cmd += " -p'#{@password}' " unless @password.nil?
|
56
|
+
Utils.run cmd
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute
|
60
|
+
require "mysql"
|
61
|
+
|
62
|
+
begin
|
63
|
+
# connect to the MySQL server
|
64
|
+
dbh = Mysql.real_connect("localhost", "#{@user}", "#{@password}", "#{@database}")
|
65
|
+
yield dbh
|
66
|
+
rescue Mysql::Error => e
|
67
|
+
puts "Error code: #{e.errno}"
|
68
|
+
puts "Error message: #{e.error}"
|
69
|
+
puts "Error SQLSTATE: #{e.sqlstate}" if e.respond_to?("sqlstate")
|
70
|
+
ensure
|
71
|
+
# disconnect from server
|
72
|
+
dbh.close if dbh
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def dump(out_file, reset_logs)
|
79
|
+
cmd = "mysqldump --quick --single-transaction --create-options -u#{@user} "
|
80
|
+
if reset_logs
|
81
|
+
cmd += " --flush-logs --master-data=2 --delete-master-logs "
|
82
|
+
end
|
83
|
+
cmd += " -p'#{@password}' " unless @password.nil?
|
84
|
+
cmd += " #{@database} | gzip > #{out_file}"
|
85
|
+
Utils.run cmd
|
86
|
+
end
|
87
|
+
|
88
|
+
def load_from_dump(in_file)
|
89
|
+
cmd = "gunzip -c #{in_file} | mysql -u#{@user} "
|
90
|
+
cmd += " -p'#{@password}' " unless @password.nil?
|
91
|
+
cmd += " #{@database}"
|
92
|
+
Utils.run cmd
|
93
|
+
end
|
94
|
+
|
95
|
+
def execute_binary_log(log_file)
|
96
|
+
cmd = "mysqlbinlog --database=#{@database} #{log_file} | mysql -u#{@user} "
|
97
|
+
cmd += " -p'#{@password}' " unless @password.nil?
|
98
|
+
Utils.run cmd
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,151 @@
|
|
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 'net/http'
|
20
|
+
require 'pp'
|
21
|
+
require 'socket'
|
22
|
+
require 'yaml'
|
23
|
+
require 'erb'
|
24
|
+
|
25
|
+
module Ec2onrails
|
26
|
+
module RolesHelper
|
27
|
+
ROLES_FILE = "/etc/ec2onrails/roles.yml"
|
28
|
+
MONGREL_CONF_FILE = "/etc/mongrel_cluster/app.yml"
|
29
|
+
|
30
|
+
def local_address
|
31
|
+
@local_address ||= get_metadata "local-ipv4"
|
32
|
+
end
|
33
|
+
|
34
|
+
def public_address
|
35
|
+
@public_address ||= get_metadata "public-ipv4"
|
36
|
+
end
|
37
|
+
|
38
|
+
def roles
|
39
|
+
@roles ||= resolve_all_addresses(YAML::load_file(ROLES_FILE))
|
40
|
+
end
|
41
|
+
|
42
|
+
def start(role, service, prog_name = service)
|
43
|
+
puts "STARTING #{role} role (service: #{service}, program_name: #{prog_name})"
|
44
|
+
sudo "god start #{role}"
|
45
|
+
# sudo "god monitor #{role}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def stop(role, service, prog_name = service)
|
49
|
+
puts "STOPING #{role} role (service: #{service}, program_name: #{prog_name})"
|
50
|
+
# sudo "god monitor #{role}"
|
51
|
+
sudo "god stop #{role}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def run(cmd)
|
55
|
+
result = system(cmd)
|
56
|
+
puts("*****ERROR: #{cmd} returned #{$?}") unless result
|
57
|
+
end
|
58
|
+
|
59
|
+
def sudo(cmd)
|
60
|
+
run("sudo #{cmd}")
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_metadata(type)
|
64
|
+
data = Net::HTTP.get('169.254.169.254', "/latest/meta-data/#{type}").strip
|
65
|
+
|
66
|
+
raise "couldn't get instance data: #{type}" if data.nil? || data.strip.length == 0
|
67
|
+
# puts "#{type}: #{address}"
|
68
|
+
return data
|
69
|
+
end
|
70
|
+
|
71
|
+
def resolve(hostname)
|
72
|
+
address = IPSocket.getaddress(hostname).strip
|
73
|
+
if address == local_address || address == public_address
|
74
|
+
"127.0.0.1"
|
75
|
+
else
|
76
|
+
address
|
77
|
+
end
|
78
|
+
rescue Exception => e
|
79
|
+
puts "couldn't resolve hostname '#{hostname}'"
|
80
|
+
raise e
|
81
|
+
end
|
82
|
+
|
83
|
+
def resolve_all_addresses(original)
|
84
|
+
resolved = {}
|
85
|
+
original.each do |rolename, hostnames|
|
86
|
+
resolved[rolename] = hostnames.map{|hostname| resolve(hostname)} if hostnames
|
87
|
+
end
|
88
|
+
resolved
|
89
|
+
end
|
90
|
+
|
91
|
+
def in_role?(role)
|
92
|
+
return false unless roles[role]
|
93
|
+
return roles[role].include?("127.0.0.1")
|
94
|
+
end
|
95
|
+
#to provide deprecated usage
|
96
|
+
alias :in_role :in_role?
|
97
|
+
|
98
|
+
|
99
|
+
def add_etc_hosts_entry(entry_name, entry_addr)
|
100
|
+
host_file = "/etc/hosts"
|
101
|
+
run("cp #{host_file}.original #{host_file}") unless File.exists?("#{host_file}.original")
|
102
|
+
hosts = File.read(host_file)
|
103
|
+
if hosts =~ /\s*.+?\s+#{entry_name}\s*$/
|
104
|
+
hosts.sub!(/\s*.+?\s+#{entry_name}\s*$/, "\n#{entry_addr}\t#{entry_name}\n")
|
105
|
+
else
|
106
|
+
puts "adding '#{entry_addr}\t#{entry_name}' to /etc/hosts"
|
107
|
+
hosts << "\n#{entry_addr}\t#{entry_name}\n"
|
108
|
+
end
|
109
|
+
File.open(host_file, 'w') {|f| f.write(hosts) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def web_starting_port
|
113
|
+
mongrel_config['port'].to_i rescue 8000
|
114
|
+
end
|
115
|
+
|
116
|
+
def web_num_instances
|
117
|
+
mongrel_config['servers'].to_i rescue 6
|
118
|
+
end
|
119
|
+
|
120
|
+
def web_port_range
|
121
|
+
(web_starting_port..(web_starting_port + web_num_instances-1))
|
122
|
+
end
|
123
|
+
|
124
|
+
def server_environment
|
125
|
+
mongrel_config["environment"]
|
126
|
+
end
|
127
|
+
|
128
|
+
def user
|
129
|
+
mongrel_config['user']
|
130
|
+
end
|
131
|
+
|
132
|
+
def group
|
133
|
+
mongrel_config['group']
|
134
|
+
end
|
135
|
+
|
136
|
+
def application_root
|
137
|
+
mongrel_config['cwd']
|
138
|
+
end
|
139
|
+
|
140
|
+
def pid_file
|
141
|
+
"#{application_root}/#{mongrel_config['pid_file']}"
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def mongrel_config
|
147
|
+
@mongrel_config ||= YAML::load_file(MONGREL_CONF_FILE)
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,99 @@
|
|
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 'rubygems'
|
20
|
+
require 'aws/s3'
|
21
|
+
require 'yaml'
|
22
|
+
require 'erb'
|
23
|
+
require 'fileutils'
|
24
|
+
require "#{File.dirname(__FILE__)}/utils"
|
25
|
+
require "#{File.dirname(__FILE__)}/aws_helper"
|
26
|
+
|
27
|
+
module Ec2onrails
|
28
|
+
class S3Helper
|
29
|
+
|
30
|
+
# make attributes available for specs
|
31
|
+
attr_accessor :bucket
|
32
|
+
attr_accessor :dir
|
33
|
+
attr_accessor :config_file
|
34
|
+
attr_accessor :rails_env
|
35
|
+
attr_accessor :aws_access_key
|
36
|
+
attr_accessor :aws_secret_access_key
|
37
|
+
attr_accessor :bucket
|
38
|
+
|
39
|
+
def initialize(bucket, dir, config_file = Ec2onrails::AwsHelper.default_config_file, rails_env = Utils.rails_env)
|
40
|
+
@dir = dir
|
41
|
+
@config_file = config_file
|
42
|
+
@rails_env = rails_env
|
43
|
+
@awsHelper = Ec2onrails::AwsHelper.new(config_file, rails_env)
|
44
|
+
@aws_access_key = @awsHelper.aws_access_key
|
45
|
+
@aws_secret_access_key = @awsHelper.aws_secret_access_key
|
46
|
+
@bucket_base_name = @awsHelper.bucket_base_name
|
47
|
+
@bucket = bucket || "#{@bucket_base_name}-#{Ec2onrails::Utils.hostname}"
|
48
|
+
AWS::S3::Base.establish_connection!(:access_key_id => @aws_access_key, :secret_access_key => @aws_secret_access_key, :use_ssl => true)
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_bucket
|
52
|
+
retries = 0
|
53
|
+
begin
|
54
|
+
AWS::S3::Bucket.find(@bucket)
|
55
|
+
rescue AWS::S3::NoSuchBucket
|
56
|
+
AWS::S3::Bucket.create(@bucket)
|
57
|
+
sleep 1 # If we try to use the bucket too quickly sometimes it's not found
|
58
|
+
retry if (retries += 1) < 15
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def store_file(file)
|
63
|
+
create_bucket
|
64
|
+
AWS::S3::S3Object.store(s3_key(file), open(file), @bucket)
|
65
|
+
end
|
66
|
+
|
67
|
+
def retrieve_file(file)
|
68
|
+
key = s3_key(file)
|
69
|
+
AWS::S3::S3Object.find(key, @bucket)
|
70
|
+
open(file, 'w') do |f|
|
71
|
+
AWS::S3::S3Object.stream(key, @bucket) do |chunk|
|
72
|
+
f.write chunk
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def list_keys(filename_prefix)
|
78
|
+
prefix = @dir ? "#{@dir}/#{filename_prefix}" : filename_prefix
|
79
|
+
AWS::S3::Bucket.objects(@bucket, :prefix => prefix).collect{|obj| obj.key}
|
80
|
+
end
|
81
|
+
|
82
|
+
def retrieve_files(filename_prefix, local_dir)
|
83
|
+
list_keys(filename_prefix).each do |k|
|
84
|
+
file = "#{local_dir}/#{File.basename(k)}"
|
85
|
+
retrieve_file(file)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete_files(filename_prefix)
|
90
|
+
list_keys(filename_prefix).each do |k|
|
91
|
+
AWS::S3::S3Object.delete(k, @bucket)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def s3_key(file)
|
96
|
+
@dir ? "#{@dir}/#{File.basename(file)}" : File.basename(file)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|