capistrano-cookbook 5.0.0 → 5.0.1

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.
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__))