capistrano-cookbook 5.0.0 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6196d2ecf217984aa66e19657b8ebfd58b0202b70d5c33bbcdf7b3e5385ccddd
4
- data.tar.gz: 84eaad2671892ed175d1cc8e605fb7f7a935a484a310d3ae8a29355acee50050
3
+ metadata.gz: ccf86ecd4d2c04f71dd86f6aaf38877d57c1b7482e21435986b58dcbd768e18c
4
+ data.tar.gz: 1a9f6bc210c07faf2c998ad13f438b97ac4efbccdb3734993e173f94cf7953be
5
5
  SHA512:
6
- metadata.gz: 11507790fa3e84d2897565a729714cbe766b97e1d33169bd796901ac26fefdf4fc01253df4508d5a9929cb6fafdbe5397e8214a10abdb4484685409d62515b09
7
- data.tar.gz: 0e218729f6040493dc87f900e8af733c31fa913ee1ac916d7da0138c459efe6a23cd6163871a308c1b4efcdcc8f55d967c9e111223398ac0f01f782f49dbf47a
6
+ metadata.gz: 936557739c95b9b6c4d2f7bc92fa300778437e0c335b84670c7b4d9e67dce28daa65196f0713cf2e9babdb3fe913777c181bf5587f9378880b4567f091453893
7
+ data.tar.gz: e55cb0581cfdde734cdea13b675ccb89aea40f1fab79c1280b1eda86590b37fb0cb3c22af6565d56e94d7fb4466b80d6823cb398ccb39d5b16e4277bd85066a2
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 5.0.1 (March 2021)
4
+
5
+ - Adds full support for deploy (but not config creation) without sudo access
6
+ - Refactor config files to use single array of hashes with flags
7
+ - Refactor Sidekiq and Monit configurations to copy files directly rather than using symlinks to avoid potential root access leak
8
+ - Fixes bug where object identifier was outputted in logs rather than filename
9
+ - Fixes nginx not being reloaded after `setup_config` due to shared log directory not yet existing
10
+
11
+ ## 5.0.0 (March 2021)
12
+
13
+ - Full overhaul to support Rails 6 and Ubuntu 20.04
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
 
20
20
  spec.add_dependency 'capistrano', '~> 3.16'
21
21
  spec.add_dependency 'capistrano3-puma', '~> 5.0.4'
22
+ spec.add_dependency 'capistrano-sidekiq', '~> 2.0'
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.5"
24
25
  spec.add_development_dependency "rake"
@@ -9,6 +9,7 @@ module Capistrano
9
9
  require 'capistrano/cookbook/run_tests'
10
10
  require 'capistrano/cookbook/setup_config'
11
11
  require 'capistrano/cookbook/create_database'
12
- require 'capistrano/cookbook/systemd'
12
+ require 'capistrano/cookbook/puma_systemd'
13
+ require 'capistrano/cookbook/sidekiq_systemd'
13
14
  end
14
15
  end
@@ -1,59 +1,46 @@
1
1
  module Capistrano
2
2
  module Cookbook
3
3
  class SetupConfigValues
4
- def symlinks
5
- fetch(:symlinks) || symlinks_defaults
6
- end
7
-
8
- def executable_config_files
9
- fetch(:executable_config_files) || executable_config_files_defaults
10
- end
11
-
12
4
  def config_files
13
5
  fetch(:config_files) || config_files_defaults
14
6
  end
15
7
 
16
8
  private
17
9
 
18
- def symlinks_defaults
10
+ def config_files_defaults
19
11
  base = [
20
12
  {
21
- source: "log_rotation",
22
- link: "/etc/logrotate.d/{{full_app_name}}"
13
+ source: 'log_rotation',
14
+ destination: "/etc/logrotate.d/#{fetch(:full_app_name)}",
15
+ executable: false,
16
+ as_root: true
17
+ },
18
+ {
19
+ source: 'database.example.yml',
20
+ destination: "#{shared_path}/config/database.example.yml",
21
+ executable: false,
22
+ as_root: false
23
23
  }
24
24
  ]
25
+
25
26
  return base unless sidekiq_enabled?
26
27
 
27
28
  base + [
28
29
  {
29
- source: "sidekiq.service.capistrano",
30
- link: "/etc/systemd/system/#{fetch(:sidekiq_service_unit_name)}.service"
30
+ source: 'sidekiq.service.capistrano',
31
+ destination: "/home/#{fetch(:deploy_user)}/.config/systemd/user/#{fetch(:sidekiq_service_unit_name)}.service",
32
+ executable: false,
33
+ as_root: false
31
34
  },
32
35
  {
33
36
  source: "sidekiq_monit",
34
- link: "/etc/monit/conf.d/#{fetch(:full_app_name)}_sidekiq.conf"
37
+ destination: "/etc/monit/conf.d/#{fetch(:full_app_name)}_sidekiq.conf",
38
+ executable: false,
39
+ as_root: true
35
40
  }
36
41
  ]
37
42
  end
38
43
 
39
- def executable_config_files_defaults
40
- %w(
41
- )
42
- end
43
-
44
- def config_files_defaults
45
- base = %w(
46
- database.example.yml
47
- log_rotation
48
- )
49
- return base unless sidekiq_enabled?
50
-
51
- base + %w(
52
- sidekiq.service.capistrano
53
- sidekiq_monit
54
- )
55
- end
56
-
57
44
  def sidekiq_enabled?
58
45
  defined?(Capistrano::Sidekiq) == 'constant' && Capistrano::Sidekiq.class == Class
59
46
  end
@@ -1,3 +1,6 @@
1
+ require 'securerandom'
2
+ require 'stringio'
3
+
1
4
  # will first try and copy the file:
2
5
  # config/deploy/#{full_app_name}/#{from}.erb
3
6
  # to:
@@ -11,13 +14,12 @@
11
14
  # ones to be over-ridden
12
15
  # if the target file name is the same as the source then
13
16
  # the second parameter can be left out
14
- def smart_template(from, to=nil)
15
- to ||= from
16
- full_to_path = "#{shared_path}/config/#{to}"
17
+ def smart_template(from, to, as_root=false)
17
18
  if from_erb_path = template_file(from)
18
19
  from_erb = StringIO.new(ERB.new(File.read(from_erb_path)).result(binding))
19
- upload! from_erb, full_to_path
20
- info "copying: #{from_erb} to: #{full_to_path}"
20
+ upload!(from_erb, to) unless as_root
21
+ sudo_upload!(from_erb, to) if as_root
22
+ info "copying: #{from} to: #{to}"
21
23
  else
22
24
  error "error #{from} not found"
23
25
  end
@@ -35,3 +37,14 @@ def template_file(name)
35
37
  end
36
38
  return nil
37
39
  end
40
+
41
+ def sudo_upload!(file_path, remote_path, mode: '644', owner: 'root:root')
42
+ tmp_path = "/tmp/#{SecureRandom.uuid}"
43
+
44
+ upload!(file_path, tmp_path)
45
+
46
+ execute(:sudo, :mkdir, '-p', File.dirname(remote_path))
47
+ execute(:sudo, :mv, '-f', tmp_path, remote_path)
48
+ execute(:sudo, :chmod, mode, remote_path)
49
+ execute(:sudo, :chown, owner, remote_path)
50
+ end
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/puma_systemd.cap", File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ load File.expand_path("tasks/sidekiq_systemd.cap", File.dirname(__FILE__))
@@ -3,7 +3,7 @@ namespace :nginx do
3
3
  desc "#{task } Nginx"
4
4
  task task_name do
5
5
  on roles(:app), in: :sequence, wait: 5 do
6
- sudo "/etc/init.d/nginx #{task_name}"
6
+ sudo "systemctl #{task_name} nginx"
7
7
  end
8
8
  end
9
9
  end
@@ -6,8 +6,8 @@ namespace :puma do
6
6
  if fetch(:puma_systemctl_user) == :system
7
7
  sudo "#{fetch(:puma_systemctl_bin)} reload-or-restart #{fetch(:puma_service_unit_name)}"
8
8
  else
9
- execute "#{fetch(:puma_systemctl_bin)}", "--user", "reload", fetch(:puma_service_unit_name)
10
9
  execute :loginctl, "enable-linger", fetch(:puma_lingering_user) if fetch(:puma_enable_lingering)
10
+ execute "#{fetch(:puma_systemctl_bin)}", "--user", "reload-or-restart", fetch(:puma_service_unit_name)
11
11
  end
12
12
  end
13
13
  end
@@ -1,7 +1,7 @@
1
1
  require 'capistrano/dsl'
2
2
  require 'capistrano/cookbook/helpers/setup_config_values'
3
3
  require 'capistrano/cookbook/helpers/substitute_strings'
4
- require 'capistrano/cookbook/helpers/template'
4
+ require 'capistrano/cookbook/helpers/smart_template'
5
5
  require 'capistrano/cookbook/nginx'
6
6
  require 'capistrano/cookbook/monit'
7
7
  require 'securerandom'
@@ -13,22 +13,24 @@ namespace :deploy do
13
13
  on roles(:app) do
14
14
  # make the config dir
15
15
  execute :mkdir, "-p #{shared_path}/config"
16
+ execute :mkdir, "-p /home/#{fetch(:deploy_user)}/.config/systemd/user"
16
17
 
17
18
  # config files to be uploaded to shared/config, see the
18
19
  # definition of smart_template for details of operation.
19
20
  conf.config_files.each do |file|
20
- smart_template file
21
+ smart_template(file[:source], file[:destination], file[:as_root])
22
+ execute(:chmod, "+x #{file[:destination]}") if file[:executable]
21
23
  end
22
24
 
23
25
  # which of the above files should be marked as executable
24
- conf.executable_config_files.each do |file|
25
- execute :chmod, "+x #{shared_path}/config/#{file}"
26
- end
26
+ # conf.executable_config_files.each do |file|
27
+ # execute :chmod, "+x #{shared_path}/config/#{file}"
28
+ # end
27
29
 
28
30
  # symlink stuff which should be... symlinked
29
- conf.symlinks.each do |symlink|
30
- sudo "ln -nfs #{shared_path}/config/#{symlink[:source]} #{sub_strings(symlink[:link])}"
31
- end
31
+ # conf.symlinks.each do |symlink|
32
+ # sudo "ln -nfs #{shared_path}/config/#{symlink[:source]} #{sub_strings(symlink[:link])}"
33
+ # end
32
34
 
33
35
  if File.exists?(File.join('config', 'master.key'))
34
36
  upload! File.join('config', 'master.key'), File.join(shared_path, 'config', 'master.key')
@@ -41,6 +43,12 @@ end
41
43
  # remove the default nginx configuration as it will tend to conflict with our configs
42
44
  before 'deploy:setup_config', 'nginx:remove_default_vhost'
43
45
 
46
+ # make sure that shared directories etc exist before running otherwise the
47
+ # initial nginx reload won't work because of the nginx log file directory path
48
+ # not existing
49
+ before 'deploy:setup_config', 'deploy:check:directories'
50
+ before 'deploy:setup_config', 'deploy:check:linked_dirs'
51
+
44
52
  # After setup config has generated and setup initial files, run the Capistrano Puma
45
53
  # tasks responsible for uploading config files. Note that `setup_config` creates overrides
46
54
  # for these in `config/deploy/templates` so we're not using the default ones from the gem
@@ -48,6 +56,10 @@ after 'deploy:setup_config', 'puma:config'
48
56
  after 'deploy:setup_config', 'puma:nginx_config'
49
57
  after 'deploy:setup_config', 'puma:monit:config'
50
58
  after 'deploy:setup_config', 'puma:systemd:config'
59
+ after 'deploy:setup_config', 'puma:systemd:enable'
60
+
61
+ # Enable the sidekiq systemd service so that it's started automatically on (re)boot
62
+ after 'deploy:setup_config', 'sidekiq:systemd:enable' if (defined?(Capistrano::Sidekiq) == 'constant' && Capistrano::Sidekiq.class == Class)
51
63
 
52
64
  # reload nginx to it will pick up any modified vhosts from setup_config
53
65
  after 'deploy:setup_config', 'nginx:reload'
@@ -0,0 +1,15 @@
1
+ namespace :sidekiq do
2
+ namespace :systemd do
3
+ desc 'Install systemd sidekiq service'
4
+ task :enable do
5
+ on roles fetch(:sidekiq_roles) do |role|
6
+ if fetch(:sidekiq_service_unit_user) == :system
7
+ execute :sudo, :systemctl, "enable", fetch(:sidekiq_service_unit_name)
8
+ else
9
+ execute :systemctl, "--user", "enable", fetch(:sidekiq_service_unit_name)
10
+ execute :loginctl, "enable-linger", fetch(:sidekiq_systemctl_user) if fetch(:sidekiq_enable_lingering)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  module Capistrano
2
2
  module Cookbook
3
- VERSION = "5.0.0"
3
+ VERSION = "5.0.1"
4
4
  end
5
5
  end
@@ -13,20 +13,19 @@ set :rbenv_ruby, '3.0.0'
13
13
  set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
14
14
  set :rbenv_map_bins, %w{rake gem bundle ruby rails}
15
15
 
16
- <% if @generate_sidekiq %>
17
- # Setup sidekiq, make sure we run sidekiq as our deployment user, otherwise
18
- # it will default to root which a) is insecture and b) will lead to lots of
19
- # strange permissions issues
20
- set :sidekiq_service_unit_user, :system
21
- set :sidekiq_user, fetch(:deploy_user)
22
- <% end %>
23
-
24
16
  # setup puma to operate in clustered mode, required for zero downtime deploys
25
17
  set :puma_preload_app, false
26
18
  set :puma_init_active_record, true
27
19
  set :puma_workers, 3
20
+ set :puma_systemctl_user, fetch(:deploy_user)
21
+ set :puma_enable_lingering, true
22
+
23
+ <% if @generate_sidekiq %>
24
+ set :sidekiq_systemctl_user, fetch(:deploy_user)
25
+ set :sidekiq_enable_lingering, true
26
+ <% end %>
28
27
 
29
- # how many old releases do we want to keep, not much
28
+ # how many old releases do we want to keep
30
29
  set :keep_releases, 5
31
30
 
32
31
  # Directories that should be linked to the shared folder
@@ -14,7 +14,7 @@ set :full_app_name, "#{fetch(:application)}_#{fetch(:stage)}"
14
14
  <% if @generate_sidekiq %>
15
15
  # Name sidekiq systemd service after the app and stage name so that
16
16
  # multiple apps and stages can co-exist on the same machine if needed
17
- set :sidekiq_service_unit_name, "#{fetch(:full_app_name)}_sidekiq"
17
+ set :sidekiq_service_unit_name, "sidekiq_#{fetch(:full_app_name)}"
18
18
  <% end %>
19
19
 
20
20
  server '<%= @production_server_address %>', user: 'deploy', roles: %w{web app db}, primary: true
@@ -1,7 +1,4 @@
1
- # Monit configuration for Puma
2
- # Service name: <%= puma_monit_service_name %>
3
- #
4
1
  check process <%= puma_monit_service_name %>
5
2
  with pidfile "<%= fetch(:puma_pid) %>"
6
- start program = "/usr/bin/systemctl start <%= fetch(:puma_service_unit_name) %>"
7
- stop program = "/usr/bin/systemctl stop <%= fetch(:puma_service_unit_name) %>"
3
+ start program = "/bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$(id -u) /usr/bin/systemctl start --user <%= fetch(:puma_service_unit_name) %>'" as uid "<%= fetch(:puma_systemctl_user) %>" and gid "<%= fetch(:puma_systemctl_user) %>"
4
+ stop program = "/bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$(id -u) /usr/bin/systemctl stop --user <%= fetch(:puma_service_unit_name) %>'" as uid "<%= fetch(:puma_systemctl_user) %>" and gid "<%= fetch(:puma_systemctl_user) %>"
@@ -1,5 +1,3 @@
1
- <% # Adapted from: https://github.com/seuros/capistrano-sidekiq/blob/master/lib/generators/capistrano/sidekiq/systemd/templates/sidekiq.service.capistrano.erb %>
2
-
3
1
  [Unit]
4
2
  Description=sidekiq for <%= "#{fetch(:application)} (#{fetch(:stage)})" %>
5
3
  After=syslog.target network.target
@@ -12,7 +10,7 @@ ExecReload=/bin/kill -TSTP $MAINPID
12
10
  ExecStop=/bin/kill -TERM $MAINPID
13
11
  <%="StandardOutput=append:#{fetch(:sidekiq_log)}" if fetch(:sidekiq_log) %>
14
12
  <%="StandardError=append:#{fetch(:sidekiq_error_log)}" if fetch(:sidekiq_error_log) %>
15
- <%="User=#{fetch(:sidekiq_user)}" if fetch(:sidekiq_user) %>
13
+ <%="User=#{fetch(:sidekiq_user)}" if (fetch(:sidekiq_user) && (fetch(:puma_systemctl_user) == :system)) %>
16
14
  <%="EnvironmentFile=#{fetch(:sidekiq_service_unit_env_file)}" if fetch(:sidekiq_service_unit_env_file) %>
17
15
  <% fetch(:sidekiq_service_unit_env_vars, []).each do |environment_variable| %>
18
16
  <%="Environment=#{environment_variable}" %>
@@ -27,4 +25,6 @@ Restart=on-failure
27
25
  SyslogIdentifier=sidekiq_<%= fetch(:application) %>_<%= fetch(:stage) %>
28
26
 
29
27
  [Install]
30
- WantedBy=default.target
28
+ WantedBy=<%=(fetch(:sidekiq_systemctl_user) == :system) ? "multi-user.target" : "default.target"%>
29
+
30
+ <% # Adapted from: https://github.com/seuros/capistrano-sidekiq/blob/master/lib/generators/capistrano/sidekiq/systemd/templates/sidekiq.service.capistrano.erb %>
@@ -1,4 +1,4 @@
1
1
  check process <%= fetch(:sidekiq_service_unit_name) %> matching "sidekiq.*<%= fetch(:full_app_name) %>"
2
- start program = "/usr/bin/systemctl start <%= fetch(:sidekiq_service_unit_name) %>"
3
- stop program = "/usr/bin/systemctl stop <%= fetch(:sidekiq_service_unit_name) %>"
2
+ start program = "/bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$(id -u) /usr/bin/systemctl start --user <%= fetch(:sidekiq_service_unit_name) %>'" as uid "<%= fetch(:sidekiq_systemctl_user) %>" and gid "<%= fetch(:sidekiq_systemctl_user) %>"
3
+ stop program = "/bin/bash -c 'XDG_RUNTIME_DIR=/run/user/$(id -u) /usr/bin/systemctl stop --user <%= fetch(:sidekiq_service_unit_name) %>'" as uid "<%= fetch(:sidekiq_systemctl_user) %>" and gid "<%= fetch(:sidekiq_systemctl_user) %>"
4
4
  group <%= fetch(:sidekiq_monit_group) || fetch(:full_app_name) %>-sidekiq
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-cookbook
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Dixon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-18 00:00:00.000000000 Z
11
+ date: 2021-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capistrano
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 5.0.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: capistrano-sidekiq
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -74,6 +88,7 @@ extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
90
  - ".gitignore"
91
+ - CHANGELOG.md
77
92
  - Gemfile
78
93
  - LICENSE.txt
79
94
  - README.md
@@ -86,23 +101,25 @@ files:
86
101
  - lib/capistrano/cookbook/compile_assets_locally.rb
87
102
  - lib/capistrano/cookbook/create_database.rb
88
103
  - lib/capistrano/cookbook/helpers/setup_config_values.rb
104
+ - lib/capistrano/cookbook/helpers/smart_template.rb
89
105
  - lib/capistrano/cookbook/helpers/substitute_strings.rb
90
- - lib/capistrano/cookbook/helpers/template.rb
91
106
  - lib/capistrano/cookbook/logs.rb
92
107
  - lib/capistrano/cookbook/monit.rb
93
108
  - lib/capistrano/cookbook/nginx.rb
109
+ - lib/capistrano/cookbook/puma_systemd.rb
94
110
  - lib/capistrano/cookbook/run_tests.rb
95
111
  - lib/capistrano/cookbook/setup_config.rb
96
- - lib/capistrano/cookbook/systemd.rb
112
+ - lib/capistrano/cookbook/sidekiq_systemd.rb
97
113
  - lib/capistrano/cookbook/tasks/check_revision.cap
98
114
  - lib/capistrano/cookbook/tasks/compile_assets_locally.cap
99
115
  - lib/capistrano/cookbook/tasks/create_database.cap
100
116
  - lib/capistrano/cookbook/tasks/logs.cap
101
117
  - lib/capistrano/cookbook/tasks/monit.cap
102
118
  - lib/capistrano/cookbook/tasks/nginx.cap
119
+ - lib/capistrano/cookbook/tasks/puma_systemd.cap
103
120
  - lib/capistrano/cookbook/tasks/run_tests.cap
104
121
  - lib/capistrano/cookbook/tasks/setup_config.cap
105
- - lib/capistrano/cookbook/tasks/systemd.cap
122
+ - lib/capistrano/cookbook/tasks/sidekiq_systemd.cap
106
123
  - lib/capistrano/cookbook/templates/database.example.yml.erb
107
124
  - lib/capistrano/cookbook/templates/log_rotation.erb
108
125
  - lib/capistrano/cookbook/templates/sidekiq.yml.erb
@@ -1 +0,0 @@
1
- load File.expand_path("tasks/systemd.cap", File.dirname(__FILE__))