capistrano-unicorn-sic 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8091b3b6283213655531467af348b2559f93a0fa
4
+ data.tar.gz: 2cf9717de5125c0c81af464b93fe7a4bd78dfa0a
5
+ SHA512:
6
+ metadata.gz: fa9cde766ec7c9eef970fcd877489d5c63a69ba85f05bad4ce816f86f1ad37054ff804b5ea53b9a970b2a9b37c5338170a920540a0ad623b97df003d9d5b1c30
7
+ data.tar.gz: c66ff4d5b531c2768b92f1627fa06b027ee5ed4db1cb0255cc2761842574c82cf3f174aeb969b8bb0a3316e3848fd398b69082c10b86c8f00c847ab326cb58ca
data/.gitignore ADDED
@@ -0,0 +1,41 @@
1
+ !.gitignore
2
+ *.gem
3
+ *.rbc
4
+ *.sw[a-p]
5
+ *.tmproj
6
+ *.tmproject
7
+ *.un~
8
+ *~
9
+ .DS_Store
10
+ .Spotlight-V100
11
+ .Trashes
12
+ ._*
13
+ .bundle
14
+ .config
15
+ .directory
16
+ .elc
17
+ .redcar
18
+ .yardoc
19
+ /.emacs.desktop
20
+ /.emacs.desktop.lock
21
+ Desktop.ini
22
+ Gemfile.lock
23
+ Icon?
24
+ InstalledFiles
25
+ Session.vim
26
+ Thumbs.db
27
+ \#*\#
28
+ _yardoc
29
+ auto-save-list
30
+ coverage
31
+ doc/
32
+ lib/bundler/man
33
+ pkg
34
+ pkg/*
35
+ rdoc
36
+ spec/reports
37
+ test/tmp
38
+ test/version_tmp
39
+ tmp
40
+ tmtags
41
+ tramp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=documentation
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rspec'
7
+ gem 'capistrano-spec'
8
+ gem 'pry-debugger'
9
+ end
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2011-2013 Dan Sosedoff.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to
8
+ do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/NEWS.md ADDED
@@ -0,0 +1,27 @@
1
+ # Capistrano Unicorn NEWS
2
+
3
+ ## 0.2.0
4
+
5
+ Significant changes since 0.1.10 are as follows. Backwards-incompatible changes are **in bold**.
6
+
7
+ * Ensured `RAILS_ENV` is set correctly.
8
+ * Embedded multistage docs directly within the [README](README.md) (the wiki page was version-specific and misleading).
9
+ * Significantly tidied up the usage and documentation of configuration variables:
10
+ * **In most cases, it should now be sufficient to simply set `rails_env` correctly,
11
+ and other variables should assume the correct value by default.**
12
+ * **Make `unicorn_env` default to `rails_env` or `'production'`.**
13
+ * **Rename `app_env` to `unicorn_rack_env` and fix default value.**
14
+ * Add `unicorn_options` variable which allows passing of arbitrary options to unicorn.
15
+ * Added `app_subdir` to support app running in a subdirectory.
16
+ * Updated documentation in [README](README.md) to fix inaccuracies and ambiguities.
17
+ * `unicorn_pid` defaults to attempting to auto-detect from unicorn config file.
18
+ This avoids having to keep two paths in sync.
19
+ https://github.com/sosedoff/capistrano-unicorn/issues/7
20
+ * Also added the `unicorn:show_vars` task to make it easier to debug
21
+ config variable values client-side.
22
+ * Defer calculation of `unicorn-roles`.
23
+
24
+ It was noticed that there are a
25
+ [huge number of unmerged forks on github](https://github.com/sosedoff/capistrano-unicorn/issues/45),
26
+ so we also updated the [README](README.md) asking the community to
27
+ contribute back any useful changes they make.
data/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # Capistrano Unicorn
2
+
3
+ Capistrano 3.x plugin that integrates Unicorn tasks into capistrano deployment script.
4
+ Taken from https://github.com/sosedoff/capistrano-unicorn and adapted to work with Capistrano 3.x.
5
+
6
+ **Note: this code is not well tested, if anything fails, please report it. Use at your own risk.**
7
+
8
+ **Developers:** Please consider contributing your forked changes, or opening an
9
+ issue if there is no existing relevant one. There are a lot of forks--we'd love
10
+ to reabsorb some of the issues/solutions the community has encountered.
11
+
12
+ [![Gem Version](https://badge.fury.io/rb/sepastian-capistrano3-unicorn.png)](http://badge.fury.io/rb/sepastian-capistrano3-unicorn)
13
+
14
+ ## Usage
15
+
16
+ If you are upgrading from a previous version, please see the [NEWS file](NEWS.md).
17
+
18
+ ### Setup
19
+
20
+ Add the library to your `Gemfile`:
21
+
22
+ ```ruby
23
+ group :development do
24
+ gem 'sepastian-capistrano3-unicorn', :require => false
25
+ end
26
+ ```
27
+
28
+ And load it into your deployment script `config/deploy.rb`:
29
+
30
+ ```ruby
31
+ require 'capistrano/unicorn'
32
+ ```
33
+
34
+ Add unicorn restart task hook:
35
+
36
+ ```ruby
37
+ after 'deploy:restart', 'unicorn:reload' # app IS NOT preloaded
38
+ after 'deploy:restart', 'unicorn:restart' # app preloaded
39
+ after 'deploy:restart', 'unicorn:duplicate' # before_fork hook implemented (zero downtime deployments)
40
+ ```
41
+
42
+ Create a new configuration file `config/unicorn.rb` or `config/unicorn/STAGE.rb`,
43
+ where stage is your deployment environment.
44
+
45
+ Example config - [examples/rails3.rb](https://github.com/sosedoff/capistrano-unicorn/blob/master/examples/rails3.rb).
46
+ Please refer to Unicorn documentation for more examples and configuration options.
47
+
48
+ ### Deploy
49
+
50
+ First, make sure you're running the latest release:
51
+
52
+ ```
53
+ cap deploy
54
+ ```
55
+
56
+ Then you can test each individual task:
57
+
58
+ ```
59
+ cap unicorn:start
60
+ cap unicorn:stop
61
+ cap unicorn:reload
62
+ ```
63
+
64
+ ## Configuration
65
+
66
+ You can modify any of the following Capistrano variables in your `deploy.rb` config.
67
+ You can use the `unicorn:show_vars` task to check that the values you have specified
68
+ are set correctly.
69
+
70
+ ### Environment parameters
71
+
72
+ - `unicorn_env` - Set basename of unicorn config `.rb` file to be used loaded from `unicorn_config_path`. Defaults to `rails_env` variable if set, otherwise `production`.
73
+ - `unicorn_rack_env` - Set the value which will be passed to unicorn via [the `-E` parameter as the Rack environment](http://unicorn.bogomips.org/unicorn_1.html). Valid values are `development`, `deployment`, and `none`. Defaults to `development` if `rails_env` is `development`, otherwise `deployment`.
74
+
75
+ ### Execution parameters
76
+
77
+ - `unicorn_user` - Launch unicorn master as the specified user via `sudo`. Defaults to `nil`, which means no use of `sudo`, i.e. run as the user defined by the `user` variable.
78
+ - `unicorn_roles` - Define which roles to perform unicorn recipes on. Defaults to `:app`.
79
+ - `unicorn_bundle` - Set bundler command for unicorn. Defaults to `bundle`.
80
+ - `unicorn_bin` - Set unicorn executable file. Defaults to `unicorn`.
81
+ - `unicorn_options` - Set any additional options to be passed to unicorn on startup.
82
+ - `unicorn_restart_sleep_time` - Number of seconds to wait for (old) pidfile to show up when restarting unicorn. Defaults to 2.
83
+
84
+ ### Relative path parameters
85
+
86
+ - `app_subdir` - If your app lives in a subdirectory 'rails' (say) of your repository, set this to `/rails` (the leading slash is required).
87
+ - `unicorn_config_rel_path` - Set the directory path (relative to `app_path` - see below) where unicorn config files reside. Defaults to `config`.
88
+ - `unicorn_config_filename` - Set the filename of the unicorn config file loaded from `unicorn_config_path`. Should not be present in multistage installations. Defaults to `unicorn.rb`.
89
+
90
+ ### Absolute path parameters
91
+
92
+ - `app_path` - Set path to app root. Defaults to `current_path + app_subdir`.
93
+ - `unicorn_pid` - Set unicorn PID file path. By default, attempts to auto-detect from unicorn config file. On failure, falls back to value in `unicorn_default_pid`
94
+ - `unicorn_default_pid` - See above. Defaults to `#{current_path}/tmp/pids/unicorn.pid`
95
+ - `bundle_gemfile` - Set path to Gemfile. Defaults to `#{app_path}/Gemfile`
96
+ - `unicorn_config_path` - Set the directory where unicorn config files reside. Defaults to `#{current_path}/config`.
97
+
98
+ ### Zero Downtime Deployment Options
99
+
100
+ * `unicorn:restart`: :-1: This can sort of support it with a configurable timeout, which may not be reliable.
101
+ * `unicorn:reload`: :question: Can anyone testify to its zero-downtime support?
102
+ * `unicorn:duplicate`: :+1: If you install the Unicorn `before_fork` hook, then yes! See: https://github.com/sosedoff/capistrano-unicorn/issues/40#issuecomment-16011353
103
+
104
+ ## Available Tasks
105
+
106
+ To get a list of all capistrano tasks, run `cap -T`:
107
+
108
+ ```
109
+ cap unicorn:add_worker # Add a new worker
110
+ cap unicorn:remove_worker # Remove amount of workers
111
+ cap unicorn:reload # Reload Unicorn
112
+ cap unicorn:restart # Restart Unicorn
113
+ cap unicorn:show_vars # Debug Unicorn variables
114
+ cap unicorn:shutdown # Immediately shutdown Unicorn
115
+ cap unicorn:start # Start Unicorn master process
116
+ cap unicorn:stop # Stop Unicorn
117
+ ```
118
+
119
+ ## Tests
120
+
121
+ To execute test suite run:
122
+
123
+ ```
124
+ bundle exec rake test
125
+ ```
126
+
127
+ ### Multistage
128
+
129
+ The issue here is that capistrano loads default configuration and then
130
+ executes your staging task and overrides previously defined
131
+ variables. The default environment before executing your stage task is
132
+ set to `:production`, so it will use a wrong environment unless you
133
+ take steps to ensure that `:rails_env` and `:unicorn_env` are
134
+ set correctly.
135
+
136
+ Let's say you have a scenario involving two deployment stages: staging
137
+ and production. You’ll need to add `config/deploy/staging.rb` and
138
+ `config/deploy/production.rb` files. However, it makes sense to
139
+ adhere to DRY and avoid duplicating lines between the two files. So
140
+ it would be nicer to keep common settings in `config/deploy.rb`, and
141
+ only put stuff in each staging definition file which is really
142
+ specific to that staging environment. Fortunately this can be done
143
+ using the [lazy evaluation form of `set`](https://github.com/capistrano/capistrano/wiki/2.x-DSL-Configuration-Variables-Set).
144
+
145
+ So `config/deploy.rb` file would contain something like:
146
+
147
+ ```ruby
148
+ set :stages, %w(production staging)
149
+ set :default_stage, "staging"
150
+ require 'capistrano/ext/multistage'
151
+
152
+ role(:web) { domain }
153
+ role(:app) { domain }
154
+ role(:db, :primary => true) { domain }
155
+
156
+ set(:deploy_to) { "/home/#{user}/#{application}/#{fetch :rails_env}" }
157
+ set(:current_path) { File.join(deploy_to, current_dir) }
158
+ ```
159
+
160
+ Then `config/deploy/production.rb` would contain something like:
161
+
162
+ ```ruby
163
+ set :domain, "app.mydomain.com"
164
+ set :rails_env, "production"
165
+ ```
166
+
167
+ and `config/deploy/staging.rb` would only need to contain something like:
168
+
169
+ ```ruby
170
+ set :domain, "app.staging.mydomain.com"
171
+ set :rails_env, "staging"
172
+ ```
173
+
174
+ Nice and clean!
175
+
176
+ ## License
177
+
178
+ See LICENSE file for details.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+
6
+ RSpec::Core::RakeTask.new(:test) do |spec|
7
+ spec.pattern = "spec/**/*_spec.rb"
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/capistrano/unicorn/version", __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "capistrano-unicorn-sic"
6
+ spec.version = CapistranoUnicorn::VERSION.dup
7
+ spec.author = "Sebastian Gassner, Dan Sosedoff, Florian Schwab"
8
+ spec.email = "sebastian.gassner@gmail.com"
9
+ spec.homepage = "https://github.com/SICSoftwareGmbH/capistrano-unicorn"
10
+ spec.summary = %q{Unicorn integration for Capistrano 3.x}
11
+ spec.description = %q{Capistrano 3.x plugin that integrates Unicorn server tasks.}
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files`.split("\n")
15
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "rake"
20
+ spec.add_development_dependency "unicorn"
21
+ spec.add_runtime_dependency "capistrano", "~> 3.0.0"
22
+ end
@@ -0,0 +1,45 @@
1
+ # ------------------------------------------------------------------------------
2
+ # Sample rails 3 config
3
+ # ------------------------------------------------------------------------------
4
+
5
+ # Set your full path to application.
6
+ app_path = "/path/to/app"
7
+
8
+ # Set unicorn options
9
+ worker_processes 1
10
+ preload_app true
11
+ timeout 180
12
+ listen "127.0.0.1:9000"
13
+
14
+ # Spawn unicorn master worker for user apps (group: apps)
15
+ user 'apps', 'apps'
16
+
17
+ # Fill path to your app
18
+ working_directory app_path
19
+
20
+ # Should be 'production' by default, otherwise use other env
21
+ rails_env = ENV['RAILS_ENV'] || 'production'
22
+
23
+ # Log everything to one file
24
+ stderr_path "log/unicorn.log"
25
+ stdout_path "log/unicorn.log"
26
+
27
+ # Set master PID location
28
+ pid "#{app_path}/tmp/pids/unicorn.pid"
29
+
30
+ before_fork do |server, worker|
31
+ ActiveRecord::Base.connection.disconnect!
32
+
33
+ old_pid = "#{server.config[:pid]}.oldbin"
34
+ if File.exists?(old_pid) && server.pid != old_pid
35
+ begin
36
+ Process.kill("QUIT", File.read(old_pid).to_i)
37
+ rescue Errno::ENOENT, Errno::ESRCH
38
+ # someone else did our job for us
39
+ end
40
+ end
41
+ end
42
+
43
+ after_fork do |server, worker|
44
+ ActiveRecord::Base.establish_connection
45
+ end
File without changes
@@ -0,0 +1,155 @@
1
+ require 'capistrano/unicorn/utility'
2
+
3
+ include CapistranoUnicorn::Utility
4
+
5
+ # Load default values the capistrano 3.x way.
6
+ # See https://github.com/capistrano/capistrano/pull/605
7
+ namespace :load do
8
+ task :defaults do
9
+
10
+ # Environments
11
+ set :unicorn_env , Proc.new{ fetch(:rails_env, 'production') }
12
+ # Following recommendations from http://unicorn.bogomips.org/unicorn_1.html
13
+ set :unicorn_rack_env, Proc.new{ fetch(:rails_env) == 'development' ? 'development' : 'deployment' }
14
+
15
+ # Execution
16
+ set :unicorn_user , nil
17
+ set :unicorn_bundle , Proc.new{ fetch(:bundle_cmd, "bundle") }
18
+ set :unicorn_bin , "unicorn"
19
+ set :unicorn_options , ''
20
+ set :unicorn_restart_sleep_time, 2
21
+
22
+ # Relative paths
23
+ set :app_subdir , ''
24
+ set :unicorn_config_rel_path , "config"
25
+ set :unicorn_config_filename , "unicorn.rb"
26
+ set :unicorn_config_rel_file_path , Proc.new{ File.join(fetch(:unicorn_config_rel_path), fetch(:unicorn_config_filename)) }
27
+ set :unicorn_config_stage_rel_file_path, Proc.new{ File.join(fetch(:unicorn_config_rel_path), 'unicorn', "#{fetch(:unicorn_env)}.rb") }
28
+
29
+ # Absolute paths
30
+ # If you find the following confusing, try running 'cap unicorn:show_vars' -
31
+ # it might help :-)
32
+ set :app_path , Proc.new{ File.join(current_path, fetch(:app_subdir)) }
33
+ set :unicorn_config_path , Proc.new{ File.join(fetch(:app_path), fetch(:unicorn_config_rel_path)) }
34
+ set :unicorn_config_file_path , Proc.new{ File.join(fetch(:app_path), fetch(:unicorn_config_rel_file_path)) }
35
+ set :unicorn_config_stage_file_path, Proc.new{ File.join(fetch(:app_path), fetch(:unicorn_config_stage_rel_file_path)) }
36
+ set :unicorn_default_pid , Proc.new{ File.join(fetch(:app_path), 'tmp', 'pids', 'unicorn.pid') }
37
+ set :unicorn_pid, Proc.new{
38
+ extracted_pid = extract_pid_file
39
+ if extracted_pid
40
+ extracted_pid
41
+ else
42
+ # TODO logger is not defined
43
+ #logger.important "err :: failed to auto-detect pid from #{local_unicorn_config}"
44
+ #logger.important "err :: falling back to default: #{unicorn_default_pid}"
45
+ fetch :unicorn_default_pid
46
+ end
47
+ }
48
+ end
49
+ end
50
+
51
+ namespace :unicorn do
52
+ desc 'Debug Unicorn variables'
53
+ task :show_vars do
54
+ on roles :app do
55
+ puts <<-EOF.gsub(/^ +/, '')
56
+ # Environments
57
+ rails_env #{fetch :rails_env}
58
+ unicorn_env #{fetch :unicorn_env}
59
+ unicorn_rack_env #{fetch :unicorn_rack_env}
60
+
61
+ # Execution
62
+ unicorn_user #{fetch(:unicorn_user).inspect}
63
+ unicorn_bundle #{fetch :unicorn_bundle}
64
+ unicorn_bin #{fetch :unicorn_bin}
65
+ unicorn_options #{fetch :unicorn_options}
66
+ unicorn_restart_sleep_time #{fetch :unicorn_restart_sleep_time}
67
+
68
+ # Relative paths
69
+ app_subdir #{fetch :app_subdir}
70
+ unicorn_config_rel_path #{fetch :unicorn_config_rel_path}
71
+ unicorn_config_filename #{fetch :unicorn_config_filename}
72
+ unicorn_config_rel_file_path #{fetch :unicorn_config_rel_file_path}
73
+ unicorn_config_stage_rel_file_path #{fetch :unicorn_config_stage_rel_file_path}
74
+
75
+ # Absolute paths
76
+ app_path #{fetch :app_path}
77
+ unicorn_pid #{fetch :unicorn_pid}
78
+ #bundle_gemfile #{fetch :bundle_gemfile}
79
+ unicorn_config_path #{fetch :unicorn_config_path}
80
+ unicorn_config_file_path #{fetch :unicorn_config_file_path}
81
+ unicorn_config_stage_file_path
82
+ -> "#{fetch :unicorn_config_stage_file_path}
83
+ EOF
84
+ end
85
+ end
86
+
87
+ desc 'Start Unicorn master process'
88
+ task :start do
89
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
90
+ execute start_unicorn
91
+ end
92
+ end
93
+
94
+ desc 'Stop Unicorn'
95
+ task :stop do
96
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
97
+ execute kill_unicorn('QUIT')
98
+ end
99
+ end
100
+
101
+ desc 'Immediately shutdown Unicorn'
102
+ task :shutdown do
103
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
104
+ execute kill_unicorn('TERM')
105
+ end
106
+ end
107
+
108
+ desc 'Restart Unicorn'
109
+ task :restart do
110
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
111
+ duplicate_unicorn
112
+ execute :sleep, fetch(:unicorn_restart_sleep_time)
113
+
114
+ if old_unicorn_is_running?
115
+ unicorn_send_signal('QUIT', get_old_unicorn_pid)
116
+ end
117
+ end
118
+ end
119
+
120
+ desc 'Duplicate Unicorn'
121
+ task :duplicate do
122
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
123
+ duplicate_unicorn
124
+ end
125
+ end
126
+
127
+ desc 'Reload Unicorn'
128
+ task :reload do
129
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
130
+ if unicorn_is_running?
131
+ unicorn_send_signal('HUP')
132
+ else
133
+ start_unicorn
134
+ end
135
+ end
136
+ end
137
+
138
+ desc 'Add a new worker'
139
+ task :add_worker do
140
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
141
+ if unicorn_is_running?
142
+ unicorn_send_signal('TTIN')
143
+ end
144
+ end
145
+ end
146
+
147
+ desc 'Remove amount of workers'
148
+ task :remove_worker do
149
+ on roles unicorn_roles, reject: lambda { |h| h.properties.no_release } do
150
+ if unicorn_is_running?
151
+ unicorn_send_signal('TTOU')
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1 @@
1
+ load File.expand_path(File.join('..', 'tasks', 'unicorn.cap'), __FILE__)
@@ -0,0 +1,149 @@
1
+ require 'tempfile'
2
+
3
+ module CapistranoUnicorn
4
+ module Utility
5
+ # In Capistrano 3, shell scripts must be invoked with SSHKit's execute, instead of run.
6
+ def local_unicorn_config
7
+ if File.exist? fetch(:unicorn_config_rel_file_path)
8
+ fetch(:unicorn_config_rel_file_path)
9
+ else
10
+ fetch(:unicorn_config_stage_rel_file_path)
11
+ end
12
+ end
13
+
14
+ def extract_pid_file
15
+ tmp = Tempfile.new('unicorn.rb')
16
+ begin
17
+ conf = local_unicorn_config
18
+ tmp.write <<-EOF.gsub(/^ */, '')
19
+ config_file = "#{conf}"
20
+
21
+ # stub working_directory to avoid chdir failure since this will
22
+ # run client-side:
23
+ def working_directory(path); end
24
+
25
+ instance_eval(File.read(config_file), config_file) if config_file
26
+ puts set[:pid]
27
+ exit 0
28
+ EOF
29
+ tmp.close
30
+ extracted_pid = `unicorn -c "#{tmp.path}"`
31
+ $?.success? ? extracted_pid.rstrip : nil
32
+ rescue StandardError => e
33
+ return nil
34
+ ensure
35
+ tmp.close
36
+ tmp.unlink
37
+ end
38
+ end
39
+
40
+ # Check if a remote process exists using its pid file
41
+ #
42
+ def remote_process_exists?(pid_file)
43
+ test("[ -e #{pid_file} ]") && unicorn_execute(:kill, '-0', "`cat #{pid_file}`", '> /dev/null 2>&1', raise_on_non_zero_exit: false)
44
+ end
45
+
46
+ # Stale Unicorn process pid file
47
+ #
48
+ def old_unicorn_pid
49
+ "#{fetch :unicorn_pid}.oldbin"
50
+ end
51
+
52
+ # Command to check if Unicorn is running
53
+ #
54
+ def unicorn_is_running?
55
+ remote_process_exists?(fetch(:unicorn_pid))
56
+ end
57
+
58
+ # Command to check if stale Unicorn is running
59
+ #
60
+ def old_unicorn_is_running?
61
+ remote_process_exists?(old_unicorn_pid)
62
+ end
63
+
64
+ # Get unicorn master process PID (using the shell)
65
+ #
66
+ def get_unicorn_pid(pid_file=fetch(:unicorn_pid))
67
+ capture "cat #{pid_file}"
68
+ end
69
+
70
+ # Get unicorn master (old) process PID
71
+ #
72
+ def get_old_unicorn_pid
73
+ get_unicorn_pid(old_unicorn_pid)
74
+ end
75
+
76
+ # Send a signal to a unicorn master processes
77
+ #
78
+ def unicorn_send_signal(signal, pid=get_unicorn_pid)
79
+ unicorn_execute 'kill', '-s', signal, pid
80
+ end
81
+
82
+ # Run a unicorn command with or without sudo
83
+ # Run a command as the :unicorn_user user if :unicorn_user is a string.
84
+ # Otherwise run as default (:user) user.
85
+ #
86
+ def unicorn_execute(*args)
87
+ options = args.extract_options!
88
+
89
+ command = "bash -l -c \"#{args.join(' ')}\""
90
+ if unicorn_user = fetch(:unicorn_user)
91
+ execute :sudo, '-u', unicorn_user, command, options
92
+ else
93
+ execute command, options
94
+ end
95
+ end
96
+
97
+ # Kill Unicorns in multiple ways O_O
98
+ #
99
+ def kill_unicorn(signal)
100
+ if unicorn_is_running?
101
+ puts 'Stopping unicorn...'
102
+ unicorn_send_signal(signal)
103
+ else
104
+ puts 'Unicorn is not running'
105
+ end
106
+ end
107
+
108
+ # Start the Unicorn server
109
+ #
110
+ def start_unicorn
111
+ if test("[ -e #{fetch(:unicorn_config_file_path)} ]")
112
+ unicorn_config_file_path = fetch(:unicorn_config_file_path)
113
+ elsif test("[ -e #{fetch(:unicorn_config_stage_file_path)} ]")
114
+ unicorn_config_file_path = fetch(:unicorn_config_stage_file_path)
115
+ else
116
+ fail "Config file for \"#{fetch(:unicorn_env)}\" environment was not found at either \"#{fetch(:unicorn_config_file_path)}\" or \"#{fetch(:unicorn_config_stage_file_path)}\""
117
+ end
118
+
119
+ if test("[ -e #{fetch(:unicorn_pid)} ]")
120
+ if unicorn_is_running?
121
+ puts 'Unicorn is already running!'
122
+ return
123
+ else
124
+ unicorn_execute :rm, fetch(:unicorn_pid)
125
+ end
126
+ end
127
+
128
+ puts 'Starting unicorn...'
129
+
130
+ within fetch(:app_path) do
131
+ with rails_env: fetch(:rails_env), bundle_gemfile: fetch(:bundle_gemfile) do
132
+ unicorn_execute fetch(:unicorn_bin), '-c', unicorn_config_file_path, '-E', fetch(:unicorn_rack_env), '-D', fetch(:unicorn_options)
133
+ end
134
+ end
135
+ end
136
+
137
+ def duplicate_unicorn
138
+ if unicorn_is_running?
139
+ unicorn_send_signal('USR2')
140
+ else
141
+ start_unicorn
142
+ end
143
+ end
144
+
145
+ def unicorn_roles
146
+ fetch(:unicorn_roles, :app)
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,5 @@
1
+ module CapistranoUnicorn
2
+ unless defined?(::CapistranoUnicorn::VERSION)
3
+ VERSION = "0.3.1".freeze
4
+ end
5
+ end
data/lib/unicorn.rb ADDED
File without changes
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ describe CapistranoUnicorn::CapistranoIntegration, "loaded tasks into capistrano" do
4
+ before do
5
+ @configuration = Capistrano::Configuration.new
6
+ @configuration.extend(Capistrano::Spec::ConfigurationExtension)
7
+ CapistranoUnicorn::CapistranoIntegration.load_into(@configuration)
8
+ end
9
+
10
+ shared_examples_for "a task" do |task_name|
11
+ it "sets attributes in before_task hook" do
12
+ # Environments
13
+ @configuration.should_receive(:_cset).with(:unicorn_env)
14
+ @configuration.should_receive(:_cset).with(:unicorn_rack_env)
15
+
16
+ # Execution
17
+ @configuration.should_receive(:_cset).with(:unicorn_user)
18
+ @configuration.should_receive(:_cset).with(:unicorn_bundle)
19
+ @configuration.should_receive(:_cset).with(:unicorn_bin)
20
+ @configuration.should_receive(:_cset).with(:unicorn_options)
21
+ @configuration.should_receive(:_cset).with(:unicorn_restart_sleep_time)
22
+
23
+ # Relative paths
24
+ @configuration.should_receive(:_cset).with(:app_subdir)
25
+ @configuration.should_receive(:_cset).with(:unicorn_config_rel_path)
26
+ @configuration.should_receive(:_cset).with(:unicorn_config_filename)
27
+ @configuration.should_receive(:_cset).with(:unicorn_config_rel_file_path)
28
+ @configuration.should_receive(:_cset).with(:unicorn_config_stage_rel_file_path)
29
+
30
+ # Absolute paths
31
+ @configuration.should_receive(:_cset).with(:app_path)
32
+ @configuration.should_receive(:_cset).with(:unicorn_pid)
33
+ @configuration.should_receive(:_cset).with(:bundle_gemfile)
34
+ @configuration.should_receive(:_cset).with(:unicorn_config_path)
35
+ @configuration.should_receive(:_cset).with(:unicorn_config_file_path)
36
+ @configuration.should_receive(:_cset).with(:unicorn_config_stage_file_path)
37
+
38
+ @configuration.find_and_execute_task(task_name)
39
+ end
40
+ end
41
+
42
+ describe "task" do
43
+ describe 'unicorn:start' do
44
+ before do
45
+ @configuration.stub(:start_unicorn)
46
+ @configuration.stub(:_cset)
47
+ end
48
+
49
+ it_behaves_like "a task", 'unicorn:start'
50
+
51
+ it "runs start_unicorn command" do
52
+ @configuration.should_receive(:start_unicorn).and_return("start unicorn command")
53
+ @configuration.find_and_execute_task('unicorn:start')
54
+ @configuration.should have_run("start unicorn command")
55
+ end
56
+ end
57
+
58
+ describe 'unicorn:stop' do
59
+ before do
60
+ @configuration.stub(:kill_unicorn)
61
+ @configuration.stub(:_cset)
62
+ end
63
+
64
+ it_behaves_like "a task", 'unicorn:stop'
65
+
66
+ it "runs kill_unicorn command" do
67
+ @configuration.should_receive(:kill_unicorn).with('QUIT').and_return("kill unicorn command")
68
+ @configuration.find_and_execute_task('unicorn:stop')
69
+ @configuration.should have_run("kill unicorn command")
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#kill_unicorn" do
75
+ before do
76
+ @configuration.stub(:unicorn_pid).and_return(999)
77
+ @configuration.stub(:unicorn_user).and_return("deploy_user")
78
+ end
79
+
80
+ it "generates the kill unicorn command" do
81
+ @configuration.kill_unicorn('QUIT').should match /-u deploy_user kill -s QUIT `cat 999`;/
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+ describe CapistranoUnicorn::Config, "loaded into a configuration" do
3
+ before do
4
+ @configuration = Capistrano::Configuration.new
5
+ @configuration.extend(Capistrano::Spec::ConfigurationExtension)
6
+ CapistranoUnicorn::CapistranoIntegration.load_into(@configuration)
7
+ end
8
+
9
+ context "testing variables" do
10
+ before do
11
+ # define _cset etc. from capistrano
12
+ @configuration.load 'deploy'
13
+
14
+ # capistrano-unicorn variables are set during a 'before'
15
+ # callback, so in order to be able to test the result, we need
16
+ # to ensure the callback is triggered.
17
+ @configuration.trigger :before
18
+ end
19
+
20
+ describe "app paths" do
21
+ cur_path = '/path/to/myapp'
22
+
23
+ before do
24
+ @configuration.set(:current_path, cur_path)
25
+ end
26
+
27
+ shared_examples_for "an app in path" do |app_path|
28
+ let(:shell) { :` } # ` } work around confused emacs ruby-mode
29
+
30
+ specify "app_path should default to #{app_path}" do
31
+ @configuration.fetch(:app_path).should == app_path
32
+ end
33
+
34
+ it "should default to a sensible pid file when auto-detection failed" do
35
+ @configuration.should_receive(shell).with(/unicorn -c /).and_return('') do |cmd|
36
+ `false` # Simulate failure by setting $?
37
+ end
38
+ @configuration.logger.stub(:important)
39
+ @configuration.fetch(:unicorn_pid).should == app_path + "/tmp/pids/unicorn.pid"
40
+ end
41
+
42
+ shared_examples "auto-detect pid file from unicorn config" do
43
+ |pid_file, primary_exists, config_file|
44
+ which_config = primary_exists ? 'primary' : 'stage'
45
+ it "should auto-detect pid file from #{which_config} unicorn config" do
46
+ # Tempfile.new in Ruby 1.9.2 will call File.exist?
47
+ allow(File).to receive(:exist?).with(/tmp/)
48
+
49
+ File.should_receive(:exist?).with('config/unicorn.rb').and_return(primary_exists)
50
+ tmpfile = nil
51
+ @configuration.should_receive(shell).with(/unicorn -c /) do |cmd|
52
+ (cmd =~ /^unicorn -c "(.+)"$/).should be_true
53
+ tmpfile = $~[1]
54
+ tmpfile.should include("tmp")
55
+ File.read(tmpfile).should include(%!config_file = "#{config_file}"!)
56
+ `true` # Simulate success by setting $?
57
+ pid_file
58
+ end
59
+ @configuration.fetch(:unicorn_pid).should == pid_file
60
+ end
61
+ end
62
+
63
+ include_examples "auto-detect pid file from unicorn config", \
64
+ '/path/to/pid/from/config/file', true, "config/unicorn.rb"
65
+
66
+ include_examples "auto-detect pid file from unicorn config", \
67
+ '/path/to/pid/from/stage/config/file', false, "config/unicorn/production.rb"
68
+
69
+ specify "Gemfile should default correctly" do
70
+ @configuration.fetch(:bundle_gemfile).should == app_path + "/Gemfile"
71
+ end
72
+
73
+ specify "config/ directory should default correctly" do
74
+ @configuration.fetch(:unicorn_config_path).should == app_path + "/config"
75
+ end
76
+
77
+ specify "config file should default correctly" do
78
+ @configuration.fetch(:unicorn_config_file_path).should == app_path + "/config/unicorn.rb"
79
+ end
80
+
81
+ specify "per-stage config file should default correctly" do
82
+ @configuration.fetch(:unicorn_config_stage_file_path).should == app_path + "/config/unicorn/production.rb"
83
+ end
84
+
85
+ specify "per-stage config file should be set correctly for different environment" do
86
+ @configuration.set(:rails_env, 'staging')
87
+ @configuration.fetch(:unicorn_config_stage_file_path).should == app_path + "/config/unicorn/staging.rb"
88
+ end
89
+ end
90
+
91
+ context "app in current_path" do
92
+ it_should_behave_like "an app in path", cur_path
93
+ end
94
+
95
+ context "app in a subdirectory" do
96
+ subdir = 'mysubdir'
97
+
98
+ before do
99
+ @configuration.set(:app_subdir, '/' + subdir)
100
+ end
101
+
102
+ it_should_behave_like "an app in path", cur_path + '/' + subdir
103
+ end
104
+ end
105
+
106
+ describe "unicorn_env" do
107
+ it "should default to value of rails_env if set" do
108
+ @configuration.set(:rails_env, 'staging')
109
+ @configuration.fetch(:unicorn_env).should == \
110
+ @configuration.fetch(:rails_env)
111
+ end
112
+
113
+ it "should default to production if rails_env not set" do
114
+ @configuration.fetch(:unicorn_env).should == 'production'
115
+ end
116
+ end
117
+
118
+ describe "unicorn_rack_env" do
119
+ it "should default to deployment if rails_env not set" do
120
+ @configuration.fetch(:unicorn_rack_env).should == 'deployment'
121
+ end
122
+
123
+ it "should default to development if rails_env set to development" do
124
+ @configuration.set(:rails_env, 'development')
125
+ @configuration.fetch(:unicorn_rack_env).should == 'development'
126
+ end
127
+
128
+ it "should default to deployment if rails_env set to anything else" do
129
+ @configuration.set(:rails_env, 'staging')
130
+ @configuration.fetch(:unicorn_rack_env).should == 'deployment'
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,7 @@
1
+ require 'capistrano-spec'
2
+ require 'capistrano-unicorn'
3
+
4
+ RSpec.configure do |config|
5
+ config.include Capistrano::Spec::Matchers
6
+ config.include Capistrano::Spec::Helpers
7
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-unicorn-sic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Gassner, Dan Sosedoff, Florian Schwab
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: unicorn
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: capistrano
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0
55
+ description: Capistrano 3.x plugin that integrates Unicorn server tasks.
56
+ email: sebastian.gassner@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - ".rspec"
63
+ - ".travis.yml"
64
+ - Gemfile
65
+ - LICENSE
66
+ - NEWS.md
67
+ - README.md
68
+ - Rakefile
69
+ - capistrano-unicorn.gemspec
70
+ - examples/rails3.rb
71
+ - lib/capistrano-unicorn.rb
72
+ - lib/capistrano/tasks/unicorn.cap
73
+ - lib/capistrano/unicorn.rb
74
+ - lib/capistrano/unicorn/utility.rb
75
+ - lib/capistrano/unicorn/version.rb
76
+ - lib/unicorn.rb
77
+ - spec/capistrano_integration_spec.rb
78
+ - spec/config_spec.rb
79
+ - spec/spec_helper.rb
80
+ homepage: https://github.com/SICSoftwareGmbH/capistrano-unicorn
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.2.2
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Unicorn integration for Capistrano 3.x
104
+ test_files:
105
+ - spec/capistrano_integration_spec.rb
106
+ - spec/config_spec.rb
107
+ - spec/spec_helper.rb