dark-capistrano-recipes 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Webficient LLC, Phil Misiowiec
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,89 @@
1
+ =Capistrano Recipes
2
+
3
+ Useful Capistrano recipes including:
4
+
5
+ * Create MySQL database and user on server (via prompts)
6
+ * Create standalone copy of database.yml in shared path (via prompts)
7
+ * Log rotation and tailing commands
8
+ * Restart and profile Phusion Passenger application server
9
+ * Configure, start/stop/restart Unicorn application server
10
+
11
+ ==Included Tasks
12
+
13
+ * cap db:create_yaml
14
+ * cap db:mysql:setup
15
+ * cap log:rotate
16
+ * cap log:tail
17
+ * cap passenger:bounce
18
+ * cap passenger:memory
19
+ * cap passenger:status
20
+ * cap nginx:setup
21
+ * cap nginx:start
22
+ * cap nginx:stop
23
+ * cap nginx:restart
24
+ * cap nginx:status
25
+ * cap unicorn:start
26
+ * cap unicorn:stop
27
+ * cap unicorn:restart
28
+ * cap unicorn:setup
29
+ * cap symlinks:make
30
+
31
+ ==Installation
32
+
33
+ Easy as pie...
34
+
35
+ Ensure you have the Capistrano gem installed:
36
+
37
+ sudo gem install capistrano
38
+
39
+ Optionally install the Capistrano extensions gem to give you multistage support:
40
+
41
+ sudo gem install capistrano-ext
42
+
43
+ Install this gem:
44
+
45
+ sudo gem install capistrano-recipes --source=http://gemcutter.com
46
+
47
+ To setup the initial Capistrano deploy file, go to your Rails app folder via command line and enter:
48
+
49
+ capify .
50
+
51
+ ==Configuration
52
+
53
+ Inside the newly created config/deploy.rb, add:
54
+
55
+ require 'capistrano_recipes'
56
+ require 'capistrano/ext/multistage' # only require if you've installed Cap ext gem
57
+
58
+ ===RVM
59
+
60
+ RVM is enabled by default. You can disable it by setting :using_rvm to false, or leverage it
61
+ by setting your rvm_ruby_string to appropriate ones (default is ree)
62
+
63
+ If using_rvm is true, the rvm recipe will load rvm's own capistrano extensions so you don't
64
+ have to worry about it during deploy. Just make sure you have everything set up right, like
65
+ .rvmrc on project root and system-wide install on the servers.
66
+
67
+ See (http://rvm.beginrescueend.com/rvm/install) for more info.
68
+
69
+ ===Nginx
70
+
71
+ If you're using nginx as your web server, set :web_server to :nginx and deploy:setup will
72
+ generate the appropriate configuration file for it based on your other variables, such as
73
+ :application_uses_ssl, etc.
74
+
75
+ ===Passenger
76
+
77
+ If you're running Phusion Passenger (http://www.modrails.com) be sure you add this line to config/deploy.rb:
78
+
79
+ set :server, :passenger
80
+
81
+ ===Unicorn
82
+
83
+ If you're running Unicorn (http://unicorn.bogomips.org/) be sure to add this line instead:
84
+
85
+ set :server, :unicorn
86
+
87
+ ==Copyright
88
+
89
+ Copyright (c) 2009 Webficient LLC, Phil Misiowiec. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "dark-capistrano-recipes"
8
+ gem.summary = %Q{Darkside's Capistrano recipes}
9
+ gem.description = 'Extend the Capistrano gem with these useful recipes'
10
+ gem.email = "leonardobighetti@gmail.com"
11
+ gem.homepage = "http://github.com/darkside/capistrano-recipes"
12
+ gem.authors = ["Phil Misiowiec", "Leonardo Bighetti"]
13
+ gem.add_dependency('capistrano', ['>= 2.5.9'])
14
+ gem.add_dependency('capistrano-ext', ['>= 1.2.1'])
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
20
+ end
21
+
22
+ require 'rake/rdoctask'
23
+ Rake::RDocTask.new do |rdoc|
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = 'capistrano-recipes'
26
+ rdoc.options << '--line-numbers' << '--inline-source'
27
+ rdoc.rdoc_files.include('README*')
28
+ rdoc.rdoc_files.include('lib/**/*.rb')
29
+ end
30
+
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :patch: 4
3
+ :major: 0
4
+ :build:
5
+ :minor: 6
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{dark-capistrano-recipes}
8
+ s.version = "0.6.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Phil Misiowiec", "Leonardo Bighetti"]
12
+ s.date = %q{2010-09-20}
13
+ s.description = %q{Extend the Capistrano gem with these useful recipes}
14
+ s.email = %q{leonardobighetti@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION.yml",
25
+ "dark-capistrano-recipes.gemspec",
26
+ "doc/god/god",
27
+ "doc/god/god.conf",
28
+ "doc/god/god.init",
29
+ "generators/app.god.erb",
30
+ "generators/nginx.conf.erb",
31
+ "generators/unicorn.rb.erb",
32
+ "lib/capistrano_recipes.rb",
33
+ "lib/helpers.rb",
34
+ "lib/recipes/application.rb",
35
+ "lib/recipes/bundler.rb",
36
+ "lib/recipes/db.rb",
37
+ "lib/recipes/deploy.rb",
38
+ "lib/recipes/god.rb",
39
+ "lib/recipes/hooks.rb",
40
+ "lib/recipes/log.rb",
41
+ "lib/recipes/nginx.rb",
42
+ "lib/recipes/passenger.rb",
43
+ "lib/recipes/rvm.rb",
44
+ "lib/recipes/symlinks.rb",
45
+ "lib/recipes/unicorn.rb"
46
+ ]
47
+ s.homepage = %q{http://github.com/darkside/capistrano-recipes}
48
+ s.rdoc_options = ["--charset=UTF-8"]
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = %q{1.3.7}
51
+ s.summary = %q{Darkside's Capistrano recipes}
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
58
+ s.add_runtime_dependency(%q<capistrano>, [">= 2.5.9"])
59
+ s.add_runtime_dependency(%q<capistrano-ext>, [">= 1.2.1"])
60
+ else
61
+ s.add_dependency(%q<capistrano>, [">= 2.5.9"])
62
+ s.add_dependency(%q<capistrano-ext>, [">= 1.2.1"])
63
+ end
64
+ else
65
+ s.add_dependency(%q<capistrano>, [">= 2.5.9"])
66
+ s.add_dependency(%q<capistrano-ext>, [">= 1.2.1"])
67
+ end
68
+ end
69
+
data/doc/god/god ADDED
@@ -0,0 +1 @@
1
+ GOD_CONFIG=/etc/god/god.conf
data/doc/god/god.conf ADDED
@@ -0,0 +1,102 @@
1
+ APPS_ROOT = Dir.glob("/var/www/apps/*/current/config/app.god")
2
+
3
+ # Helper Methods
4
+ def unicorn(w, config, options = {})
5
+ rails_root = options[:rails_root]
6
+ rails_env = options[:rails_env] || 'production'
7
+ unicorn_group = options[:app] || options[:name] || 'default'
8
+ unicorn_name = "#{unicorn_group}-unicorn"
9
+ unicorn_bin = options[:bin_unicorn] || 'bootup_unicorn_rails'
10
+ unicorn_pid = options[:unicorn_pid] || "#{rails_root}/log/unicorn.pid"
11
+ unicorn_config = "#{rails_root}/config/unicorn.rb"
12
+ unicorn_start = options[:start_cmd] || "cd #{rails_root} && #{unicorn_bin} -c #{unicorn_config} -E #{rails_env} -D"
13
+ # QUIT gracefully shuts down workers
14
+ unicorn_stop = options[:stop_cmd] || "kill -QUIT `cat #{unicorn_pid}`"
15
+ # USR2 causes the master to re-create itself and spawn a new worker pool
16
+ unicorn_restart = options[:restart_cmd] || "kill -USR2 `cat #{unicorn_pid}`"
17
+
18
+
19
+ w.name = unicorn_name
20
+ w.group = unicorn_group
21
+ w.start = unicorn_start
22
+ w.stop = unicorn_stop
23
+ w.restart = unicorn_restart
24
+ w.start_grace = 20.seconds
25
+ w.restart_grace = 20.seconds
26
+ w.pid_file = unicorn_pid
27
+ w.behavior(:clean_pid_file)
28
+
29
+ generic_monitor(w, config, rails_root, options)
30
+ end
31
+
32
+ def generic_monitor(w, config, rails_root, options = {})
33
+ w.uid = options[:user] || 'deploy'
34
+ w.gid = options[:group] || 'www-data'
35
+ w.interval = 60.seconds # default
36
+
37
+ # determine the state on startup
38
+ w.transition(:init, { true => :up, false => :start }) do |on|
39
+ on.condition(:process_running) do |c|
40
+ c.running = true
41
+ end
42
+ end
43
+
44
+ # determine when process has finished starting
45
+ w.transition([:start, :restart], :up) do |on|
46
+ on.condition(:process_running) do |c|
47
+ c.running = true
48
+ end
49
+
50
+ # failsafe
51
+ on.condition(:tries) do |c|
52
+ c.times = 5
53
+ c.transition = :start
54
+ end
55
+ end
56
+
57
+ # start if process is not running
58
+ w.transition(:up, :start) do |on|
59
+ on.condition(:process_exits) do |c|
60
+ end
61
+ end
62
+
63
+ # restart if memory or cpu is too high
64
+ w.transition(:up, :restart) do |on|
65
+ on.condition(:memory_usage) do |c|
66
+ c.interval = 20
67
+ c.above = 100.megabytes
68
+ c.times = [3, 5]
69
+ end
70
+
71
+ on.condition(:cpu_usage) do |c|
72
+ c.interval = 10
73
+ c.above = 20.percent
74
+ c.times = [3, 5]
75
+ end
76
+ end
77
+
78
+ # lifecycle
79
+ w.lifecycle do |on|
80
+ on.condition(:flapping) do |c|
81
+ c.to_state = [:start, :restart]
82
+ c.times = 5
83
+ c.within = 5.minute
84
+ c.transition = :unmonitored
85
+ c.retry_in = 10.minutes
86
+ c.retry_times = 5
87
+ c.retry_within = 2.hours
88
+ end
89
+ end
90
+ end
91
+
92
+ God.log_level = :info
93
+ puts "God is loading the apps now..."
94
+ APPS_ROOT.each do |app|
95
+ begin
96
+ puts "Loading app: #{app}"
97
+ God.load app
98
+ puts "Done"
99
+ rescue Exception => e
100
+ puts "Failed! #{e}"
101
+ end
102
+ end
data/doc/god/god.init ADDED
@@ -0,0 +1,62 @@
1
+ #!/bin/sh
2
+
3
+ ### BEGIN INIT INFO
4
+ # Provides: god
5
+ # Required-Start: $all
6
+ # Required-Stop: $all
7
+ # Default-Start: 2 3 4 5
8
+ # Default-Stop: 0 1 6
9
+ # Short-Description: God
10
+ ### END INIT INFO
11
+
12
+ NAME=god
13
+ DESC=god
14
+
15
+ GOD_BIN=/usr/local/bin/bootup_god
16
+ GOD_PID=/var/run/god.pid
17
+ GOD_LOG=/var/log/god.log
18
+ set -e
19
+
20
+ # Make sure the binary and the config file are present before proceeding
21
+ test -x $GOD_BIN || exit 0
22
+
23
+ # Create this file and put in a variable called GOD_CONFIG, pointing to
24
+ # your God configuration file
25
+ test -f /etc/default/god && . /etc/default/god
26
+ [ $GOD_CONFIG ] || exit 0
27
+
28
+ . /lib/lsb/init-functions
29
+
30
+ RETVAL=0
31
+
32
+ case "$1" in
33
+ start)
34
+ echo -n "Starting $DESC: "
35
+ $GOD_BIN -c $GOD_CONFIG -P $GOD_PID -l $GOD_LOG
36
+ RETVAL=$?
37
+ echo "$NAME."
38
+ ;;
39
+ stop)
40
+ echo -n "Stopping $DESC: "
41
+ kill `cat $GOD_PID`
42
+ RETVAL=$?
43
+ echo "$NAME."
44
+ ;;
45
+ restart)
46
+ echo -n "Restarting $DESC: "
47
+ kill `cat $GOD_PID`
48
+ $GOD_BIN -c $GOD_CONFIG -P $GOD_PID -l $GOD_LOG
49
+ RETVAL=$?
50
+ echo "$NAME."
51
+ ;;
52
+ status)
53
+ $GOD_BIN status
54
+ RETVAL=$?
55
+ ;;
56
+ *)
57
+ echo "Usage: god {start|stop|restart|status}"
58
+ exit 1
59
+ ;;
60
+ esac
61
+
62
+ exit $RETVAL
@@ -0,0 +1,25 @@
1
+ app_name = '<%= application %>'
2
+ rails_root = '<%= deploy_to %>/current'
3
+ unicorn_bin = '<%= unicorn_bin %>'
4
+ unicorn_pid = '<%= unicorn_pid %>'
5
+ unicorn_config = '<%= unicorn_remote_config %>'
6
+ unicorn_start_cmd = '<%= unicorn_start_cmd %>'
7
+ unicorn_stop_cmd = '<%= unicorn_stop_cmd %>'
8
+ unicorn_restart_cmd = '<%= unicorn_restart_cmd %>'
9
+
10
+ # Unicorn
11
+ God.watch do |w|
12
+ unicorn(w, rails_root,
13
+ :memory_limit => 100.megabytes,
14
+ :cpu_limit => 50.percent,
15
+ :bin_unicorn => unicorn_bin,
16
+ :name => app_name,
17
+ :rails_root => rails_root,
18
+ :unicorn_conf => unicorn_config,
19
+ :unicorn_pid => unicorn_pid,
20
+ :start_cmd => unicorn_start_cmd,
21
+ :stop_cmd => unicorn_stop_cmd,
22
+ :restart_cmd => unicorn_restart_cmd,
23
+ :user => '<%= unicorn_user %>',
24
+ :group => '<%= unicorn_group %>')
25
+ end
@@ -0,0 +1,150 @@
1
+ upstream <%= application %>_app_server {
2
+ server unix:<%= unicorn_socket %> fail_timeout=0;
3
+ }
4
+ # <%= application %> Server
5
+ server {
6
+ listen <%= application_port %>;
7
+
8
+ client_max_body_size 500M;
9
+ server_name <%= application %>;
10
+
11
+ # ~2 seconds is often enough for most folks to parse HTML/CSS and
12
+ # retrieve needed images/icons/frames, connections are cheap in
13
+ # nginx so increasing this is generally safe...
14
+ keepalive_timeout 5;
15
+
16
+ # path for static files
17
+ root <%= deploy_to %>/current/public;
18
+ access_log <%= deploy_to %>/current/log/nginx.access.log main;
19
+ error_log <%= deploy_to %>/current/log/nginx.error.log info;
20
+
21
+ # this rewrites all the requests to the maintenance.html
22
+ # page if it exists in the doc root. This is for capistrano's
23
+ # disable web task
24
+ if (-f $document_root/system/maintenance.html) {
25
+ rewrite ^(.*)$ /system/maintenance.html last;
26
+ break;
27
+ }
28
+
29
+ location / {
30
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
31
+ #proxy_set_header X-Forwarded-Proto https;
32
+ proxy_set_header Host $http_host;
33
+ #proxy_redirect off;
34
+
35
+ # If the file exists as a static file serve it directly without
36
+ # running all the other rewite tests on it
37
+ if (-f $request_filename) {
38
+ break;
39
+ }
40
+
41
+ # check for index.html for directory index
42
+ # if its there on the filesystem then rewite
43
+ # the url to add /index.html to the end of it
44
+ # and then break to send it to the next config rules.
45
+ if (-f $request_filename/index.html) {
46
+ rewrite (.*) $1/index.html break;
47
+ }
48
+
49
+ # this is the meat of the rails page caching config
50
+ # it adds .html to the end of the url and then checks
51
+ # the filesystem for that file. If it exists, then we
52
+ # rewite the url to have explicit .html on the end
53
+ # and then send it on its way to the next config rule.
54
+ # if there is no file on the fs then it sets all the
55
+ # necessary headers and proxies to our upstream mongrels
56
+ if (-f $request_filename.html) {
57
+ rewrite (.*) $1.html break;
58
+ }
59
+
60
+ if (!-f $request_filename) {
61
+ proxy_pass http://<%= application %>_app_server;
62
+ break;
63
+ }
64
+
65
+ }
66
+
67
+ # Rails error pages
68
+ error_page 500 502 503 504 /500.html;
69
+ location = /500.html {
70
+ root <%= deploy_to %>/current/public;
71
+ }
72
+ }
73
+ <% if application_uses_ssl %>
74
+ upstream <%= application %>_app_ssl {
75
+ server unix:<%= unicorn_socket %> fail_timeout=0;
76
+ }
77
+ # This server is setup for ssl. Uncomment if
78
+ # you are using ssl as well as port 80.
79
+ server {
80
+ listen <%= application_port_ssl%>;
81
+ server_name <%= application %>;
82
+
83
+ ssl on;
84
+ ssl_certificate /etc/ssl/certs/server.crt;
85
+ ssl_certificate_key /etc/ssl/private/server.key;
86
+ ssl_session_timeout 5m;
87
+ client_max_body_size 50M;
88
+
89
+ root <%= deploy_to %>/current/public;
90
+ access_log <%= deploy_to %>/current/log/nginx.access.log main;
91
+ error_log <%= deploy_to %>/current/log/nginx.error.log info;
92
+
93
+ # this rewrites all the requests to the maintenance.html
94
+ # page if it exists in the doc root. This is for capistrano's
95
+ # disable web task
96
+ if (-f $document_root/system/maintenance.html) {
97
+ rewrite ^(.*)$ /system/maintenance.html last;
98
+ break;
99
+ }
100
+
101
+ location / {
102
+ # needed to forward user's IP address to rails
103
+ proxy_set_header X-Real-IP $remote_addr;
104
+
105
+ # needed for HTTPS
106
+ proxy_set_header X_FORWARDED_PROTO https;
107
+
108
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
109
+ proxy_set_header Host $http_host;
110
+ proxy_redirect off;
111
+ proxy_max_temp_file_size 0;
112
+
113
+
114
+ # If the file exists as a static file serve it directly without
115
+ # running all the other rewite tests on it
116
+ if (-f $request_filename) {
117
+ break;
118
+ }
119
+
120
+ # check for index.html for directory index
121
+ # if its there on the filesystem then rewite
122
+ # the url to add /index.html to the end of it
123
+ # and then break to send it to the next config rules.
124
+ if (-f $request_filename/index.html) {
125
+ rewrite (.*) $1/index.html break;
126
+ }
127
+
128
+ # this is the meat of the rails page caching config
129
+ # it adds .html to the end of the url and then checks
130
+ # the filesystem for that file. If it exists, then we
131
+ # rewite the url to have explicit .html on the end
132
+ # and then send it on its way to the next config rule.
133
+ # if there is no file on the fs then it sets all the
134
+ # necessary headers and proxies to our upstream mongrels
135
+ if (-f $request_filename.html) {
136
+ rewrite (.*) $1.html break;
137
+ }
138
+
139
+ if (!-f $request_filename) {
140
+ proxy_pass http://<%= application %>_app_ssl;
141
+ break;
142
+ }
143
+ }
144
+
145
+ error_page 500 502 503 504 /500.html;
146
+ location = /500.html {
147
+ root <%= deploy_to %>/current/public;
148
+ }
149
+ }
150
+ <% end %>