capistrano-cookbook 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +246 -0
  6. data/Rakefile +1 -0
  7. data/capistrano-cookbook.gemspec +24 -0
  8. data/lib/capistrano/.DS_Store +0 -0
  9. data/lib/capistrano/cookbook/.DS_Store +0 -0
  10. data/lib/capistrano/cookbook/check_revision.rb +1 -0
  11. data/lib/capistrano/cookbook/compile_assets_locally.rb +1 -0
  12. data/lib/capistrano/cookbook/create_database.rb +1 -0
  13. data/lib/capistrano/cookbook/helpers/setup_config_values.rb +57 -0
  14. data/lib/capistrano/cookbook/helpers/substitute_strings.rb +12 -0
  15. data/lib/capistrano/cookbook/helpers/template.rb +35 -0
  16. data/lib/capistrano/cookbook/logs.rb +1 -0
  17. data/lib/capistrano/cookbook/monit.rb +1 -0
  18. data/lib/capistrano/cookbook/nginx.rb +1 -0
  19. data/lib/capistrano/cookbook/restart.rb +1 -0
  20. data/lib/capistrano/cookbook/run_tests.rb +1 -0
  21. data/lib/capistrano/cookbook/setup_config.rb +1 -0
  22. data/lib/capistrano/cookbook/tasks/check_revision.cap +14 -0
  23. data/lib/capistrano/cookbook/tasks/compile_assets_locally.cap +16 -0
  24. data/lib/capistrano/cookbook/tasks/create_database.cap +32 -0
  25. data/lib/capistrano/cookbook/tasks/logs.cap +14 -0
  26. data/lib/capistrano/cookbook/tasks/monit.cap +10 -0
  27. data/lib/capistrano/cookbook/tasks/nginx.cap +22 -0
  28. data/lib/capistrano/cookbook/tasks/restart.cap +10 -0
  29. data/lib/capistrano/cookbook/tasks/run_tests.cap +18 -0
  30. data/lib/capistrano/cookbook/tasks/setup_config.cap +45 -0
  31. data/lib/capistrano/cookbook/templates/database.example.yml.erb +11 -0
  32. data/lib/capistrano/cookbook/templates/log_rotation.erb +11 -0
  33. data/lib/capistrano/cookbook/templates/mongoid.example.yml.erb +69 -0
  34. data/lib/capistrano/cookbook/templates/monit.erb +22 -0
  35. data/lib/capistrano/cookbook/templates/nginx.conf.erb +57 -0
  36. data/lib/capistrano/cookbook/templates/sidekiq.yml.erb +2 -0
  37. data/lib/capistrano/cookbook/templates/sidekiq_init.sh.erb +40 -0
  38. data/lib/capistrano/cookbook/templates/unicorn.rb.erb +41 -0
  39. data/lib/capistrano/cookbook/templates/unicorn_init.sh.erb +86 -0
  40. data/lib/capistrano/cookbook/version.rb +5 -0
  41. data/lib/capistrano/cookbook.rb +15 -0
  42. metadata +134 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 35eb6b3a910ba77b7eb89ce34b18a058c3b3be03
4
+ data.tar.gz: a953b777c7e7d98576cd022be446b29e9be8fca4
5
+ SHA512:
6
+ metadata.gz: 85b4b56e0ae319ec6e4d23fd4896a880eefc3be20ed9429345da128a95d656d742a4d503033c1201bb6cf044b00b8a6dc6551004bb3359b7a21dda7c822ac1a1
7
+ data.tar.gz: 9fc81774aeda29f06691d0932bf6e3d3ab7dfce740e7ba53bd518632ef09679b5f4de2501de37d1801968f35d659451ef1f1c3a29a2e0da53bc7acf85028c715
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
18
+ DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-cookbook.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Ben Dixon
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,246 @@
1
+ # Capistrano::Cookbook
2
+
3
+ A collection of Capistrano 3 Compatible tasks to make deploying Rails and Sinatra based applications easier.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'capistrano-cookbook'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install capistrano-cookbook
18
+
19
+ ## Usage
20
+
21
+ ### Including Tasks
22
+
23
+ To include all tasks from the gem, add the following to your `Capfile`:
24
+
25
+ ```ruby
26
+ require 'capistrano/cookbook'
27
+ ```
28
+
29
+ Otherwise you can include tasks individually:
30
+
31
+ ```ruby
32
+ require 'capistrano/cookbook/check_revision'
33
+ require 'capistrano/cookbook/compile_assets_locally'
34
+ require 'capistrano/cookbook/create_database'
35
+ require 'capistrano/cookbook/logs'
36
+ require 'capistrano/cookbook/monit'
37
+ require 'capistrano/cookbook/nginx'
38
+ require 'capistrano/cookbook/restart'
39
+ require 'capistrano/cookbook/run_tests'
40
+ require 'capistrano/cookbook/setup_config'
41
+ ```
42
+
43
+ ### The Tasks
44
+
45
+ #### Check Revision
46
+
47
+ Checks that the remote branch the selected stage deploys from, matches the current local version, if it doesn't the deploy will be halted with an error.
48
+
49
+ Add the following to `deploy.rb`
50
+
51
+ ```ruby
52
+ before :deploy, 'deploy:check_revision'
53
+ ```
54
+
55
+ #### Compile Assets Locally
56
+
57
+ Compiles local assets and then rsyncs them to the production server. Avoids the need for a javascript runtime on the target machine and saves a significant amount of time when deploying to multiple web frontends.
58
+
59
+ Add the following to `deploy.rb`
60
+
61
+ ``` ruby
62
+ after 'deploy:symlink:shared', 'deploy:compile_assets_locally'
63
+ ```
64
+
65
+ #### Create Database
66
+
67
+ Currently only works with Postgresql on configurations where your web server and db server are the same machine, e.g. single box deployments. This task will:
68
+
69
+ * Check to see if a remote `database.yml` exists in `APP_PATH/shared/config`, if not attempt to copy one from `APP_PATH/shared/config`.
70
+ * Download the remote `database.yml`
71
+ * Create the Postgres user specified in `database.yml` if it doesn't already exist
72
+ * Create the Database specified in `database.yml` if it doesn't already exist
73
+ * Grant the user all permissions on that database
74
+
75
+ Run using:
76
+
77
+ ``` bash
78
+ cap STAGE database:create
79
+ ```
80
+
81
+ #### Logs
82
+
83
+ Allows remote log files (anything in `APP_PATH/shared/log`) to be tailed locally with Capistrano rather than SSHing in.
84
+
85
+ To tail the log file `APP_PATH/shared/log/production.log` on the `production` stage:
86
+
87
+ ``` bash
88
+ cap production 'logs:tail[production]'
89
+ ```
90
+
91
+ To tail the log file `APP_PATH/shared/log/unicorn.log`
92
+
93
+ ``` bash
94
+ cap production 'logs:tail[unicorn]'
95
+ ```
96
+
97
+ #### Monit
98
+
99
+ Provides convenience tasks for restarting the Monit service.
100
+
101
+ Available actions are `start`, `stop` and `restart`.
102
+
103
+ Usage:
104
+
105
+ ```bash
106
+ cap STAGE monit:start
107
+ cap STAGE monit:stop
108
+ cap STAGE monit:restart
109
+ ```
110
+
111
+ #### Nginx
112
+
113
+ Provides convenience tasks for interacting with Nginx using its `init.d` script as well as an additional task to remove the `default` virtualhost from `/etc/nginx/sites-enabled`
114
+
115
+ Available actions are `start`, `stop`, `restart`, `reload`, `remove_default_vhost`.
116
+
117
+ `reload` will reload the nginx virtualhosts without restarting the server.
118
+
119
+ Usage:
120
+
121
+ ```bash
122
+ cap STAGE nginx:start
123
+ cap STAGE nginx:stop
124
+ cap STAGE nginx:restart
125
+ cap STAGE nginx:remove_default_vhost
126
+ ```
127
+
128
+ #### Restart
129
+
130
+ Provides Commands for interacting with the Unicorn app server via an `init.d` script.
131
+
132
+ Usage:
133
+
134
+ ``` bash
135
+ cap STAGE deploy:start
136
+ cap STAGE deploy:stop
137
+ cap STAGE deploy:force-stop
138
+ cap STAGE deploy:restart
139
+ cap STAGE deploy:upgrade
140
+ ```
141
+
142
+ #### Run Tests
143
+
144
+ Allows a test suite to be automatically run with `rspec`, if the tests pass the deploy will continue, if they fail, the deploy will halt and the test output will be displayed.
145
+
146
+ Usage:
147
+
148
+ Define the tests to be run in `deploy.rb`
149
+
150
+ ``` ruby
151
+ set(:tests, ['spec'])
152
+ ```
153
+
154
+ and add a hook in `deploy.rb` to run them automatically:
155
+
156
+ ``` ruby
157
+ before "deploy", "deploy:run_tests"
158
+ ```
159
+
160
+ #### Setup Config
161
+
162
+ The `deploy:setup_config` tasks provides a simple way to automate the generation of server specific configuration files and the setting up of any required symlinks outside of the applications normal directory structure.
163
+
164
+ If no values are provided in `deploy.rb` to override the defaults then this task includes opinionated defaults to setup a server for deployment as explained in the book [Reliably Deploying Rails Applications](https://leanpub.com/deploying_rails_applications) and [this tutorial](http://www.talkingquickly.co.uk/2014/01/deploying-rails-apps-to-a-vps-with-capistrano-v3/).
165
+
166
+ Each of the `config_files` will be created in `APP_PATH/shared.config`.
167
+
168
+ The task looks in the following locations for a template file with a corresponding name with a `.erb` extension:
169
+
170
+ * `config/deploy/STAGE/FILENAME.erb`
171
+ * `config/deploy/shared/FILENAME.erb`
172
+ * `templates/FILENAME.erb` directory of this gem ([github link](https://github.com/TalkingQuickly/capistrano-cookbook/tree/master/lib/capistrano/cookbook/templates))
173
+
174
+ For any config files included in the `source` part of an entry in the `symlinks` array, a symlink will be created to the corresponding `link` location on the target machine.
175
+
176
+ Finally any config files included in `executable_config_files` will be marked as executable.
177
+
178
+ This task will also automatically invoke the following tasks:
179
+
180
+ * `nginx:remove_default_vhost`
181
+ * `nginx:reload`
182
+ * `monit:restart`
183
+
184
+ To ensure configuration file changes are picked up correctly.
185
+
186
+ The defaults are:
187
+
188
+ Config Files:
189
+
190
+ ``` ruby
191
+ set(
192
+ :config_files,
193
+ %w(
194
+ nginx.conf
195
+ database.example.yml
196
+ log_rotation
197
+ monit
198
+ unicorn.rb
199
+ unicorn_init.sh
200
+ ))
201
+ ```
202
+
203
+ Symlinks:
204
+
205
+ ```ruby
206
+ set(
207
+ :symlinks,
208
+ [
209
+ {
210
+ source: "nginx.conf",
211
+ link: "/etc/nginx/sites-enabled/{{full_app_name}}"
212
+ },
213
+ {
214
+ source: "unicorn_init.sh",
215
+ link: "/etc/init.d/unicorn_{{full_app_name}}"
216
+ },
217
+ {
218
+ source: "log_rotation",
219
+ link: "/etc/logrotate.d/{{full_app_name}}"
220
+ },
221
+ {
222
+ source: "monit",
223
+ link: "/etc/monit/conf.d/{{full_app_name}}.conf"
224
+ }
225
+ ]
226
+ )
227
+ ```
228
+
229
+ Executable Config Files:
230
+
231
+ ```ruby
232
+ set(
233
+ :executable_config_files,
234
+ w(
235
+ unicorn_init.sh
236
+ )
237
+ )
238
+ ```
239
+
240
+ ## Contributing
241
+
242
+ 1. Fork it ( http://github.com/<my-github-username>/capistrano-cookbook/fork )
243
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
244
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
245
+ 4. Push to the branch (`git push origin my-new-feature`)
246
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capistrano/cookbook/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "capistrano-cookbook"
8
+ spec.version = Capistrano::Cookbook::VERSION
9
+ spec.authors = ["Ben Dixon"]
10
+ spec.email = ["ben@talkingquickly.co.uk"]
11
+ spec.summary = %q{Selection of Capistrano 3 tasks to reduce boilerplate required when deploying Rails and Sinatra applications}
12
+ spec.homepage = "https://github.com/TalkingQuickly/capistrano-cookbook"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_runtime_dependency "capistrano", ['~> 3.1', '> 3.1.0']
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.5"
23
+ spec.add_development_dependency "rake"
24
+ end
Binary file
Binary file
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/check_revision.cap",File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/compile_assets_locally.cap", File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/create_database.cap", File.dirname(__FILE__))
@@ -0,0 +1,57 @@
1
+ module Capistrano
2
+ module Cookbook
3
+ class SetupConfigValues
4
+ def symlinks
5
+ fetch(:symlinks) || symlinks_defaults
6
+ end
7
+
8
+ def executable_config_files
9
+ fetch(:executable_config_files) || executable_config_files_defaults
10
+ end
11
+
12
+ def config_files
13
+ fetch(:config_files) || config_files_defaults
14
+ end
15
+
16
+ private
17
+
18
+ def symlinks_defaults
19
+ [
20
+ {
21
+ source: "nginx.conf",
22
+ link: "/etc/nginx/sites-enabled/{{full_app_name}}"
23
+ },
24
+ {
25
+ source: "unicorn_init.sh",
26
+ link: "/etc/init.d/unicorn_{{full_app_name}}"
27
+ },
28
+ {
29
+ source: "log_rotation",
30
+ link: "/etc/logrotate.d/{{full_app_name}}"
31
+ },
32
+ {
33
+ source: "monit",
34
+ link: "/etc/monit/conf.d/{{full_app_name}}.conf"
35
+ }
36
+ ]
37
+ end
38
+
39
+ def executable_config_files_defaults
40
+ %w(
41
+ unicorn_init.sh
42
+ )
43
+ end
44
+
45
+ def config_files_defaults
46
+ %w(
47
+ nginx.conf
48
+ database.example.yml
49
+ log_rotation
50
+ monit
51
+ unicorn.rb
52
+ unicorn_init.sh
53
+ )
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,12 @@
1
+ # we often want to refer to variables which
2
+ # are defined in subsequent stage files. This
3
+ # let's us use the {{var}} to represent fetch(:var)
4
+ # in strings which are only evaluated at runtime.
5
+
6
+ def sub_strings(input_string)
7
+ output_string = input_string
8
+ input_string.scan(/{{(\w*)}}/).each do |var|
9
+ output_string.gsub!("{{#{var[0]}}}", fetch(var[0].to_sym))
10
+ end
11
+ output_string
12
+ end
@@ -0,0 +1,35 @@
1
+ # will first try and copy the file:
2
+ # config/deploy/#{full_app_name}/#{from}.erb
3
+ # to:
4
+ # shared/config/to
5
+ # if the original source path doesn exist then it will
6
+ # search in:
7
+ # config/deploy/shared/#{from}.erb
8
+ # otherwise it will search in the gems template directory
9
+ # this allows files which are common to all enviros to
10
+ # come from a single source while allowing specific
11
+ # ones to be over-ridden
12
+ # if the target file name is the same as the source then
13
+ # the second parameter can be left out
14
+ def smart_template(from, to=nil)
15
+ to ||= from
16
+ full_to_path = "#{shared_path}/config/#{to}"
17
+ if from_erb_path = template_file(from)
18
+ from_erb = StringIO.new(ERB.new(File.read(from_erb_path)).result(binding))
19
+ upload! from_erb, full_to_path
20
+ info "copying: #{from_erb} to: #{full_to_path}"
21
+ else
22
+ error "error #{from} not found"
23
+ end
24
+ end
25
+
26
+ def template_file(name)
27
+ if File.exist?((file = "config/deploy/#{fetch(:full_app_name)}/#{name}.erb"))
28
+ return file
29
+ elsif File.exist?((file = "config/deploy/shared/#{name}.erb"))
30
+ return file
31
+ elsif File.exist?(file = File.expand_path("../templates/#{name}.erb",File.dirname(__FILE__)))
32
+ return file
33
+ end
34
+ return nil
35
+ end
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/logs.cap", File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/monit.cap", File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/nginx.cap",File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/restart.cap", File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/run_tests.cap", File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/setup_config.cap", File.dirname(__FILE__))
@@ -0,0 +1,14 @@
1
+ namespace :deploy do
2
+ desc "checks whether the currently checkout out revision matches the
3
+ remote one we're trying to deploy from"
4
+ task :check_revision do
5
+ branch = fetch(:branch)
6
+ unless `git rev-parse HEAD` == `git rev-parse origin/#{branch}`
7
+ puts "WARNING: HEAD is not the same as origin/#{branch}"
8
+ puts "Run `git push` to sync changes or make sure you've"
9
+ puts "checked out the branch: #{branch} as you can only deploy"
10
+ puts "if you've got the target branch checked out"
11
+ exit
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ namespace :deploy do
2
+ desc "compiles assets locally then rsyncs"
3
+ task :compile_assets_locally do
4
+ run_locally do
5
+ execute "RAILS_ENV=#{fetch(:rails_env)} bundle exec rake assets:precompile"
6
+ end
7
+ on roles(:app) do |role|
8
+ run_locally do
9
+ execute"rsync -av ./public/assets/ #{role.user}@#{role.hostname}:#{release_path}/public/assets/;"
10
+ end
11
+ end
12
+ run_locally do
13
+ execute "rm -rf ./public/assets"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ # Inspired by https://gist.github.com/dv/10370719
2
+
3
+ namespace :database do
4
+ desc "fetches the remote database.yml and creates the user and database specified in it currently postgres only. Will only work if your db server also has your rails app on it."
5
+ task :create do
6
+ on primary(:db) do |host|
7
+ unless test("[ -f #{shared_path}/config/database.yml ]")
8
+ execute "cp #{shared_path}/config/database.example.yml #{shared_path}/config/database.yml"
9
+ end
10
+ system("scp #{fetch(:deploy_user)}@#{host}:#{shared_path}/config/database.yml db.tmp.yml")
11
+ yaml = YAML.load_file("db.tmp.yml")
12
+ system("rm db.tmp.yml")
13
+ puts yaml
14
+ puts fetch(:rails_env)
15
+ database_config = yaml[fetch(:rails_env).to_s]
16
+
17
+ if test %Q{sudo -u postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='#{database_config["username"]}';" | grep -q 1}
18
+ info "Role #{database_config['username']} already exists"
19
+ else
20
+ execute %Q{sudo -u postgres psql -c "create user #{database_config["username"]} with password '#{database_config["password"]}';"}
21
+ end
22
+
23
+ # Create the database
24
+ if test %Q{sudo -u postgres psql -lqt | cut -d \\| -f 1 | grep -wq #{database_config["database"]}}
25
+ info "Database #{database_config['database']} already exists"
26
+ else
27
+ execute %Q{sudo -u postgres psql -c "create database #{database_config["database"]};"}
28
+ execute %Q{sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE #{database_config["database"]} to #{database_config["username"]};"}
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,14 @@
1
+ namespace :logs do
2
+ task :tail, :file do |t, args|
3
+ if args[:file]
4
+ on roles(:app) do
5
+ execute "tail -f #{shared_path}/log/#{args[:file]}.log"
6
+ end
7
+ else
8
+ puts "please specify a logfile e.g: 'rake logs:tail[logfile]"
9
+ puts "will tail 'shared_path/log/logfile.log'"
10
+ puts "remember if you use zsh you'll need to format it as:"
11
+ puts "rake 'logs:tail[logfile]' (single quotes)"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ namespace :monit do
2
+ %w(start stop restart).each do |task_name|
3
+ desc "#{task_name} Monit"
4
+ task task_name do
5
+ on roles(:app), in: :sequence, wait: 5 do
6
+ sudo "service monit #{task_name}"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ namespace :nginx do
2
+ %w(start stop restart reload).each do |task_name|
3
+ desc "#{task } Nginx"
4
+ task task_name do
5
+ on roles(:app), in: :sequence, wait: 5 do
6
+ sudo "/etc/init.d/nginx #{task_name}"
7
+ end
8
+ end
9
+ end
10
+
11
+ desc "Remove default Nginx Virtual Host"
12
+ task "remove_default_vhost" do
13
+ on roles(:app) do
14
+ if test("[ -f /etc/nginx/sites-enabled/default ]")
15
+ sudo "rm /etc/nginx/sites-enabled/default"
16
+ puts "removed default Nginx Virtualhost"
17
+ else
18
+ puts "No default Nginx Virtualhost to remove"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ namespace :deploy do
2
+ desc 'Commands for unicorn application'
3
+ %w(start stop force-stop restart upgrade reopen-logs).each do |command|
4
+ task command.to_sym do
5
+ on roles(:app), in: :sequence, wait: 5 do
6
+ sudo "/etc/init.d/unicorn_#{fetch(:full_app_name)} #{command}"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ namespace :deploy do
2
+ desc "Runs test before deploying, can't deploy unless they pass"
3
+ task :run_tests do
4
+ test_log = "log/capistrano.test.log"
5
+ tests = fetch(:tests)
6
+ tests.each do |test|
7
+ puts "--> Running tests: '#{test}', please wait ..."
8
+ unless system "bundle exec rspec #{test} > #{test_log} 2>&1"
9
+ puts "--> Tests: '#{test}' failed. Results in: #{test_log} and below:"
10
+ system "cat #{test_log}"
11
+ exit;
12
+ end
13
+ puts "--> '#{test}' passed"
14
+ end
15
+ puts "--> All tests passed"
16
+ system "rm #{test_log}"
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ require 'capistrano/cookbook/helpers/setup_config_values'
2
+ require 'capistrano/cookbook/helpers/substitute_strings'
3
+ require 'capistrano/cookbook/helpers/template'
4
+ require 'capistrano/cookbook/nginx'
5
+ require 'capistrano/cookbook/monit'
6
+ require 'securerandom'
7
+
8
+ namespace :deploy do
9
+ task :setup_config do
10
+ conf = ::Capistrano::Cookbook::SetupConfigValues.new
11
+ on roles(:app) do
12
+ # make the config dir
13
+ execute :mkdir, "-p #{shared_path}/config"
14
+ full_app_name = fetch(:full_app_name)
15
+
16
+ # config files to be uploaded to shared/config, see the
17
+ # definition of smart_template for details of operation.
18
+ conf.config_files.each do |file|
19
+ smart_template file
20
+ end
21
+
22
+ # which of the above files should be marked as executable
23
+ conf.executable_config_files.each do |file|
24
+ execute :chmod, "+x #{shared_path}/config/#{file}"
25
+ end
26
+
27
+ # symlink stuff which should be... symlinked
28
+ conf.symlinks.each do |symlink|
29
+ sudo "ln -nfs #{shared_path}/config/#{symlink[:source]} #{sub_strings(symlink[:link])}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ # remove the default nginx configuration as it will tend
36
+ # to conflict with our configs.
37
+ before 'deploy:setup_config', 'nginx:remove_default_vhost'
38
+
39
+ # reload nginx to it will pick up any modified vhosts from
40
+ # setup_config
41
+ after 'deploy:setup_config', 'nginx:reload'
42
+
43
+ # Restart monit so it will pick up any monit configurations
44
+ # we've added
45
+ after 'deploy:setup_config', 'monit:restart'
@@ -0,0 +1,11 @@
1
+ <%= fetch(:rails_env) %>:
2
+ adapter: postgresql
3
+ timeout: 5000
4
+ encoding: utf8
5
+ reconnect: false
6
+ database: <%= "#{fetch(:application)}_#{fetch(:rails_env)}" %>
7
+ pool: 5
8
+ username: <%= "#{fetch(:application)}_#{fetch(:rails_env)}" %>
9
+ password: <%= SecureRandom.hex(12) %>
10
+ host: 127.0.0.1
11
+ port: 5432
@@ -0,0 +1,11 @@
1
+ <%= fetch(:deploy_to) %>/shared/log/*.log {
2
+ daily
3
+ missingok
4
+ rotate 52
5
+ compress
6
+ delaycompress
7
+ notifempty
8
+ sharedscripts
9
+ endscript
10
+ copytruncate
11
+ }
@@ -0,0 +1,69 @@
1
+ <%= fetch(:rails_env) %>:
2
+ # Configure available database sessions. (required)
3
+ sessions:
4
+ # Defines the default session. (required)
5
+ default:
6
+ # Defines the name of the default database that Mongoid can connect to.
7
+ # (required).
8
+ database: <%= "#{fetch(:applocation)}_#{fetch(:rails_env)}" %>
9
+ # Provides the hosts the default session can connect to. Must be an array
10
+ # of host:port pairs. (required)
11
+ hosts:
12
+ - localhost
13
+ options:
14
+ # Change whether the session persists in safe mode by default.
15
+ # (default: false)
16
+ safe: true
17
+
18
+ # Change the default consistency model to :eventual or :strong.
19
+ # :eventual will send reads to secondaries, :strong sends everything
20
+ # to master. (default: :eventual)
21
+ # consistency: :eventual
22
+
23
+ # How many times Moped should attempt to retry an operation after
24
+ # failure. (default: 30)
25
+ # max_retries: 30
26
+
27
+ # The time in seconds that Moped should wait before retrying an
28
+ # operation on failure. (default: 1)
29
+ # retry_interval: 1
30
+ # Configure Mongoid specific options. (optional)
31
+ options:
32
+ # Configuration for whether or not to allow access to fields that do
33
+ # not have a field definition on the model. (default: true)
34
+ # allow_dynamic_fields: true
35
+
36
+ # Enable the identity map, needed for eager loading. (default: false)
37
+ identity_map_enabled: true
38
+
39
+ # Includes the root model name in json serialization. (default: false)
40
+ # include_root_in_json: false
41
+
42
+ # Include the _type field in serializaion. (default: false)
43
+ # include_type_for_serialization: false
44
+
45
+ # Preload all models in development, needed when models use
46
+ # inheritance. (default: false)
47
+ # preload_models: false
48
+
49
+ # Protect id and type from mass assignment. (default: true)
50
+ # protect_sensitive_fields: true
51
+
52
+ # Raise an error when performing a #find and the document is not found.
53
+ # (default: true)
54
+ # raise_not_found_error: true
55
+
56
+ # Raise an error when defining a scope with the same name as an
57
+ # existing method. (default: false)
58
+ # scope_overwrite_exception: false
59
+
60
+ # Skip the database version check, used when connecting to a db without
61
+ # admin access. (default: false)
62
+ # skip_version_check: false
63
+
64
+ # User Active Support's time zone in conversions. (default: true)
65
+
66
+ # Ensure all times are UTC in the app side. (default: false)
67
+ use_utc: true
68
+
69
+
@@ -0,0 +1,22 @@
1
+ <% application = fetch(:application) %>
2
+ set mail-format { subject: <%= "#{fetch(:full_app_name)} - #{fetch(:rails_env)}" %> $SERVICE $EVENT at $DATE }
3
+
4
+ check process unicorn
5
+ with pidfile <%= current_path %>/tmp/pids/unicorn.pid
6
+ start program = "/etc/init.d/unicorn_<%= application %>_<%= fetch(:rails_env)%> start"
7
+ stop program = "/etc/init.d/unicorn_<%= application %>_<%= fetch(:rails_env)%> stop"
8
+ if mem is greater than 300.0 MB for 1 cycles then restart # eating up memory?
9
+ if cpu is greater than 50% for 2 cycles then alert # send an email to admin
10
+ if cpu is greater than 80% for 30 cycles then restart # hung process?
11
+ group unicorn
12
+
13
+ <% (0..(fetch(:unicorn_worker_count) -1)).each do |worker| %>
14
+ check process unicorn_worker_<%= (5000 + worker).to_s %>
15
+ with pidfile <%= current_path %>/tmp/pids/unicorn.<%= (5000 + worker).to_s %>.pid
16
+ start program = "/bin/true"
17
+ stop program = "/etc/init.d/unicorn_<%= application %>_<%= fetch(:rails_env)%> kill_worker <%= (5000 + worker).to_s %>"
18
+ if mem is greater than 350.0 MB for 1 cycles then restart
19
+ if cpu is greater than 80% for 30 cycles then restart
20
+
21
+ group unicorn_workers
22
+ <% end %>
@@ -0,0 +1,57 @@
1
+ upstream unicorn {
2
+ server unix:/tmp/unicorn.<%= fetch(:full_app_name) %>.sock fail_timeout=0;
3
+ }
4
+
5
+ server {
6
+ server_name <%= fetch(:server_name) %>;
7
+ listen 80;
8
+ root <%= fetch(:deploy_to) %>/current/public;
9
+
10
+ location ^~ /assets/ {
11
+ gzip_static on;
12
+ expires max;
13
+ add_header Cache-Control public;
14
+ }
15
+
16
+ try_files $uri/index.html $uri @unicorn;
17
+ location @unicorn {
18
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
19
+ proxy_set_header Host $http_host;
20
+ proxy_redirect off;
21
+ proxy_pass http://unicorn;
22
+ }
23
+
24
+ error_page 500 502 503 504 /500.html;
25
+ client_max_body_size 4G;
26
+ keepalive_timeout 10;
27
+ }
28
+
29
+ <% if fetch(:enable_ssl) %>
30
+ server {
31
+ server_name <%= fetch(:server_name) %>;
32
+ listen 443;
33
+ root <%= fetch(:deploy_to) %>/current/public;
34
+
35
+ location ^~ /assets/ {
36
+ gzip_static on;
37
+ expires max;
38
+ add_header Cache-Control public;
39
+ }
40
+
41
+ try_files $uri/index.html $uri @unicorn;
42
+ location @unicorn {
43
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
44
+ proxy_set_header X-Forwarded-Proto https;
45
+ proxy_set_header Host $http_host;
46
+ proxy_redirect off;
47
+ proxy_pass http://unicorn;
48
+ }
49
+
50
+ error_page 500 502 503 504 /500.html;
51
+ client_max_body_size 4G;
52
+ keepalive_timeout 10;
53
+ ssl on;
54
+ ssl_certificate <%= fetch(:deploy_to) %>/shared/ssl_cert.crt;
55
+ ssl_certificate_key <%= fetch(:deploy_to) %>/shared/ssl_private_key.key;
56
+ }#
57
+ <% end %>
@@ -0,0 +1,2 @@
1
+ <%= fetch(:rails_env) %>:
2
+ concurrency: 5
@@ -0,0 +1,40 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ APP_ROOT=<%= current_path %>
5
+ PID=$APP_ROOT/tmp/pids/sidekiq.pid
6
+ CMD="cd $APP_ROOT; RAILS_ENV=<%= "#{fetch(:rails_env)}" %> nohup bundle exec sidekiq -e <%= "#{fetch(:rails_env)}" %> -C <%= current_path %>/config/sidekiq.yml -i 0 -P $PID >> <%= current_path %>/log/sidekiq.log 2>&1 &"
7
+ AS_USER="deploy"
8
+
9
+ run () {
10
+ if [ "$(id -un)" = "$AS_USER" ]; then
11
+ eval $1
12
+ else
13
+ su -c "$1" - $AS_USER
14
+ fi
15
+ }
16
+
17
+ sig () {
18
+ test -s "$PID" && kill -$1 `cat $PID`
19
+ }
20
+
21
+ case "$1" in
22
+ start)
23
+ sig 0 && echo >&2 "Already Running" && exit 0
24
+ run "$CMD"
25
+ ;;
26
+ stop)
27
+ if kill -0 `cat $PID`
28
+ then
29
+ cd $APP_ROOT
30
+ bundle exec sidekiqctl stop $APP_ROOT/tmp/pids/sidekiq.pid 10
31
+ echo "stopping...."
32
+ else
33
+ echo "not running"
34
+ fi
35
+ ;;
36
+ *)
37
+ echo >&2 "Usage: $0 <start|stop>"
38
+ exit 1
39
+ ;;
40
+ esac
@@ -0,0 +1,41 @@
1
+ root = "<%= current_path %>"
2
+ working_directory root
3
+ pid "#{root}/tmp/pids/unicorn.pid"
4
+ stderr_path "#{root}/log/unicorn.log"
5
+ stdout_path "#{root}/log/unicorn.log"
6
+
7
+ listen "/tmp/unicorn.<%= fetch(:full_app_name) %>.sock"
8
+ worker_processes <%= fetch(:unicorn_worker_count) %>
9
+ timeout 40
10
+ preload_app true
11
+
12
+ # Force unicorn to look at the Gemfile in the current_path
13
+ # otherwise once we've first started a master process, it
14
+ # will always point to the first one it started.
15
+ before_exec do |server|
16
+ ENV['BUNDLE_GEMFILE'] = "<%= current_path %>/Gemfile"
17
+ end
18
+
19
+ before_fork do |server, worker|
20
+ defined?(ActiveRecord::Base) and
21
+ ActiveRecord::Base.connection.disconnect!
22
+ # Quit the old unicorn process
23
+ old_pid = "#{server.config[:pid]}.oldbin"
24
+ if File.exists?(old_pid) && server.pid != old_pid
25
+ puts "We've got an old pid and server pid is not the old pid"
26
+ begin
27
+ Process.kill("QUIT", File.read(old_pid).to_i)
28
+ puts "killing master process (good thing tm)"
29
+ rescue Errno::ENOENT, Errno::ESRCH
30
+ puts "unicorn master already killed"
31
+ end
32
+ end
33
+ end
34
+
35
+ after_fork do |server, worker|
36
+ port = 5000 + worker.nr
37
+ child_pid = server.config[:pid].sub('.pid', ".#{port}.pid")
38
+ system("echo #{Process.pid} > #{child_pid}")
39
+ defined?(ActiveRecord::Base) and
40
+ ActiveRecord::Base.establish_connection
41
+ end
@@ -0,0 +1,86 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ # Feel free to change any of the following variables for your app:
5
+ TIMEOUT=${TIMEOUT-60}
6
+ APP_ROOT=<%= current_path %>
7
+ PID_DIR=$APP_ROOT/tmp/pids
8
+ PID=$PID_DIR/unicorn.pid
9
+ CMD="cd $APP_ROOT; bundle exec unicorn -D -c <%= "#{shared_path}/config/unicorn.rb" %> -E <%= fetch(:rails_env) %>"
10
+ AS_USER=deploy
11
+ set -u
12
+
13
+ OLD_PIN="$PID.oldbin"
14
+
15
+ sig () {
16
+ test -s "$PID" && kill -$1 `cat $PID`
17
+ }
18
+
19
+ oldsig () {
20
+ test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
21
+ }
22
+
23
+ workersig () {
24
+ workerpid="$APP_ROOT/tmp/pids/unicorn.$2.pid"
25
+
26
+ test -s "$workerpid" && kill -$1 `cat $workerpid`
27
+ }
28
+
29
+ run () {
30
+ if [ "$(id -un)" = "$AS_USER" ]; then
31
+ eval $1
32
+ else
33
+ su -c "$1" - $AS_USER
34
+ fi
35
+ }
36
+
37
+ case "$1" in
38
+ start)
39
+ sig 0 && echo >&2 "Already running" && exit 0
40
+ run "$CMD"
41
+ ;;
42
+ stop)
43
+ sig QUIT && exit 0
44
+ echo >&2 "Not running"
45
+ ;;
46
+ force-stop)
47
+ sig TERM && exit 0
48
+ echo >&2 "Not running"
49
+ ;;
50
+ kill_worker)
51
+ workersig QUIT $2 && exit 0
52
+ echo >&2 "Worker not running"
53
+ ;;
54
+ restart|reload)
55
+ sig USR2 && echo reloaded OK && exit 0
56
+ echo >&2 "Couldn't reload, starting '$CMD' instead"
57
+ run "$CMD"
58
+ ;;
59
+ upgrade)
60
+ if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
61
+ then
62
+ n=$TIMEOUT
63
+ while test -s $OLD_PIN && test $n -ge 0
64
+ do
65
+ printf '.' && sleep 1 && n=$(( $n - 1 ))
66
+ done
67
+ echo
68
+
69
+ if test $n -lt 0 && test -s $OLD_PIN
70
+ then
71
+ echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
72
+ exit 1
73
+ fi
74
+ exit 0
75
+ fi
76
+ echo >&2 "Couldn't upgrade, starting '$CMD' instead"
77
+ run "$CMD"
78
+ ;;
79
+ reopen-logs)
80
+ sig USR1
81
+ ;;
82
+ *)
83
+ echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
84
+ exit 1
85
+ ;;
86
+ esac
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module Cookbook
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ require "capistrano/cookbook/version"
2
+
3
+ module Capistrano
4
+ module Cookbook
5
+ require 'capistrano/cookbook/check_revision'
6
+ require 'capistrano/cookbook/compile_assets_locally'
7
+ require 'capistrano/cookbook/logs'
8
+ require 'capistrano/cookbook/monit'
9
+ require 'capistrano/cookbook/nginx'
10
+ require 'capistrano/cookbook/restart'
11
+ require 'capistrano/cookbook/run_tests'
12
+ require 'capistrano/cookbook/setup_config'
13
+ require 'capistrano/cookbook/create_database'
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-cookbook
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Ben Dixon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capistrano
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ - - ">"
21
+ - !ruby/object:Gem::Version
22
+ version: 3.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ - - ">"
31
+ - !ruby/object:Gem::Version
32
+ version: 3.1.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.5'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ description:
62
+ email:
63
+ - ben@talkingquickly.co.uk
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - ".gitignore"
69
+ - Gemfile
70
+ - LICENSE.txt
71
+ - README.md
72
+ - Rakefile
73
+ - capistrano-cookbook.gemspec
74
+ - lib/capistrano/.DS_Store
75
+ - lib/capistrano/cookbook.rb
76
+ - lib/capistrano/cookbook/.DS_Store
77
+ - lib/capistrano/cookbook/check_revision.rb
78
+ - lib/capistrano/cookbook/compile_assets_locally.rb
79
+ - lib/capistrano/cookbook/create_database.rb
80
+ - lib/capistrano/cookbook/helpers/setup_config_values.rb
81
+ - lib/capistrano/cookbook/helpers/substitute_strings.rb
82
+ - lib/capistrano/cookbook/helpers/template.rb
83
+ - lib/capistrano/cookbook/logs.rb
84
+ - lib/capistrano/cookbook/monit.rb
85
+ - lib/capistrano/cookbook/nginx.rb
86
+ - lib/capistrano/cookbook/restart.rb
87
+ - lib/capistrano/cookbook/run_tests.rb
88
+ - lib/capistrano/cookbook/setup_config.rb
89
+ - lib/capistrano/cookbook/tasks/check_revision.cap
90
+ - lib/capistrano/cookbook/tasks/compile_assets_locally.cap
91
+ - lib/capistrano/cookbook/tasks/create_database.cap
92
+ - lib/capistrano/cookbook/tasks/logs.cap
93
+ - lib/capistrano/cookbook/tasks/monit.cap
94
+ - lib/capistrano/cookbook/tasks/nginx.cap
95
+ - lib/capistrano/cookbook/tasks/restart.cap
96
+ - lib/capistrano/cookbook/tasks/run_tests.cap
97
+ - lib/capistrano/cookbook/tasks/setup_config.cap
98
+ - lib/capistrano/cookbook/templates/database.example.yml.erb
99
+ - lib/capistrano/cookbook/templates/log_rotation.erb
100
+ - lib/capistrano/cookbook/templates/mongoid.example.yml.erb
101
+ - lib/capistrano/cookbook/templates/monit.erb
102
+ - lib/capistrano/cookbook/templates/nginx.conf.erb
103
+ - lib/capistrano/cookbook/templates/sidekiq.yml.erb
104
+ - lib/capistrano/cookbook/templates/sidekiq_init.sh.erb
105
+ - lib/capistrano/cookbook/templates/unicorn.rb.erb
106
+ - lib/capistrano/cookbook/templates/unicorn_init.sh.erb
107
+ - lib/capistrano/cookbook/version.rb
108
+ homepage: https://github.com/TalkingQuickly/capistrano-cookbook
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.2.2
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Selection of Capistrano 3 tasks to reduce boilerplate required when deploying
132
+ Rails and Sinatra applications
133
+ test_files: []
134
+ has_rdoc: