deployinator 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- # set :log_level, :debug
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
- 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
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("docker", "exec", "--tty",
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("docker", "exec", "--tty",
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("docker", "run", "--rm", "--tty", "--user", fetch(:webserver_username),
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("docker", "run", "--rm", "--tty",
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("docker", "run", "--rm", "--tty",
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("docker", "run", "--rm", "--tty", "--user", fetch(:deployment_username),
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
@@ -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
- before 'bundler:install', 'deploy:check:bundle_command_map'
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
- before 'deploy:started', :rm_command_map do
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
- before 'deploy:check', :settings do
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
- before 'deploy:check', :templates do
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
- before 'deploy:check', 'deployinator:deployment_user'
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
- before 'deploy:check', :postgres_running do
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
- before 'deploy:check', :ensure_cadvisor do
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
@@ -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
 
@@ -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
- before :starting, :set_branch do
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
- before 'bundler:install', 'deploy:copy_git'
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
- before 'bundler:install', 'deploy:install_bundler'
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
- task :force => [:install_config_files, 'deploy:check:settings'] do
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
- after 'deploy:finished', :write_version_file do
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
- after 'deploy:finished', :success_message do
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}
@@ -0,0 +1,10 @@
1
+ ---
2
+ production:
3
+ adapter: postgresql
4
+ database: <%= fetch(:database_name) %>
5
+ username: <%= fetch(:database_username) %>
6
+ password: <%= fetch(:database_password) %>
7
+ host: <%= fetch(:postgres_socket_path) %>
8
+ pool: 5
9
+ encoding: UTF8
10
+ timeout: 500
@@ -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' unless defined?(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
- "-exec", "chown", "#{fetch(:webserver_username)}:#{fetch(:webserver_username)}", "{}", "+"
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
- "-exec", "chown", "#{fetch(:deployment_username)}:#{fetch(:webserver_username)}", "{}", "+"
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
- "-exec", "chmod", "0750", "{}", "+"
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
- "-exec", "chmod", "2770", "{}", "+"
101
+ "-not", "-perm", "2770",
102
+ "-print0", "|", "xargs", "--no-run-if-empty", "--null", "chmod", "2770"
81
103
  execute "find", "-L", dir, "-type", "f",
82
- "-exec", "chmod", "0660", "{}", "+"
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
- "-exec", "chmod", "2750", "{}", "+"
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
- "-exec", "chmod", "0640", "{}", "+"
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)
@@ -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.5
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: 2015-01-30 00:00:00.000000000 Z
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: