deployinator 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/deployinator/built-in.rb +76 -45
- data/lib/deployinator/check.rb +15 -20
- data/lib/deployinator/config.rb +16 -8
- data/lib/deployinator/deploy.rb +73 -24
- data/lib/deployinator/examples/config/deploy.rb +7 -1
- data/lib/deployinator/examples/database.yml.erb +10 -0
- data/lib/deployinator/helpers.rb +40 -10
- data/lib/deployinator/jobs.rb +4 -3
- metadata +20 -2
@@ -1,13 +1,13 @@
|
|
1
|
-
set :deploy_log_level, "debug"
|
2
1
|
set :webserver_socket_path, -> { shared_path.join('run') }
|
3
2
|
set :deploy_templates_path, "templates/deploy"
|
4
3
|
set :jobs_app_name, "jobs"
|
4
|
+
set :deploy_custom_container_options, -> {} # Set customer Docker options w/o overriding methods below
|
5
5
|
|
6
6
|
# Default deploy_to directory is /var/www/my_app
|
7
7
|
# set :deploy_to, '/var/www/my_app'
|
8
8
|
|
9
9
|
# Default value for :log_level is :debug
|
10
|
-
|
10
|
+
set :log_level, :info
|
11
11
|
|
12
12
|
# Default value for :linked_files is []
|
13
13
|
# set :linked_files, %w{config/database.yml}
|
@@ -36,45 +36,50 @@ set :migration_role, :db # Defaults to 'db'
|
|
36
36
|
set :assets_roles, [:app] # Defaults to [:web]
|
37
37
|
#set :assets_prefix, 'prepackaged-assets' # Defaults to 'assets' this should match config.assets.prefix in your rails config/application.rb
|
38
38
|
|
39
|
-
# TODO: fix from_local, right now you have to copy-paste the set_scm method to your deploy.rb
|
40
|
-
# Use `cap <stage> deploy from_local=true` to deploy your locally changed code
|
41
|
-
# instead of the code in the git repo. You can also add --trace.
|
42
|
-
# You can set include_dir and exclude_dir settings (from capistrano-scm-copy gem).
|
43
|
-
# These will only apply when using the from_local=true option
|
44
|
-
# set :include_dir, '../.*'
|
45
|
-
# set :exclude_dir, ["../.$", "../..", '.././infrastructure']
|
46
|
-
def set_scm
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
set_scm
|
39
|
+
# # TODO: fix from_local, right now you have to copy-paste the set_scm method to your deploy.rb
|
40
|
+
# # Use `cap <stage> deploy from_local=true` to deploy your locally changed code
|
41
|
+
# # instead of the code in the git repo. You can also add --trace.
|
42
|
+
# # You can set include_dir and exclude_dir settings (from capistrano-scm-copy gem).
|
43
|
+
# # These will only apply when using the from_local=true option
|
44
|
+
# # set :include_dir, '../.*'
|
45
|
+
# # set :exclude_dir, ["../.$", "../..", '.././infrastructure']
|
46
|
+
# def set_scm
|
47
|
+
# if ENV['from_local']
|
48
|
+
# if "#{fetch(:stage)}" == "production"
|
49
|
+
# run_locally do
|
50
|
+
# fatal("You are trying to deploy to production using from_local, " +
|
51
|
+
# "this should pretty much never be done.")
|
52
|
+
# end
|
53
|
+
# ask :yes_no, "Are you positive you want to continue?"
|
54
|
+
# case fetch(:yes_no).chomp.downcase
|
55
|
+
# when "yes"
|
56
|
+
# when "no"
|
57
|
+
# exit
|
58
|
+
# else
|
59
|
+
# warn "Please enter 'yes' or 'no'"
|
60
|
+
# set_scm
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
# set :scm, :copy
|
64
|
+
# else
|
65
|
+
# set :scm, :git
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
# set_scm
|
69
69
|
|
70
70
|
def deploy_run_bluepill(host)
|
71
|
+
warn "Starting a new container named #{fetch(:ruby_container_name)} on #{host}"
|
71
72
|
execute(
|
72
73
|
"docker", "run", "--tty", "--detach",
|
74
|
+
# "--user", fetch(:webserver_username), TODO find out of this can run as the deployer user instead of root, if so, set the user, if not, fix rails console to su to www-data first
|
73
75
|
"--name", fetch(:ruby_container_name),
|
76
|
+
"-e", "APP_STAGE=#{fetch(:stage)}",
|
77
|
+
"-e", "RAILS_ROOT=#{current_path}",
|
74
78
|
"-e", "GEM_HOME=#{shared_path.join('bundle')}",
|
75
79
|
"-e", "GEM_PATH=#{shared_path.join('bundle')}",
|
76
80
|
"-e", "BUNDLE_GEMFILE=#{current_path.join('Gemfile')}",
|
77
81
|
"-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
|
82
|
+
fetch(:deploy_custom_container_options),
|
78
83
|
"--restart", "always", "--memory", "#{fetch(:ruby_container_max_mem_mb)}m",
|
79
84
|
"--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
|
80
85
|
"--entrypoint", shared_path.join('bundle', 'bin', 'bluepill'),
|
@@ -83,26 +88,34 @@ def deploy_run_bluepill(host)
|
|
83
88
|
)
|
84
89
|
end
|
85
90
|
def deploy_bluepill_restart(host)
|
86
|
-
execute(
|
91
|
+
execute(
|
92
|
+
"docker", "exec", "--tty",
|
87
93
|
fetch(:ruby_container_name),
|
88
94
|
shared_path.join('bundle', 'bin', 'bluepill'),
|
89
|
-
fetch(:application), "restart"
|
95
|
+
fetch(:application), "restart"
|
96
|
+
)
|
90
97
|
end
|
91
98
|
def deploy_bluepill_stop(host)
|
92
|
-
execute(
|
99
|
+
execute(
|
100
|
+
"docker", "exec", "--tty",
|
93
101
|
fetch(:ruby_container_name),
|
94
102
|
shared_path.join('bundle', 'bin', 'bluepill'),
|
95
|
-
fetch(:application), "stop"
|
103
|
+
fetch(:application), "stop"
|
104
|
+
)
|
96
105
|
end
|
97
106
|
def deploy_run_bluepill_jobs(host)
|
98
107
|
execute(
|
99
108
|
"docker", "run", "--tty", "--detach",
|
109
|
+
"-w", current_path,
|
100
110
|
"--user", fetch(:webserver_username),
|
101
111
|
"--name", fetch(:ruby_jobs_container_name),
|
112
|
+
"-e", "APP_STAGE=#{fetch(:stage)}",
|
113
|
+
"-e", "RAILS_ROOT=#{current_path}",
|
102
114
|
"-e", "GEM_HOME=#{shared_path.join('bundle')}",
|
103
115
|
"-e", "GEM_PATH=#{shared_path.join('bundle')}",
|
104
116
|
"-e", "BUNDLE_GEMFILE=#{current_path.join('Gemfile')}",
|
105
117
|
"-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
|
118
|
+
fetch(:deploy_custom_container_options),
|
106
119
|
"--restart", "always", "--memory", "#{fetch(:ruby_jobs_container_max_mem_mb)}m",
|
107
120
|
"--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
|
108
121
|
"--entrypoint", shared_path.join('bundle', 'bin', 'rabid_jobs_tasker'),
|
@@ -123,10 +136,13 @@ def deploy_run_cadvisor(host)
|
|
123
136
|
"google/cadvisor:latest"
|
124
137
|
)
|
125
138
|
end
|
139
|
+
# TODO change these both to run as webserver_username
|
140
|
+
# also offer Rails 2.X versions
|
126
141
|
def deploy_rails_console(host)
|
127
142
|
[
|
128
143
|
"ssh", "-t", "#{host}", "\"docker", "exec", "--interactive", "--tty",
|
129
144
|
fetch(:ruby_container_name),
|
145
|
+
# "sudo", "-u", fetch(:webserver_username), TODO, find out if running bluepill as www-data works, otherwise add this line
|
130
146
|
"bash", "-c", "'cd", current_path, "&&",
|
131
147
|
shared_path.join('bundle', 'bin', 'rails'),
|
132
148
|
"console", "#{fetch(:rails_env)}'\""
|
@@ -149,7 +165,7 @@ def sshkit_bundle_command_map
|
|
149
165
|
"-e", "GEM_PATH=#{shared_path.join('bundle')}",
|
150
166
|
"-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
|
151
167
|
"--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
|
152
|
-
"--volume", "$SSH_AUTH_SOCK:/ssh-agent --env SSH_AUTH_SOCK=/ssh-agent",
|
168
|
+
"--volume", "$SSH_AUTH_SOCK:/ssh-agent:rw", "--env SSH_AUTH_SOCK=/ssh-agent",
|
153
169
|
"--volume", "/home:/home:rw",
|
154
170
|
"--volume", "/etc/passwd:/etc/passwd:ro",
|
155
171
|
"--volume", "/etc/group:/etc/group:ro",
|
@@ -158,35 +174,49 @@ def sshkit_bundle_command_map
|
|
158
174
|
].join(' ')
|
159
175
|
end
|
160
176
|
def deploy_assets_precompile(host)
|
161
|
-
execute(
|
177
|
+
execute(
|
178
|
+
"docker", "run", "--rm", "--tty", "--user", fetch(:webserver_username),
|
179
|
+
"-e", "APP_STAGE=#{fetch(:stage)}",
|
180
|
+
"-e", "RAILS_ROOT=#{current_path}",
|
162
181
|
"-w", release_path,
|
163
182
|
"--volume", "/home:/home:rw",
|
164
183
|
"--volume", "/etc/passwd:/etc/passwd:ro",
|
165
184
|
"--volume", "/etc/group:/etc/group:ro",
|
166
185
|
"--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
|
186
|
+
fetch(:deploy_custom_container_options),
|
167
187
|
"--entrypoint", "/bin/bash",
|
168
188
|
fetch(:ruby_image_name), "-c",
|
169
189
|
"\"umask", "0007", "&&", "#{shared_path.join('bundle', 'bin', 'rake')}",
|
170
|
-
"assets:precompile\""
|
190
|
+
"assets:precompile\""
|
191
|
+
)
|
171
192
|
end
|
172
193
|
def deploy_assets_cleanup(host)
|
173
|
-
execute(
|
194
|
+
execute(
|
195
|
+
"docker", "run", "--rm", "--tty",
|
174
196
|
"-e", "RAILS_ENV=#{fetch(:rails_env)}",
|
175
197
|
"-w", release_path,
|
198
|
+
fetch(:deploy_custom_container_options),
|
176
199
|
"--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
|
177
200
|
"--entrypoint", shared_path.join('bundle', 'bin', 'bundle'),
|
178
|
-
fetch(:ruby_image_name), "exec", "rake", "assets:clean"
|
201
|
+
fetch(:ruby_image_name), "exec", "rake", "assets:clean"
|
202
|
+
)
|
179
203
|
end
|
180
204
|
def deploy_rake_db_migrate(host)
|
181
|
-
execute(
|
205
|
+
execute(
|
206
|
+
"docker", "run", "--rm", "--tty",
|
182
207
|
"-w", release_path,
|
208
|
+
"-e", "APP_STAGE=#{fetch(:stage)}",
|
209
|
+
"-e", "RAILS_ROOT=#{current_path}",
|
183
210
|
"-e", "RAILS_ENV=#{fetch(:rails_env)}",
|
211
|
+
fetch(:deploy_custom_container_options),
|
184
212
|
"--volume", "#{fetch(:deploy_to)}:#{fetch(:deploy_to)}:rw",
|
185
213
|
"--entrypoint", shared_path.join('bundle', 'bin', 'rake'),
|
186
|
-
fetch(:ruby_image_name), "db:migrate"
|
214
|
+
fetch(:ruby_image_name), "db:migrate"
|
215
|
+
)
|
187
216
|
end
|
188
217
|
def deploy_install_bundler(host)
|
189
|
-
execute(
|
218
|
+
execute(
|
219
|
+
"docker", "run", "--rm", "--tty", "--user", fetch(:deployment_username),
|
190
220
|
"-e", "GEM_HOME=#{shared_path.join('bundle')}",
|
191
221
|
"-e", "GEM_PATH=#{shared_path.join('bundle')}",
|
192
222
|
"-e", "PATH=#{shared_path.join('bundle', 'bin')}:$PATH",
|
@@ -199,5 +229,6 @@ def deploy_install_bundler(host)
|
|
199
229
|
"\"umask", "0007", "&&" "/usr/local/bin/gem", "install",
|
200
230
|
"--install-dir", "#{shared_path.join('bundle')}",
|
201
231
|
"--bindir", shared_path.join('bundle', 'bin'),
|
202
|
-
"--no-ri", "--no-rdoc", "--quiet", "bundler", "-v'#{fetch(:bundler_version)}'\""
|
232
|
+
"--no-ri", "--no-rdoc", "--quiet", "bundler", "-v'#{fetch(:bundler_version)}'\""
|
233
|
+
)
|
203
234
|
end
|
data/lib/deployinator/check.rb
CHANGED
@@ -1,33 +1,27 @@
|
|
1
1
|
namespace :deploy do
|
2
2
|
namespace :check do
|
3
3
|
|
4
|
-
task :bundle_command_map do
|
4
|
+
task :bundle_command_map => 'deployinator:load_settings' do
|
5
5
|
set :bundle_binstubs, -> { shared_path.join('bundle', 'bin') }
|
6
6
|
set :bundle_gemfile, -> { release_path.join('Gemfile') }
|
7
7
|
SSHKit.config.command_map[:bundle] = sshkit_bundle_command_map
|
8
8
|
end
|
9
|
-
|
9
|
+
if Rake::Task.task_defined?("bundler:install")
|
10
|
+
before 'bundler:install', 'deploy:check:bundle_command_map'
|
11
|
+
end
|
10
12
|
|
11
13
|
# Ensure Capistrano's inner rm commands always run using sudo
|
12
|
-
|
14
|
+
task :rm_command_map => 'deployinator:load_settings' do
|
13
15
|
SSHKit.config.command_map[:rm] = "/usr/bin/env sudo rm"
|
14
16
|
end
|
15
|
-
|
16
|
-
before 'deploy:check', :brakeman_reminder do
|
17
|
-
run_locally do
|
18
|
-
warn "Remember to run brakeman before deploying!"
|
19
|
-
ask :return_to_continue, nil
|
20
|
-
set :nothing, fetch(:return_to_continue)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
17
|
+
before 'deploy:started', 'deploy:check:rm_command_map'
|
24
18
|
if Rake::Task.task_defined?("deploy:cleanup")
|
25
19
|
# Append dependancy to existing cleanup task
|
26
20
|
task 'deploy:cleanup' => 'deploy:check:rm_command_map'
|
27
21
|
end
|
28
22
|
|
29
23
|
desc 'Ensure all deployinator specific settings are set, and warn and raise if not.'
|
30
|
-
|
24
|
+
task :settings => 'deployinator:load_settings' do
|
31
25
|
{
|
32
26
|
(File.dirname(__FILE__) + "/examples/config/deploy.rb") => 'config/deploy.rb',
|
33
27
|
(File.dirname(__FILE__) + "/examples/config/deploy/staging.rb") => "config/deploy/#{fetch(:stage)}.rb"
|
@@ -36,9 +30,10 @@ namespace :deploy do
|
|
36
30
|
Rake::Task['deployinator:settings'].reenable
|
37
31
|
end
|
38
32
|
end
|
33
|
+
before 'deploy:check', 'deploy:check:settings'
|
39
34
|
|
40
35
|
# TODO make this better
|
41
|
-
|
36
|
+
task :templates => 'deployinator:load_settings' do
|
42
37
|
run_locally do
|
43
38
|
path = fetch(:deploy_templates_path)
|
44
39
|
keys_template = File.expand_path("./#{path}/deployment_authorized_keys.erb")
|
@@ -50,11 +45,9 @@ namespace :deploy do
|
|
50
45
|
end
|
51
46
|
end
|
52
47
|
end
|
48
|
+
before 'deploy:check', 'deploy:check:templates'
|
53
49
|
|
54
|
-
|
55
|
-
before 'deploy:check', 'deployinator:webserver_user'
|
56
|
-
|
57
|
-
task :root_dir_permissions => ['deployinator:deployment_user', 'deployinator:webserver_user'] do
|
50
|
+
task :root_dir_permissions => ['deployinator:load_settings', 'deployinator:deployment_user', 'deployinator:webserver_user'] do
|
58
51
|
on roles(:app) do
|
59
52
|
as :root do
|
60
53
|
[fetch(:deploy_to), Pathname.new(fetch(:deploy_to)).join("../"), shared_path].each do |dir|
|
@@ -68,7 +61,7 @@ namespace :deploy do
|
|
68
61
|
end
|
69
62
|
before 'deploy:check:directories', 'deploy:check:root_dir_permissions'
|
70
63
|
|
71
|
-
|
64
|
+
task :postgres_running => 'deployinator:load_settings' do
|
72
65
|
on roles(:app) do
|
73
66
|
unless localhost_port_responding?(fetch(:postgres_port))
|
74
67
|
fatal "Port #{fetch(:postgres_port)} is not responding, we won't be able to db:migrate!"
|
@@ -76,8 +69,9 @@ namespace :deploy do
|
|
76
69
|
end
|
77
70
|
end
|
78
71
|
end
|
72
|
+
before 'deploy:check', 'deploy:check:postgres_running'
|
79
73
|
|
80
|
-
|
74
|
+
task :ensure_cadvisor => 'deployinator:load_settings' do
|
81
75
|
on roles(:app) do |host|
|
82
76
|
if fetch(:use_cadvisor, true)
|
83
77
|
if container_exists?("cadvisor")
|
@@ -97,6 +91,7 @@ namespace :deploy do
|
|
97
91
|
end
|
98
92
|
end
|
99
93
|
end
|
94
|
+
before 'deploy:check', 'deploy:check:ensure_cadvisor'
|
100
95
|
|
101
96
|
end
|
102
97
|
end
|
data/lib/deployinator/config.rb
CHANGED
@@ -12,11 +12,14 @@ module Capistrano
|
|
12
12
|
end
|
13
13
|
|
14
14
|
namespace :deployinator do
|
15
|
+
task :load_settings do
|
16
|
+
load "./config/deploy.rb"
|
17
|
+
SSHKit.config.output_verbosity = fetch(:log_level)
|
18
|
+
end
|
15
19
|
|
16
20
|
set :example, "_example"
|
17
|
-
|
18
21
|
desc 'Write example config files'
|
19
|
-
task :write_example_configs do
|
22
|
+
task :write_example_configs => 'deployinator:load_settings' do
|
20
23
|
run_locally do
|
21
24
|
path = fetch(:deploy_templates_path, 'templates/deploy')
|
22
25
|
execute "mkdir", "-p", "config/deploy", path
|
@@ -28,6 +31,7 @@ namespace :deployinator do
|
|
28
31
|
"examples/deployment_authorized_keys.erb" =>
|
29
32
|
"#{path}/deployment_authorized_keys#{fetch(:example)}.erb",
|
30
33
|
"examples/unicorn.rb.erb" => "#{path}/unicorn#{fetch(:example)}.rb.erb",
|
34
|
+
"examples/database.yml.erb" => "#{path}/database#{fetch(:example)}.yml.erb",
|
31
35
|
"examples/bluepill.rb.erb" => "#{path}/bluepill#{fetch(:example)}.rb.erb",
|
32
36
|
}.each do |source, destination|
|
33
37
|
config = File.read(File.dirname(__FILE__) + "/#{source}")
|
@@ -43,14 +47,14 @@ namespace :deployinator do
|
|
43
47
|
|
44
48
|
desc 'Write example config files (will overwrite any existing config files).'
|
45
49
|
namespace :write_example_configs do
|
46
|
-
task :in_place do
|
50
|
+
task :in_place => 'deployinator:load_settings' do
|
47
51
|
set :example, ""
|
48
52
|
Rake::Task['deployinator:write_example_configs'].invoke
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
52
56
|
desc 'Write a file showing the built-in overridable settings.'
|
53
|
-
task :write_built_in do
|
57
|
+
task :write_built_in => 'deployinator:load_settings' do
|
54
58
|
run_locally do
|
55
59
|
{
|
56
60
|
'built-in.rb' => 'built-in.rb',
|
@@ -66,7 +70,7 @@ namespace :deployinator do
|
|
66
70
|
# These are the only two tasks using :preexisting_ssh_user
|
67
71
|
namespace :deployment_user do
|
68
72
|
#desc "Setup or re-setup the deployment user, idempotently"
|
69
|
-
task :setup do
|
73
|
+
task :setup => 'deployinator:load_settings' do
|
70
74
|
on roles(:all) do |h|
|
71
75
|
on "#{fetch(:preexisting_ssh_user)}@#{h}" do |host|
|
72
76
|
as :root do
|
@@ -77,7 +81,7 @@ namespace :deployinator do
|
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
80
|
-
task :deployment_user do
|
84
|
+
task :deployment_user => 'deployinator:load_settings' do
|
81
85
|
on roles(:all) do |h|
|
82
86
|
on "#{fetch(:preexisting_ssh_user)}@#{h}" do |host|
|
83
87
|
as :root do
|
@@ -90,22 +94,26 @@ namespace :deployinator do
|
|
90
94
|
end
|
91
95
|
end
|
92
96
|
end
|
97
|
+
before 'deploy:check', 'deployinator:deployment_user'
|
93
98
|
|
94
|
-
task :webserver_user do
|
99
|
+
task :webserver_user => 'deployinator:load_settings' do
|
95
100
|
on roles(:app) do
|
96
101
|
as :root do
|
97
102
|
unix_user_add(fetch(:webserver_username)) unless unix_user_exists?(fetch(:webserver_username))
|
98
103
|
end
|
99
104
|
end
|
100
105
|
end
|
106
|
+
before 'deploy:check', 'deployinator:webserver_user'
|
101
107
|
|
102
|
-
task :file_permissions => [:deployment_user, :webserver_user] do
|
108
|
+
task :file_permissions => [:load_settings, :deployment_user, :webserver_user] do
|
103
109
|
on roles(:app) do
|
104
110
|
as :root do
|
105
111
|
setup_file_permissions
|
106
112
|
end
|
107
113
|
end
|
108
114
|
end
|
115
|
+
# TODO the file_permissions task after 'deploy:check' may be able to be replaced
|
116
|
+
# with only chowning the releases dir and another dir or two.
|
109
117
|
after 'deploy:check', 'deployinator:file_permissions'
|
110
118
|
before 'deploy:restart', 'deployinator:file_permissions'
|
111
119
|
|
data/lib/deployinator/deploy.rb
CHANGED
@@ -3,14 +3,8 @@ lock '3.2.1'
|
|
3
3
|
|
4
4
|
namespace :deploy do
|
5
5
|
|
6
|
-
before :starting, :log_level do
|
7
|
-
SSHKit.config.output_verbosity = fetch(:deploy_log_level)
|
8
|
-
end
|
9
|
-
|
10
|
-
before :starting, 'deployinator:sshkit_umask'
|
11
|
-
|
12
6
|
# Default branch is :master
|
13
|
-
|
7
|
+
task :set_branch => 'deployinator:load_settings' do
|
14
8
|
unless ENV['from_local']
|
15
9
|
# Always use the master branch in production:
|
16
10
|
unless "#{fetch(:stage)}" == "production"
|
@@ -18,9 +12,10 @@ namespace :deploy do
|
|
18
12
|
end
|
19
13
|
end
|
20
14
|
end
|
15
|
+
before :starting, :set_branch
|
21
16
|
|
22
17
|
#desc 'Copies .git folder to support .gemspecs that run git commands'
|
23
|
-
task :copy_git do
|
18
|
+
task :copy_git => 'deployinator:load_settings' do
|
24
19
|
unless ENV['from_local'] == "true"
|
25
20
|
on roles(:app) do
|
26
21
|
within release_path do
|
@@ -29,13 +24,15 @@ namespace :deploy do
|
|
29
24
|
end
|
30
25
|
end
|
31
26
|
end
|
32
|
-
|
27
|
+
if Rake::Task.task_defined?("bundler:install")
|
28
|
+
before 'bundler:install', 'deploy:copy_git'
|
29
|
+
end
|
33
30
|
|
34
31
|
if Rake::Task.task_defined?("deploy:assets:precompile")
|
35
32
|
# Overwrite :assets:precompile to use docker
|
36
33
|
Rake::Task["deploy:assets:precompile"].clear_actions
|
37
34
|
namespace :assets do
|
38
|
-
task :precompile do
|
35
|
+
task :precompile => 'deployinator:load_settings' do
|
39
36
|
on roles(fetch(:assets_roles)) do |host|
|
40
37
|
deploy_assets_precompile(host)
|
41
38
|
end
|
@@ -47,7 +44,7 @@ namespace :deploy do
|
|
47
44
|
# Overwrite :cleanup_assets to use docker
|
48
45
|
Rake::Task["deploy:cleanup_assets"].clear_actions
|
49
46
|
desc 'Cleanup expired assets'
|
50
|
-
task :cleanup_assets => [:set_rails_env] do
|
47
|
+
task :cleanup_assets => ['deployinator:load_settings', :set_rails_env] do
|
51
48
|
on roles(fetch(:assets_roles)) do |host|
|
52
49
|
deploy_assets_cleanup(host)
|
53
50
|
end
|
@@ -58,7 +55,7 @@ namespace :deploy do
|
|
58
55
|
# Overwrite :migrate to use docker
|
59
56
|
Rake::Task["deploy:migrate"].clear_actions
|
60
57
|
desc 'Runs rake db:migrate if migrations are set'
|
61
|
-
task :migrate => [:set_rails_env, 'deploy:check:postgres_running'] do
|
58
|
+
task :migrate => ['deployinator:load_settings', :set_rails_env, 'deploy:check:postgres_running'] do
|
62
59
|
on primary fetch(:migration_role) do |host|
|
63
60
|
conditionally_migrate = fetch(:conditionally_migrate)
|
64
61
|
info '[deploy:migrate] Checking changes in /db/migrate' if conditionally_migrate
|
@@ -72,17 +69,35 @@ namespace :deploy do
|
|
72
69
|
end
|
73
70
|
end
|
74
71
|
|
75
|
-
task :install_bundler do
|
72
|
+
task :install_bundler => 'deployinator:load_settings' do
|
76
73
|
on roles(:app) do |host|
|
77
74
|
unless file_exists?(shared_path.join('bundle', 'bin', 'bundle'))
|
78
75
|
deploy_install_bundler(host)
|
79
76
|
end
|
80
77
|
end
|
81
78
|
end
|
82
|
-
|
79
|
+
if Rake::Task.task_defined?("bundler:install")
|
80
|
+
before 'bundler:install', 'deploy:install_bundler'
|
81
|
+
end
|
82
|
+
|
83
|
+
task :install_database_yml => 'deployinator:load_settings' do
|
84
|
+
on roles(:app) do |host|
|
85
|
+
config_file = "database.yml"
|
86
|
+
template_path = File.expand_path("./#{fetch(:deploy_templates_path)}/#{config_file}.erb")
|
87
|
+
generated_config_file = ERB.new(File.new(template_path).read).result(binding)
|
88
|
+
set :final_path, -> { release_path.join('config', config_file) }
|
89
|
+
upload! StringIO.new(generated_config_file), "/tmp/#{config_file}"
|
90
|
+
execute("mv", "/tmp/#{config_file}", fetch(:final_path))
|
91
|
+
as :root do
|
92
|
+
execute("chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", fetch(:final_path))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
before 'deploy:updated', 'deploy:install_database_yml'
|
97
|
+
|
83
98
|
|
84
99
|
desc 'Restart application using bluepill restart inside the docker container.'
|
85
|
-
task :restart => [:install_config_files, 'deploy:check:settings'] do
|
100
|
+
task :restart => ['deployinator:load_settings', :install_config_files, 'deploy:check:settings'] do
|
86
101
|
on roles(:app) do |host|
|
87
102
|
name = fetch(:ruby_container_name)
|
88
103
|
if container_exists?(name)
|
@@ -98,7 +113,6 @@ namespace :deploy do
|
|
98
113
|
as :root do
|
99
114
|
execute("rm", "-f", fetch(:webserver_socket_path).join('unicorn.pid'))
|
100
115
|
end
|
101
|
-
warn "Starting a new container named #{name} on #{host}"
|
102
116
|
deploy_run_bluepill(host)
|
103
117
|
check_stayed_running(name)
|
104
118
|
end
|
@@ -106,9 +120,9 @@ namespace :deploy do
|
|
106
120
|
end
|
107
121
|
after :publishing, :restart
|
108
122
|
|
109
|
-
desc 'Restart application by recreating the docker container.'
|
110
123
|
namespace :restart do
|
111
|
-
|
124
|
+
desc 'Restart application by recreating the Docker container'
|
125
|
+
task :force => ['deployinator:load_settings', :install_config_files, 'deploy:check:settings'] do
|
112
126
|
on roles(:app) do |host|
|
113
127
|
name = fetch(:ruby_container_name)
|
114
128
|
if container_exists?(name)
|
@@ -125,7 +139,7 @@ namespace :deploy do
|
|
125
139
|
begin
|
126
140
|
execute("docker", "rm", name)
|
127
141
|
rescue
|
128
|
-
fatal "We were not able to remove the container for some reason. Try running 'cap <stage> deploy:restart:force' again."
|
142
|
+
fatal "We were not able to remove the container #{name} for some reason. Try running 'cap <stage> deploy:restart:force' again."
|
129
143
|
end
|
130
144
|
end
|
131
145
|
end
|
@@ -143,7 +157,7 @@ namespace :deploy do
|
|
143
157
|
# end
|
144
158
|
# end
|
145
159
|
|
146
|
-
task :install_config_files do
|
160
|
+
task :install_config_files => 'deployinator:load_settings' do
|
147
161
|
on roles(:app) do |host|
|
148
162
|
["bluepill.rb", "unicorn.rb"].each do |config_file|
|
149
163
|
template_path = File.expand_path("./#{fetch(:deploy_templates_path)}/#{config_file}.erb")
|
@@ -159,7 +173,7 @@ namespace :deploy do
|
|
159
173
|
end
|
160
174
|
|
161
175
|
desc "Enter the Rails console."
|
162
|
-
task :rails_console do
|
176
|
+
task :rails_console => 'deployinator:load_settings' do
|
163
177
|
on roles(:app) do |host|
|
164
178
|
info "Entering Rails Console inside #{fetch(:ruby_container_name)} on #{host}"
|
165
179
|
system deploy_rails_console(host)
|
@@ -167,7 +181,7 @@ namespace :deploy do
|
|
167
181
|
end
|
168
182
|
|
169
183
|
namespace :rails_console do
|
170
|
-
task :print do
|
184
|
+
task :print => 'deployinator:load_settings' do
|
171
185
|
on roles(:app) do |host|
|
172
186
|
info "You can SSH into #{host} and run the following command to enter the Rails Console."
|
173
187
|
info deploy_rails_console_print(host)
|
@@ -176,7 +190,7 @@ namespace :deploy do
|
|
176
190
|
end
|
177
191
|
|
178
192
|
desc "Write Version file on server"
|
179
|
-
|
193
|
+
task :write_version_file => 'deployinator:load_settings' do
|
180
194
|
on roles(:app) do |host|
|
181
195
|
execute "echo", "\"<version>", "<release>#{fetch(:current_revision)}</release>",
|
182
196
|
"<deployed_at>#{Time.now.strftime('%m/%d/%Y at %H:%M %Z')}</deployed_at>",
|
@@ -184,11 +198,46 @@ namespace :deploy do
|
|
184
198
|
"</version>\"", ">", current_path.join('public', 'version.xml')
|
185
199
|
end
|
186
200
|
end
|
201
|
+
after 'deploy:finished', 'deploy:write_version_file'
|
187
202
|
|
188
|
-
|
203
|
+
task :success_message => 'deployinator:load_settings' do
|
189
204
|
run_locally do
|
190
205
|
info "That was a successful deploy!"
|
191
206
|
end
|
192
207
|
end
|
208
|
+
after 'deploy:finished', 'deploy:success_message'
|
209
|
+
|
210
|
+
# the purpose of this task is to prevent hang during a bundle
|
211
|
+
# install that needs to reach github for the first time and will otherwise
|
212
|
+
# block asking "Are you sure you want to continue connecting (yes/no)?"
|
213
|
+
# this is only needed when deploying to a server for the first time using from_local=true.
|
214
|
+
task :add_repo_hostkeys => 'deployinator:load_settings' do
|
215
|
+
on roles(:app) do
|
216
|
+
if fetch(:repo_url).include? "@"
|
217
|
+
host = fetch(:repo_url).split(":").shift
|
218
|
+
socket = capture "echo", "$SSH_AUTH_SOCK"
|
219
|
+
with :ssh_auth_sock => socket do
|
220
|
+
if test(
|
221
|
+
"ssh", "-T", "-o", "StrictHostKeyChecking=no", "#{host};",
|
222
|
+
"EXIT_CODE=$?;",
|
223
|
+
"if", "[", "$EXIT_CODE", "-eq", "1", "];",
|
224
|
+
"then", "exit", "0;",
|
225
|
+
"else",
|
226
|
+
"exit", "$EXIT_CODE;",
|
227
|
+
"fi"
|
228
|
+
)
|
229
|
+
info "Successfully added #{host} to known host keys"
|
230
|
+
else
|
231
|
+
fatal "Not able to add #{host}'s ssh keys to the known hosts"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
else
|
235
|
+
warn "Repo URL does not appear to use SSH, not adding to known hosts"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
if Rake::Task.task_defined?("bundler:install")
|
240
|
+
before 'bundler:install', 'deploy:add_repo_hostkeys'
|
241
|
+
end
|
193
242
|
|
194
243
|
end
|
@@ -8,10 +8,16 @@ set :application, 'my_app_name'
|
|
8
8
|
set :preexisting_ssh_user, ENV['USER']
|
9
9
|
set :deployment_username, "deployer" # user with SSH access and passwordless sudo rights
|
10
10
|
set :webserver_username, "www-data" # less trusted web server user with limited write permissions
|
11
|
+
set :database_name, "db_name"
|
12
|
+
set :database_username, "db_username"
|
13
|
+
set :database_password, "db_password"
|
14
|
+
# All permissions changes are recursive, and unless overridden below,
|
15
|
+
# all folders will be "deployer www-data drwxr-s---",
|
16
|
+
# all files will be "deployer www-data -rw-r-----"
|
11
17
|
set :webserver_owned_dirs, [shared_path.join('tmp', 'cache'), shared_path.join('public', 'assets')]
|
12
18
|
set :webserver_writeable_dirs, [shared_path.join('run'), shared_path.join("tmp"), shared_path.join("log")]
|
13
19
|
set :webserver_executable_dirs, [shared_path.join("bundle", "bin")]
|
14
|
-
set :ignore_permissions_dirs, [shared_path.join("postgres"), shared_path.join("nginx")]
|
20
|
+
set :ignore_permissions_dirs, [shared_path.join("postgres"), shared_path.join("nginx"), "#{fetch(:deploy_to)}/releases"]
|
15
21
|
|
16
22
|
# Default value for linked_dirs is []
|
17
23
|
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
|
data/lib/deployinator/helpers.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
namespace :deployinator do
|
2
2
|
|
3
|
-
task :sshkit_umask do
|
3
|
+
task :sshkit_umask => 'deployinator:load_settings' do
|
4
4
|
SSHKit.config.umask = "0027"
|
5
5
|
end
|
6
|
+
before 'deploy:starting', 'deployinator:sshkit_umask'
|
6
7
|
|
7
|
-
task :settings, [:absolute_path, :relative_path] do |t, args|
|
8
|
+
task :settings, [:absolute_path, :relative_path] => 'deployinator:load_settings' do |t, args|
|
8
9
|
run_locally do
|
9
10
|
if fetch(:print_all)
|
10
11
|
lines = "\nThe following settings are needed in your config (#{args.relative_path}).\n"
|
@@ -33,7 +34,7 @@ end
|
|
33
34
|
|
34
35
|
|
35
36
|
def deployment_user_setup(templates_path)
|
36
|
-
require 'erb'
|
37
|
+
require 'erb'
|
37
38
|
name = fetch(:deployment_username)
|
38
39
|
unix_user_add(name) unless unix_user_exists?(name)
|
39
40
|
execute "usermod", "-a", "-G", "sudo,docker,#{fetch(:webserver_username)}", name
|
@@ -48,46 +49,75 @@ def deployment_user_setup(templates_path)
|
|
48
49
|
execute "chmod", "600", "/home/#{name}/.ssh/authorized_keys"
|
49
50
|
end
|
50
51
|
|
52
|
+
# TODO when replacing this method with the new one, make sure the releases dir itself gets permissioned, just not it's contents.
|
51
53
|
def setup_file_permissions
|
54
|
+
|
52
55
|
ignore_options = fetch(:ignore_permissions_dirs).collect do |dir|
|
53
56
|
["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
|
54
57
|
end
|
58
|
+
ignore_options += ["-not", "-path", "\"#{fetch(:deploy_to)}/releases/*\""]
|
55
59
|
chown_ignore_options = fetch(:webserver_owned_dirs).collect do |dir|
|
56
60
|
["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
|
57
61
|
end
|
62
|
+
|
58
63
|
# chown webserver owned
|
59
64
|
fetch(:webserver_owned_dirs).each do |dir|
|
60
65
|
if directory_exists?(dir)
|
61
66
|
execute "find", dir, ignore_options,
|
62
|
-
"-
|
67
|
+
'\(', "-not", "-user", fetch(:webserver_username), "-or",
|
68
|
+
"-not", "-group", fetch(:webserver_username), '\)',
|
69
|
+
"-print0", "|", "xargs", "--no-run-if-empty", "--null",
|
70
|
+
"chown", "#{fetch(:webserver_username)}:#{fetch(:webserver_username)}"
|
71
|
+
else
|
72
|
+
execute "mkdir", "-p", dir
|
73
|
+
execute "chown", "#{fetch(:webserver_username)}:#{fetch(:webserver_username)}", dir
|
63
74
|
end
|
64
75
|
end
|
76
|
+
|
65
77
|
# chown
|
66
78
|
execute "find", fetch(:deploy_to), ignore_options, chown_ignore_options,
|
67
|
-
"-
|
79
|
+
'\(', "-not", "-user", fetch(:deployment_username), "-or",
|
80
|
+
"-not", "-group", fetch(:webserver_username), '\)',
|
81
|
+
"-print0", "|", "xargs", "--no-run-if-empty", "--null",
|
82
|
+
"chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}"
|
83
|
+
|
68
84
|
# chmod executable
|
69
85
|
fetch(:webserver_executable_dirs).each do |dir|
|
70
86
|
if directory_exists?(dir)
|
71
87
|
execute "find", dir, "-type", "f",
|
72
|
-
"-
|
88
|
+
"-not", "-perm", "0750",
|
89
|
+
"-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "0750"
|
90
|
+
# else # don't do this mkdir because it gets run as root and doesn't chown parent dirs
|
91
|
+
# execute "mkdir", "-p", dir
|
92
|
+
# execute "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", dir
|
73
93
|
end
|
74
94
|
ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
|
75
95
|
end
|
96
|
+
|
76
97
|
# chmod writable
|
77
98
|
fetch(:webserver_writeable_dirs).each do |dir|
|
78
99
|
if directory_exists?(dir)
|
79
100
|
execute "find", "-L", dir, "-type", "d",
|
80
|
-
"-
|
101
|
+
"-not", "-perm", "2770",
|
102
|
+
"-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "2770"
|
81
103
|
execute "find", "-L", dir, "-type", "f",
|
82
|
-
"-
|
104
|
+
"-not", "-perm", "0660",
|
105
|
+
"-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "0660"
|
106
|
+
else
|
107
|
+
execute "mkdir", "-p", dir
|
108
|
+
execute "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", dir
|
109
|
+
execute "chmod", "2770", dir
|
83
110
|
end
|
84
111
|
ignore_options += ["-not", "-path", "\"#{dir}\"", "-not", "-path", "\"#{dir}/*\""]
|
85
112
|
end
|
113
|
+
|
86
114
|
# chmod
|
87
115
|
execute "find", fetch(:deploy_to), "-type", "d", ignore_options,
|
88
|
-
"-
|
116
|
+
"-not", "-perm", "2750",
|
117
|
+
"-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "2750"
|
89
118
|
execute "find", fetch(:deploy_to), "-type", "f", ignore_options,
|
90
|
-
"-
|
119
|
+
"-not", "-perm", "0640",
|
120
|
+
"-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "0640"
|
91
121
|
end
|
92
122
|
|
93
123
|
def container_exists?(container_name)
|
data/lib/deployinator/jobs.rb
CHANGED
@@ -2,7 +2,7 @@ namespace :deploy do
|
|
2
2
|
namespace :jobs do
|
3
3
|
|
4
4
|
desc 'Restart jobs using bluepill restart inside the docker container.'
|
5
|
-
task :restart => ['deploy:check:settings'] do
|
5
|
+
task :restart => ['deployinator:load_settings', 'deploy:check:settings'] do
|
6
6
|
on roles(:app) do |host|
|
7
7
|
name = fetch(:ruby_jobs_container_name)
|
8
8
|
if container_exists?(name)
|
@@ -24,11 +24,11 @@ namespace :deploy do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
|
-
after 'deploy:restart', :restart
|
27
|
+
after 'deploy:restart', 'deploy:jobs:restart'
|
28
28
|
|
29
29
|
desc 'Restart application by recreating the docker container.'
|
30
30
|
namespace :restart do
|
31
|
-
task :force => ['deploy:check:settings'] do
|
31
|
+
task :force => ['deployinator:load_settings', 'deploy:check:settings'] do
|
32
32
|
on roles(:app) do |host|
|
33
33
|
name = fetch(:ruby_jobs_container_name)
|
34
34
|
if container_exists?(name)
|
@@ -50,6 +50,7 @@ namespace :deploy do
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
53
|
+
before 'deploy:restart:force', 'deploy:jobs:restart:force'
|
53
54
|
|
54
55
|
end
|
55
56
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deployinator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-02-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: capistrano
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 3.2.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: net-ssh
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.9.4
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.9.4
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: rake
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,6 +94,7 @@ files:
|
|
78
94
|
- lib/deployinator/examples/Dockerfile
|
79
95
|
- lib/deployinator/examples/deployment_authorized_keys.erb
|
80
96
|
- lib/deployinator/examples/unicorn.rb.erb
|
97
|
+
- lib/deployinator/examples/database.yml.erb
|
81
98
|
- lib/deployinator/examples/bluepill.rb.erb
|
82
99
|
homepage: https://github.com/snarlysodboxer/deployinator
|
83
100
|
licenses:
|
@@ -106,3 +123,4 @@ signing_key:
|
|
106
123
|
specification_version: 3
|
107
124
|
summary: Deploy Applications
|
108
125
|
test_files: []
|
126
|
+
has_rdoc:
|