deployinator 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: