capistrano-zen 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,51 @@
1
+ # default capistrano tasks
2
+ load 'deploy'
3
+ load 'deploy/assets'
4
+
5
+ # the database.yml path
6
+ set :pg_config_path, File.expand_path(File.dirname(__FILE__), 'config')
7
+
8
+ # load the recipes
9
+ require 'capistrano-zen/utils'
10
+ require 'capistrano-zen/nginx'
11
+ require 'capistrano-zen/postgresql'
12
+ require 'capistrano-zen/rbenv'
13
+ require 'capistrano-zen/unicorn'
14
+
15
+ # Use Git as Version Control System
16
+ set :scm, :git
17
+ set :repository, "git@github.com:zenhacks/some_application.git"
18
+ set :branch, 'master'
19
+
20
+ # enable prompt for password
21
+ default_run_options[:pty] = true
22
+
23
+ # access github.com using as the local user
24
+ ssh_options[:forward_agent] = true
25
+
26
+ set :application, 'my_application'
27
+
28
+ set :domain, "domain.com"
29
+
30
+ server 'domain.com', :web, :app, :db, :primary => true
31
+
32
+ set :user, 'deploy'
33
+ set :group, 'deploy'
34
+ set :deploy_to, "/home/#{user}/repositories/#{application}-production"
35
+
36
+
37
+ ## Deploy Dependencies
38
+ after "deploy:install",
39
+ "nginx:install",
40
+ "nodejs:install",
41
+ "rbenv:install",
42
+ "dev_lib:install",
43
+ "pg:install"
44
+
45
+ after "deploy:setup",
46
+ "nginx:setup",
47
+ "pg:setup",
48
+ "pg:init",
49
+ "unicorn:setup"
50
+
51
+ after "deploy:finalize_update", "pg:symlink"
@@ -0,0 +1,52 @@
1
+ require 'capistrano-zen/nginx'
2
+
3
+ # enable prompt for password
4
+ default_run_options[:pty] = true
5
+
6
+ # try_sudo will not use sudo by default
7
+ set :use_sudo, false
8
+
9
+ # access github.com using as the local user
10
+ ssh_options[:forward_agent] = true
11
+
12
+ set :application, "application name"
13
+
14
+ set :domain, "domain.com"
15
+
16
+ # maxwell - 42.121.82.106, aliyun,hangzhou
17
+ server 'server_name', :web, :app, :db, :primary => true
18
+
19
+ set :user, 'deploy'
20
+ set :deploy_to, "/home/#{user}/sites/#{application}-production"
21
+
22
+ namespace :deploy do
23
+ desc "Deploys your project. This calls both `update' and `nginx.restart'. "
24
+ task :default, roles: :app do
25
+ update
26
+ nginx.restart
27
+ end
28
+
29
+ desc "Setup the directory for the application."
30
+ task :setup, roles: :app do
31
+ dirs = [deploy_to]
32
+ run "mkdir -p #{dirs.join(' ')}"
33
+ run "chmod g+w #{dirs.join(' ')}" if fetch(:group_writable, true)
34
+ end
35
+
36
+ desc "Update the dest code for this application."
37
+ task :update, roles: :app do
38
+ # your own deploy logic
39
+
40
+ # sample for a middleman site
41
+ # system('bundle exec middleman build --clean')
42
+ # roles[:app].servers.each do |server|
43
+ # system("rsync -cuavz build/* #{user}@#{server}:#{deploy_to}")
44
+ # end
45
+ end
46
+ end
47
+
48
+ after "deploy:install",
49
+ "nginx:install"
50
+
51
+ after "deploy:setup",
52
+ "nginx:setup:static"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-zen.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Steven Yang
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,156 @@
1
+ ## What Capistrano::Zen Is?
2
+ `Capistrano-zen` is **a collection of capistrano recipes** to install and manage various services on production machine powered by Ubuntu. The current tested environment is Ubuntu 12.04LTS.
3
+
4
+ It provides installation and management recipes for the following service:
5
+ - nginx
6
+ - with config templates for rails app
7
+ - nodejs
8
+ - postgresql
9
+ - unicorn (integrated with a nginx/railsapp)
10
+ - rbenv
11
+
12
+ The upcoming recipes include:
13
+ - nginx
14
+ - global config template
15
+ - static website template
16
+ - shorewall
17
+ - vsftp
18
+ - php-fpm
19
+ - mysql
20
+ - mongodb
21
+ - redis
22
+
23
+ `capistrano-zen` is extracted from the deployment procedure at [zenhacks.org](zenhacks.org) for a Rails application so it is designed to work with the structure of a rails application. But most recipes are independent and future development will detach general recipes from a rails application.
24
+
25
+ ## What Capistrano::Zen isn't?
26
+ `capistrano-zen` only provides recipes of tasks, it doesn't handle:
27
+
28
+ - the application dependencies
29
+ - the logic of deployment logic
30
+ - the server settings and configuration
31
+
32
+ You will need to declare those in your own capistrano config file such as `Capfile` or `config/deploy.rb`.
33
+
34
+ The gem includes some sample files to start with `Capfile-rails.sample`.
35
+
36
+ ## Installation
37
+
38
+ Add this line to your application's Gemfile:
39
+
40
+ gem 'capistrano-zen'
41
+
42
+ And then execute:
43
+
44
+ $ bundle
45
+
46
+ Or install it yourself as:
47
+
48
+ $ gem install capistrano-zen
49
+
50
+ ## Dependencies
51
+ `capistrano-zen` uses `python-software-properties` to ease ppa source addition. You could install it with use `python-software-properties` to ease ppa source addition. You could install it from your local machine with
52
+
53
+ cap deploy:install
54
+
55
+ Or install it mannually with
56
+
57
+ sudo apt-get install python-software-properties
58
+
59
+ ## Usage
60
+
61
+ To load a set of recipes, require them in your `Capfile` with:
62
+
63
+ require 'capistrano-zen/nginx'
64
+
65
+ You could verify the load is successful with:
66
+
67
+ cap -T
68
+
69
+ ## Recipes
70
+ Here is the recipes included in this gem:
71
+
72
+ - nginx
73
+ - with config templates for rails app
74
+ - nodejs
75
+ - postgresql
76
+ - unicorn (integrated with a nginx/railsapp)
77
+ - rbenv
78
+
79
+ ### Nginx
80
+ Default role: `web`
81
+
82
+ Configuration variables: none
83
+
84
+ Tasks:
85
+ - `nginx:install` installs the lastest release from the ppa `ppa:nginx/stable`.
86
+ - `nginx:start/stop/reload` maps to `sudo service nginx start/stop/reload` on the remote machine.
87
+ - `nginx:setup` generates a nginx site configuration for a rails app runs with `unicorn` through unix socket.
88
+
89
+ ### NodeJS
90
+ Default role: `app`
91
+
92
+ Configuration variables: none
93
+
94
+ Tasks:
95
+ - `nodejs:install` installs `node` and `npm` from the `ppa:chris-lea/node.js`.
96
+
97
+ The ppa comes from [official wiki](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager).
98
+
99
+ ### Rbenv
100
+ It uses the [rbenv installer](https://github.com/fesplugas/rbenv-installer) to create a `ruby` environment.
101
+
102
+ Default role: `app`
103
+
104
+ Configuration variables:
105
+ - `ruby_version` indicates the ruby version installed.
106
+ - `rbenv_bootstrap` indicates the ubuntu version to install the rbenv bootstrap.
107
+
108
+ Tasks:
109
+ - `rbenv:install` installs `rbenv`, setups configuration in `~/.bashrc` and installs `ruby` with `ruby_version`
110
+ - `rbenv:patch` autoruns a ruby patch to enhance performance. [more info](https://gist.github.com/1688857?utm_source=rubyweekly&utm_medium=email)
111
+
112
+ ### PostgreSQL
113
+ Currently, postgresql configuration is tightly attached to a rails application, it depends on the `config/database.yml` to setup remote server.
114
+
115
+ Default role: `db`
116
+
117
+ Configuration variables:
118
+ - `pg_config_path` the path for the `database.yml` file, the recipe reads from it to create database and generate remote `database.yml`. If you are using this recipe out of Rails application, store your configuration in a `config/database.yml`.
119
+ - `pg_backup_path` the path to store database dumps.
120
+
121
+ Tasks:
122
+ - `pg:install` installs `postgresql` and `libpg-dev` from `ppa:pitti/postgresql`.
123
+ - `pg:reset` drops the databases and roles with the same names as in the application.
124
+ - `pg:init` generates roles and databases for the rails application.
125
+ - `pg:setup` generates remote `database.yml` based on local `database.yml`'s `production` settings.
126
+ - `pg:symlink` creates symbolic for the `database.yml` in the release.
127
+ - `pg:dump` dumps and compresses the application database, store them in the `pg_backup_path`.
128
+ - `pg:restore` prompts and restores selected dumps from the `pg_backup_path`, it defaults to lastest dump.
129
+
130
+ ### Unicorn
131
+ This recipes setup unicorn configuration based on current rails application, and generate a `init.d` control scripts to manage the service.
132
+ Default role: `app`
133
+
134
+ Configuration variables:
135
+ - `unicorn_user` the user to run unicorn process, default to the same user as remote login user.
136
+ - `unicorn_group` the group to run unicorn process.
137
+ - `unicorn_pid` the path for the `unicorn.pid` file, default to the `current/tmp/pids/unicorn.pid`.
138
+ - `unicorn_config` the path to put the unicorn config file, default to `shared/config/unicorn.rb`.
139
+ - `unicorn_log` the path to put the unicorn log file, default to `shared/log/unicorn.log`.
140
+ - `unicorn_workers` the number of unicorn workers, default to 4.
141
+
142
+ Tasks:
143
+ - `unicorn:setup` generate `unicorn.rb` config file and register `service` with `unicorn_init`.
144
+ - `unicorn:start/stop/restart/upgrade/force-stop` maps to remote `service unicorn start/stop/restart/upgrade/force-stop`. Details is in `/tmpls/unicorn_init.rb`
145
+
146
+ ### Utils
147
+ - `check:revision` autoruns before any deployment tasks. It compares the local and remote master branch head to make sure remote master branch are up-to-date.
148
+ - `dev_lib:install` install libraries on which some gems depend such as `nokogiri` or `paperclip`.
149
+
150
+ ## Get Started with Capistrano
151
+ The [wiki page](https://github.com/capistrano/capistrano/wiki) of `capistrano` has good resources to make you up to speed.
152
+ [Railscasts](http://railscasts.com/episodes?utf8=%E2%9C%93&search=capistrano) also has a good coverage for this tool.
153
+
154
+ ## TODO
155
+ - make configuration rails-less
156
+ - add more recipes
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capistrano-zen/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "capistrano-zen"
8
+ gem.version = Capistrano::Zen::VERSION
9
+ gem.authors = ["Steven Yang"]
10
+ gem.email = ["yangchenyun@gmail.com"]
11
+ gem.description = %q{Capistrano Recipes used at zenhacks.org.}
12
+ gem.summary = %q{Nginx, Unicorn, PostgreSQL, NodeJS Recipes install on a machine running Ubuntu. }
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ gem.extra_rdoc_files = [
20
+ "LICENSE"
21
+ ]
22
+
23
+ gem.add_dependency "capistrano", ">= 2.5.3"
24
+ end
@@ -0,0 +1,15 @@
1
+ require 'capistrano-zen/common'
2
+
3
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
4
+ Capistrano::Configuration.instance(:must_exist) :
5
+ Capistrano.configuration(:must_exist)
6
+
7
+ configuration.load do
8
+ namespace :deploy do
9
+ desc "Install everything onto the server"
10
+ task :install do
11
+ run "#{sudo} apt-get -y update"
12
+ run "#{sudo} apt-get -y install python-software-properties"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ def _cset(name, *args, &block)
2
+ unless exists?(name)
3
+ set(name, *args, &block)
4
+ end
5
+ end
6
+
7
+ def template(from, to)
8
+ erb = File.read(File.expand_path("../tmpls/#{from}", __FILE__))
9
+ put ERB.new(erb).result(binding), to
10
+ end
@@ -0,0 +1,40 @@
1
+ require 'capistrano-zen/base'
2
+
3
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
4
+ Capistrano::Configuration.instance(:must_exist) :
5
+ Capistrano.configuration(:must_exist)
6
+
7
+ configuration.load do
8
+ namespace :nginx do
9
+ desc "Install latest stable release of nginx"
10
+ task :install, roles: :web do
11
+ run "#{sudo} add-apt-repository -y ppa:nginx/stable"
12
+ run "#{sudo} apt-get -y update"
13
+ run "#{sudo} apt-get -y install nginx"
14
+ run "#{sudo} rm -f /etc/nginx/sites-enabled/default"
15
+ end
16
+
17
+ namespace :setup do
18
+ desc "Setup nginx configuration for unicorn application"
19
+ task :unicorn, roles: :web do
20
+ template "nginx_unicorn.erb", "/tmp/nginx_conf"
21
+ run "#{sudo} mv /tmp/nginx_conf /etc/nginx/sites-enabled/#{application}"
22
+ restart
23
+ end
24
+
25
+ desc "Setup nginx configuration for static website"
26
+ task :static, roles: :web do
27
+ template "nginx_static.erb", "/tmp/nginx_conf"
28
+ run "#{sudo} mv /tmp/nginx_conf /etc/nginx/sites-enabled/#{application}"
29
+ restart
30
+ end
31
+ end
32
+
33
+ %w[start stop restart reload].each do |command|
34
+ desc "#{command} nginx"
35
+ task command, roles: :web do
36
+ run "#{sudo} service nginx #{command}"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,18 @@
1
+ require 'capistrano-zen/base'
2
+
3
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
4
+ Capistrano::Configuration.instance(:must_exist) :
5
+ Capistrano.configuration(:must_exist)
6
+
7
+ configuration.load do
8
+ namespace :nodejs do
9
+ desc "Install the latest relase of Node.js"
10
+ # Reference
11
+ # https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
12
+ task :install, roles: :app do
13
+ run "#{sudo} add-apt-repository -y ppa:chris-lea/node.js"
14
+ run "#{sudo} apt-get -y update"
15
+ run "#{sudo} apt-get -y install nodejs npm"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,81 @@
1
+ require 'capistrano-zen/base'
2
+ require 'yaml'
3
+
4
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
5
+ Capistrano::Configuration.instance(:must_exist) :
6
+ Capistrano.configuration(:must_exist)
7
+
8
+ configuration.load do
9
+
10
+ _cset(:pg_config_path) { abort "[Error] posgtresql recipes need `pg_config_path` to find the database.yml file." }
11
+ _cset(:pg_backup_path) { abort "[Error] posgtresql recipes need `pg_backup_path` to execute backups." }
12
+
13
+ DB_FILE_PATH = "#{pg_config_path}/database.yml"
14
+ DBCONFIG = YAML.load_file(DB_FILE_PATH)
15
+
16
+ _cset(:psql_host) { DBCONFIG['production']['host'] }
17
+ _cset(:psql_user) { DBCONFIG['production']['username'] }
18
+ _cset(:psql_password) { DBCONFIG['production']['password'] }
19
+ _cset(:psql_database) { DBCONFIG['production']['database'] }
20
+
21
+ namespace :pg do
22
+ desc "Install the latest stable release of psql."
23
+ task :install, roles: :db, only: {primary: true} do
24
+ run "#{sudo} add-apt-repository -y ppa:pitti/psql"
25
+ run "#{sudo} apt-get -y update"
26
+ run "#{sudo} apt-get -y install psql libpq-dev"
27
+ end
28
+
29
+ desc "Create a database for this application."
30
+ task :init, roles: :db, only: { primary: true } do
31
+ # reset the database and role
32
+ run %Q{#{sudo} -u postgres psql -c "CREATE USER #{psql_user} WITH PASSWORD '#{psql_password}';"}
33
+ run %Q{#{sudo} -u postgres psql -c "CREATE DATABASE #{psql_database} OWNER #{psql_user};"}
34
+ end
35
+
36
+ desc "Reset the database and role for this application."
37
+ task :reset, roles: :db, only: { primary: true } do
38
+ # drop the database and role
39
+ run %Q{#{sudo} -u postgres psql -c "DROP DATABASE #{psql_database};"}
40
+ run %Q{#{sudo} -u postgres psql -c "DROP ROLE #{psql_user};"}
41
+ end
42
+
43
+ desc "Generate the database.yml configuration file."
44
+ task :setup, roles: :app do
45
+ run "mkdir -p #{shared_path}/config"
46
+ template "postgresql.yml.erb", "#{shared_path}/config/database.yml"
47
+ # init backup directory
48
+ run "#{sudo} mkdir -p #{pg_backup_path}"
49
+ run "#{sudo} chown :#{group} #{pg_backup_path}"
50
+ run "#{sudo} chmod g+w #{pg_backup_path}"
51
+ end
52
+
53
+ desc "Symlink the database.yml file into latest release"
54
+ task :symlink, roles: :app do
55
+ run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
56
+ end
57
+
58
+ desc "Dump the application's database to backup path."
59
+ task :dump, roles: :db, only: { primary: true } do
60
+ # ignore migrations / exclude ownership / clean restore
61
+ run "pg_dump #{psql_database} -T '*migrations' -O -c -U #{psql_user} -h #{psql_host} | gzip > #{pg_backup_path}/#{application}-#{release_name}.sql.gz" do |channel, stream, data|
62
+ puts data if data.length >= 3
63
+ channel.send_data("#{psql_password}\n") if data.include? 'Password'
64
+ end
65
+ end
66
+
67
+ desc "Restore the application's database from dump files."
68
+ task :restore, roles: :db, only: { primary: true } do
69
+ backups = capture("ls -x #{pg_backup_path}").split.sort
70
+ default_backup = backups.last
71
+ puts "Available backups: "
72
+ puts backups
73
+ backup = Capistrano::CLI.ui.ask "Which backup would you like to restore? [#{default_backup}] "
74
+ backup = backups.last if backup.empty?
75
+ run "gunzip -c #{pg_backup_path}/#{backup} | psql -d #{psql_database} -U #{psql_user} -h #{psql_host}" do |channel, stream, data|
76
+ puts data if data.length >= 3
77
+ channel.send_data("#{psql_password}\n") if data.include? 'Password'
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,52 @@
1
+ require 'capistrano-zen/base'
2
+
3
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
4
+ Capistrano::Configuration.instance(:must_exist) :
5
+ Capistrano.configuration(:must_exist)
6
+
7
+ configuration.load do
8
+ _cset :ruby_version, "1.9.3-p194"
9
+ _cset :rbenv_bootstrap, "bootstrap-ubuntu-12-04"
10
+ _cset(:root_password) { Capistrano::CLI.password_prompt "Root Password: " }
11
+
12
+ # https://github.com/fesplugas/rbenv-installer
13
+ namespace :rbenv do
14
+ desc "Install rbenv, Ruby, and the Bundler gem"
15
+ task :install, roles: :app do
16
+ run "#{sudo} apt-get -y install curl git-core"
17
+ run "curl -L https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash"
18
+ # FIXME run command to change download path to taobao
19
+ bashrc = <<-BASHRC
20
+ if [ -d $HOME/.rbenv ]; then
21
+ export PATH="$HOME/.rbenv/bin:$PATH"
22
+ eval "$(rbenv init -)"
23
+ fi
24
+ BASHRC
25
+ put bashrc, "/tmp/rbenvrc"
26
+ run "cat /tmp/rbenvrc ~/.bashrc > ~/.bashrc.tmp"
27
+ run "mv ~/.bashrc.tmp ~/.bashrc"
28
+ run "rm /tmp/rbenvrc"
29
+ run "rbenv #{rbenv_bootstrap}" do |channel, stream, data|
30
+ puts data if data.length >= 3
31
+ channel.send_data("#{root_password}\n") if data.include? 'password'
32
+ end
33
+ run "rbenv install #{ruby_version}"
34
+ run "rbenv global #{ruby_version}"
35
+ end
36
+
37
+ task :patch, roles: :app do
38
+ # the performance patch
39
+ # https://gist.github.com/1688857?utm_source=rubyweekly&utm_medium=email
40
+ run "#{sudo} apt-get -y install autoconf"
41
+ case "#{ruby_version}"
42
+ when "1.9.3-p194"
43
+ run "curl https://raw.github.com/gist/1688857/rbenv.sh | sh ; rbenv global 1.9.3-p194-perf"
44
+ when "1.9.3-p286"
45
+ run "curl https://raw.github.com/gist/3885178/rbenv.sh | sh ; rbenv global 1.9.3-p286-perf"
46
+ end
47
+ run "gem install bundler --no-ri --no-rdoc"
48
+ run "rbenv rehash"
49
+ end
50
+ after "rbenv:install", "rbenv:patch"
51
+ end
52
+ end
@@ -0,0 +1,12 @@
1
+ server {
2
+ listen 80;
3
+ server_name <%= domain %>;
4
+
5
+ root <%= deploy_to %>;
6
+ gzip_static on;
7
+
8
+ access_log /var/log/nginx/<%= application %>-access.log;
9
+ error_log /var/log/nginx/<%= application %>-error.log;
10
+
11
+ error_page 500 502 503 504 /500.html;
12
+ }
@@ -0,0 +1,33 @@
1
+ upstream <%= application %>_unicorn {
2
+ server unix:/tmp/unicorn.<%= application %>.sock fail_timeout=0;
3
+ }
4
+
5
+ server {
6
+ listen 80;
7
+ server_name <%= domain %>;
8
+
9
+ access_log /var/log/nginx/<%= application %>-access.log;
10
+ error_log /var/log/nginx/<%= application %>-error.log;
11
+
12
+ root <%= current_path %>/public;
13
+
14
+ location ^~ /assets/ {
15
+ gzip_static on;
16
+ expires max;
17
+ add_header Cache-Control public;
18
+ }
19
+
20
+ # try to serve static file first
21
+ try_files $uri/index.html $uri @unicorn;
22
+
23
+ location @unicorn {
24
+ proxy_set_header Host $http_host;
25
+ proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
26
+ proxy_redirect off;
27
+ proxy_pass http://<%= application %>_unicorn;
28
+ }
29
+
30
+ error_page 500 502 503 504 /500.html;
31
+ client_max_body_size 100M;
32
+ keepalive_timeout 10;
33
+ }
@@ -0,0 +1,8 @@
1
+ production:
2
+ adapter: postgresql
3
+ encoding: unicode
4
+ database: <%= psql_database %>
5
+ pool: 5
6
+ username: <%= psql_user %>
7
+ password: <%= psql_password %>
8
+ host: <%= psql_host %>
@@ -0,0 +1,89 @@
1
+ RAILS_ENV = ENV['RAILS_ENV'] || 'production'
2
+
3
+ # unicorn workers
4
+ worker_processes <%= unicorn_workers %>
5
+
6
+ # FIXME problems here
7
+ # working_directory "<%= current_path %>"
8
+
9
+ # Load rails+github.git into the master before forking workers
10
+ # for super-fast worker spawn times
11
+ preload_app true
12
+
13
+ # Restart any workers that haven't responded in 30 seconds
14
+ timeout 30
15
+
16
+ pid "<%= unicorn_pid %>"
17
+ stderr_path "<%= current_path %>/log/unicorn.stderr.log"
18
+ stdout_path "<%= current_path %>/log/unicorn.stdout.log"
19
+
20
+ # Listen on a Unix data socket
21
+ listen '/tmp/unicorn.<%= application %>.sock', :backlog => 2048
22
+
23
+ ##
24
+ # REE
25
+
26
+ # http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
27
+ if GC.respond_to?(:copy_on_write_friendly=)
28
+ GC.copy_on_write_friendly = true
29
+ end
30
+
31
+
32
+ before_fork do |server, worker|
33
+ ##
34
+ # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
35
+ # immediately start loading up a new version of itself (loaded with a new
36
+ # version of our app). When this new Unicorn is completely loaded
37
+ # it will begin spawning workers. The first worker spawned will check to
38
+ # see if an .oldbin pidfile exists. If so, this means we've just booted up
39
+ # a new Unicorn and need to tell the old one that it can now die. To do so
40
+ # we send it a QUIT.
41
+ #
42
+ # Using this method we get 0 downtime deploys.
43
+
44
+ old_pid = '<%= unicorn_pid %>.oldbin'
45
+ if File.exists?(old_pid) && server.pid != old_pid
46
+ begin
47
+ Process.kill("QUIT", File.read(old_pid).to_i)
48
+ rescue Errno::ENOENT, Errno::ESRCH
49
+ # someone else did our job for us
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ after_fork do |server, worker|
56
+ ##
57
+ # Unicorn master loads the app then forks off workers - because of the way
58
+ # Unix forking works, we need to make sure we aren't using any of the parent's
59
+ # sockets, e.g. db connection
60
+
61
+ ActiveRecord::Base.establish_connection
62
+ # CHIMNEY.client.connect_to_server
63
+ # Redis and Memcached would go here but their connections are established
64
+ # on demand, so the master never opens a socket
65
+
66
+
67
+ ##
68
+ # Unicorn master is started as root, which is fine, but let's
69
+ # drop the workers to deploy:deploy
70
+
71
+ begin
72
+ uid, gid = Process.euid, Process.egid
73
+ user, group = '<%= unicorn_user %>', '<%= unicorn_group %>'
74
+ target_uid = Etc.getpwnam(user).uid
75
+ target_gid = Etc.getgrnam(group).gid
76
+ worker.tmp.chown(target_uid, target_gid)
77
+ if uid != target_uid || gid != target_gid
78
+ Process.initgroups(user, target_gid)
79
+ Process::GID.change_privilege(target_gid)
80
+ Process::UID.change_privilege(target_uid)
81
+ end
82
+ rescue => e
83
+ if RAILS_ENV == 'development'
84
+ STDERR.puts "couldn't change user, oh well"
85
+ else
86
+ raise e
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,84 @@
1
+ #!/bin/sh
2
+ ### BEGIN INIT INFO
3
+ # Provides: unicorn
4
+ # Required-Start: $remote_fs $syslog
5
+ # Required-Stop: $remote_fs $syslog
6
+ # Default-Start: 2 3 4 5
7
+ # Default-Stop: 0 1 6
8
+ # Short-Description: Manage unicorn server
9
+ # Description: Start, stop, restart unicorn server for a specific application.
10
+ ### END INIT INFO
11
+ set -e
12
+
13
+ # Feel free to change any of the following variables for your app:
14
+ TIMEOUT=${TIMEOUT-60}
15
+ APP_ROOT=<%= current_path %>
16
+ PID=<%= unicorn_pid %>
17
+ CMD="cd <%= current_path %>; bundle exec unicorn -D -c <%= unicorn_config %> -E production"
18
+ AS_USER=<%= unicorn_user %>
19
+ set -u
20
+
21
+ OLD_PIN="$PID.oldbin"
22
+
23
+ sig () {
24
+ test -s "$PID" && kill -$1 `cat $PID`
25
+ }
26
+
27
+ oldsig () {
28
+ test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
29
+ }
30
+
31
+ run () {
32
+ if [ "$(id -un)" = "$AS_USER" ]; then
33
+ eval $1
34
+ else
35
+ su -c "$1" - $AS_USER
36
+ fi
37
+ }
38
+
39
+ case "$1" in
40
+ start)
41
+ sig 0 && echo >&2 "Already running" && exit 0
42
+ run "$CMD"
43
+ ;;
44
+ stop)
45
+ sig QUIT && exit 0
46
+ echo >&2 "Not running"
47
+ ;;
48
+ force-stop)
49
+ sig TERM && exit 0
50
+ echo >&2 "Not running"
51
+ ;;
52
+ restart|reload)
53
+ sig HUP && echo reloaded OK && exit 0
54
+ echo >&2 "Couldn't reload, starting '$CMD' instead"
55
+ run "$CMD"
56
+ ;;
57
+ upgrade)
58
+ if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
59
+ then
60
+ n=$TIMEOUT
61
+ while test -s $OLD_PIN && test $n -ge 0
62
+ do
63
+ printf '.' && sleep 1 && n=$(( $n - 1 ))
64
+ done
65
+ echo
66
+
67
+ if test $n -lt 0 && test -s $OLD_PIN
68
+ then
69
+ echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
70
+ exit 1
71
+ fi
72
+ exit 0
73
+ fi
74
+ echo >&2 "Couldn't upgrade, starting '$CMD' instead"
75
+ run "$CMD"
76
+ ;;
77
+ reopen-logs)
78
+ sig USR1
79
+ ;;
80
+ *)
81
+ echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
82
+ exit 1
83
+ ;;
84
+ esac
@@ -0,0 +1,34 @@
1
+ require 'capistrano-zen/base'
2
+
3
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
4
+ Capistrano::Configuration.instance(:must_exist) :
5
+ Capistrano.configuration(:must_exist)
6
+
7
+ configuration.load do
8
+ _cset(:unicorn_user) { user }
9
+ _cset(:unicorn_group) { group }
10
+ _cset(:unicorn_pid) { "#{current_path}/tmp/pids/unicorn.pid" }
11
+ _cset(:unicorn_config) { "#{shared_path}/config/unicorn.rb" }
12
+ _cset(:unicorn_log) { "#{shared_path}/log/unicorn.log" }
13
+ _cset(:unicorn_workers, 4)
14
+
15
+ namespace :unicorn do
16
+ desc "Setup Unicorn initializer and app configuration"
17
+ task :setup, roles: :app do
18
+ run "mkdir -p #{shared_path}/config"
19
+ template "unicorn.rb.erb", unicorn_config
20
+ template "unicorn_init.erb", "/tmp/unicorn_init"
21
+ run "chmod +x /tmp/unicorn_init"
22
+ run "#{sudo} mv /tmp/unicorn_init /etc/init.d/unicorn_#{application}"
23
+ run "#{sudo} update-rc.d -f unicorn_#{application} defaults"
24
+ end
25
+
26
+ %w[start stop restart upgrade force-stop].each do |command|
27
+ desc "#{command} unicorn"
28
+ task command, roles: :app do
29
+ run "service unicorn_#{application} #{command}"
30
+ end
31
+ after "deploy:#{command}", "unicorn:#{command}"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ require 'capistrano-zen/base'
2
+
3
+ configuration = Capistrano::Configuration.respond_to?(:instance) ?
4
+ Capistrano::Configuration.instance(:must_exist) :
5
+ Capistrano.configuration(:must_exist)
6
+
7
+ configuration.load do
8
+ before "deploy", "check:revision"
9
+ before "deploy:migrations", "check:revision"
10
+ before "deploy:cold", "check:revision"
11
+
12
+ namespace :check do
13
+ desc "Make sure local git is in sync with remote."
14
+ task :revision do
15
+ unless `git rev-parse #{branch}` == `git rev-parse origin/#{branch}`
16
+ puts "WARNING: HEAD is not the same as origin/#{branch}"
17
+ puts "Run `git push` to sync changes."
18
+ exit
19
+ end
20
+ end
21
+ end
22
+
23
+ namespace :dev_lib do
24
+ task :install do
25
+ # nokogiri dependencies
26
+ run "#{sudo} apt-get -y install libxslt-dev libxml2-dev"
27
+
28
+ # paperclip dependencies
29
+ run "#{sudo} apt-get -y install imagemagick"
30
+
31
+ # sqlite3 dependencies
32
+ run "#{sudo} apt-get -y install libsqlite3-dev"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module Zen
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-zen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Steven Yang
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.5.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 2.5.3
30
+ description: Capistrano Recipes used at zenhacks.org.
31
+ email:
32
+ - yangchenyun@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files:
36
+ - LICENSE
37
+ files:
38
+ - .gitignore
39
+ - Capfile-rails.sample
40
+ - Capfile-static.sample
41
+ - Gemfile
42
+ - LICENSE
43
+ - README.md
44
+ - Rakefile
45
+ - capistrano-zen.gemspec
46
+ - lib/capistrano-zen/base.rb
47
+ - lib/capistrano-zen/common.rb
48
+ - lib/capistrano-zen/nginx.rb
49
+ - lib/capistrano-zen/nodejs.rb
50
+ - lib/capistrano-zen/postgresql.rb
51
+ - lib/capistrano-zen/rbenv.rb
52
+ - lib/capistrano-zen/tmpls/nginx_static.erb
53
+ - lib/capistrano-zen/tmpls/nginx_unicorn.erb
54
+ - lib/capistrano-zen/tmpls/postgresql.yml.erb
55
+ - lib/capistrano-zen/tmpls/unicorn.rb.erb
56
+ - lib/capistrano-zen/tmpls/unicorn_init.erb
57
+ - lib/capistrano-zen/unicorn.rb
58
+ - lib/capistrano-zen/utils.rb
59
+ - lib/capistrano-zen/version.rb
60
+ homepage: ''
61
+ licenses: []
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.24
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Nginx, Unicorn, PostgreSQL, NodeJS Recipes install on a machine running Ubuntu.
84
+ test_files: []