poise-service 1.0.2 → 1.0.3

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
  SHA1:
3
- metadata.gz: f3fc72bef39422fae1951da15292b19f8197a71b
4
- data.tar.gz: 2aa9c8a1eb8d6808b0e591ff8a2aabfdc3360ad3
3
+ metadata.gz: 9083e6c7faa81f26cb75ba512932747ca7d78505
4
+ data.tar.gz: 1cf6379abe8c39cafb38b7d7b5812db1fa24c9d4
5
5
  SHA512:
6
- metadata.gz: 84418165ab96792da66819398e11360890259d764e2f9ecfe93ac1ce85d9e0b176d44b66e3a20cb66da20f1a6f40535910e864f83e26eec76f60f037a1f7c510
7
- data.tar.gz: e4aea2a2c486514982693e15d3d3e1d8e5d71bebce16366c45587e3fc9cbb374d95d13b8d61e26495cd34b3339de41a13f8dbaccc9ab15e1e9951577fd9a5345
6
+ metadata.gz: 475915c90a841a1f8ebadfbf48074440dc2b202a0902c8b50cd362bf2dd523feec27f60d010d9fdc46d6b60079343b53b4d56aa3f96243c1d4c7806c644f370e
7
+ data.tar.gz: 8ee09393fc20251559c2c275e7bc7cb56b12dc0d091e85ec66c7f6983f263c9a4490a9c888a1b856dfe7b56e54247846f85565d7ef0d23bd47a6afbd88ce2995
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  #<% require 'poise_boiler' %>
3
- <%= PoiseBoiler.kitchen(platforms: 'linux') %>
3
+ <%= PoiseBoiler.kitchen(platforms: %w{linux centos-5}) %>
4
4
 
5
5
  suites:
6
6
  - name: default
@@ -1,6 +1,13 @@
1
- # Changelog
1
+ # Poise-Service Changelog
2
+
3
+ ## v1.0.3
4
+
5
+ * [#10](https://github.com/poise/poise-service/pull/10) Fixes for ensuring services are restarted when their command or user changes.
6
+ * [#11](https://github.com/poise/poise-service/pull/11) Revamp the `sysvinit` provider for non-Debian platforms to be more stable.
7
+ * [#12](https://github.com/poise/poise-service/pull/12) Improve the `dummy` provider to handle dropping privs correctly.
2
8
 
3
9
  ## v1.0.2
10
+
4
11
  * Fix a potential infinite loop when starting a service with the dummy provider.
5
12
  * [#2](https://github.com/poise/poise-service/pull/2) Remove usage of root
6
13
  default files so uploading with Berkshelf works (for now).
data/README.md CHANGED
@@ -315,6 +315,7 @@ end
315
315
  * `user` – Override the service user.
316
316
  * `never_restart` – Never try to restart the service.
317
317
  * `never_reload` – Never try to reload the service.
318
+ * `auto_reload` – Run `systemctl daemon-reload` after changes to the unit file. *(default: true)*
318
319
 
319
320
  ## ServiceMixin
320
321
 
@@ -0,0 +1,7 @@
1
+ <%= {command: @command,
2
+ directory: @directory,
3
+ environment: @environment,
4
+ name: @name,
5
+ reload_signal: @reload_signal,
6
+ stop_signal: @stop_signal,
7
+ user: @user}.to_json %>
@@ -11,10 +11,6 @@
11
11
  # Description: Init script for <%= @name %>
12
12
  ### END INIT INFO
13
13
 
14
- <%- @environment.each do |key, val| -%>
15
- export <%= key %>="<%= val %>"
16
- <%- end -%>
17
-
18
14
  <%- if @platform_family == 'debian' -%>
19
15
  . /lib/lsb/init-functions
20
16
 
@@ -37,32 +33,42 @@ _reload() {
37
33
  start-stop-daemon --stop --quiet --pidfile "<%= @pid_file %>" --user "<%= @user %>" --signal "<%= @reload_signal %>"
38
34
  }
39
35
 
40
- <%- elsif @platform_family == 'rhel' -%>
41
- . /etc/rc.d/init.d/functions
42
-
43
- _pid () {
44
- pidof -s -o $$ -o $PPID -o %PPID -x "$1" || pidof -s -o $$ -o $PPID -o %PPID -x "${1##*/}"
45
- }
46
-
36
+ <%- else -%>
47
37
  _start() {
48
- ( cd "<%= @directory %>" && daemon --user "<%= @user %>" --pidfile "<%= @pid_file %>" "<%= @daemon %> <%= @daemon_options %>" >/dev/null 2>&1 ) &
49
- <%- unless @pid_file_external -%>
50
- sleep 1 # Give it some time to start before checking for a pid
51
- _pid "<%= @daemon %>" > "<%= @pid_file %>" || return 3
52
- <%- end -%>
53
- return 0 # ¯\_(ツ)_/¯
38
+ <%# Implementing this using RedHat's bash helpers is too painful. Sorry. %>
39
+ <%# See dummy.rb for a more commented version of this code. %>
40
+ /opt/chef/embedded/bin/ruby <<EOH
41
+ pid_file = <%= @pid_file.inspect %>
42
+ File.unlink(pid_file) if File.exist?(pid_file)
43
+ if Process.fork
44
+ sleep(1) until File.exist?(pid_file)
45
+ else
46
+ Process.daemon(true)
47
+ Dir.chdir(<%= @directory.inspect %>)
48
+ <%- unless @pid_file_external -%>
49
+ IO.write(pid_file, Process.pid)
50
+ <%- end -%>
51
+ Process::UID.change_privilege(<%= @user.inspect %>)
52
+ Kernel.exec(*<%= Shellwords.split(@command).inspect %>)
53
+ exit!
54
+ end
55
+ EOH
54
56
  }
55
57
 
56
58
  _stop() {
57
59
  if [ -r "<%= @pid_file %>" ]; then
58
60
  kill -<%= @stop_signal%> "$(cat "<%= @pid_file %>")"
59
61
  else
60
- killproc "<%= @daemon %>" -<%= @stop_signal%> >/dev/null
62
+ return 0
61
63
  fi
62
64
  }
63
65
 
64
66
  _status() {
65
- status -p "<%= @pid_file %>" "<%= @daemon %>"
67
+ if [ -r "<%= @pid_file %>" ]; then
68
+ kill -0 "$(cat "<%= @pid_file %>")"
69
+ else
70
+ return 1
71
+ fi
66
72
  }
67
73
 
68
74
  _reload() {
@@ -73,7 +79,7 @@ _reload() {
73
79
  fi
74
80
  }
75
81
 
76
- <%- # Some functions to match LSB because RHEL doesn't (╯°□°)╯︵ ┻━┻ -%>
82
+ <%# Some functions to match LSB %>
77
83
 
78
84
  log_daemon_msg() {
79
85
  echo -n "$1"
@@ -93,13 +99,11 @@ log_failure_msg() {
93
99
 
94
100
  log_end_msg() {
95
101
  if [ "$1" = 0 ]; then
96
- success
102
+ echo " [ OK ]"
97
103
  else
98
- failure
104
+ echo " [FAILED]"
99
105
  fi
100
106
  }
101
- <%- else -%>
102
- <%- raise "Platform family #{@platform_family} is not supported" -%>
103
107
  <%- end -%>
104
108
 
105
109
  set -e
@@ -124,6 +128,9 @@ start() {
124
128
  fi
125
129
  }
126
130
 
131
+ <%- @environment.each do |key, val| -%>
132
+ export <%= key %>="<%= val %>"
133
+ <%- end -%>
127
134
  export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
128
135
 
129
136
  case "$1" in
@@ -25,7 +25,7 @@ reload signal <%= @reload_signal %>
25
25
  <%- if @upstart_features[:setuid] -%>
26
26
  exec <%= @command %>
27
27
  <%- else -%>
28
- exec /opt/chef/embedded/bin/ruby -e 'Process.uid = "<%= @user %>"; ENV["HOME"] = Dir.home("<%= @user %>") rescue nil; exec(*<%= Shellwords.split(@command).inspect %>)'
28
+ exec /opt/chef/embedded/bin/ruby -e 'Process::UID.change_privilege("<%= @user %>"); ENV["HOME"] = Dir.home("<%= @user %>") rescue nil; exec(*<%= Shellwords.split(@command).inspect %>)'
29
29
  <%- end -%>
30
30
  <%- if !@upstart_features[:kill_signal] && @stop_signal != 'TERM' -%>
31
31
  pre-stop script
@@ -187,12 +187,26 @@ EOH
187
187
  end
188
188
  end
189
189
 
190
+ # Test the #pid accessor.
190
191
  ruby_block "/tmp/poise_test_#{new_resource.name}_pid" do
191
192
  block do
192
193
  pid = resources("poise_service[poise_test_#{new_resource.name}]").pid
193
194
  IO.write("/tmp/poise_test_#{new_resource.name}_pid", pid.to_s)
194
195
  end
195
196
  end
197
+
198
+ # Test changing the service definition itself.
199
+ poise_service "poise_test_#{new_resource.name}_change" do
200
+ provider new_resource.service_provider if new_resource.service_provider
201
+ command "/usr/bin/poise_test #{new_resource.base_port + 5}"
202
+ end
203
+
204
+ poise_service "poise_test_#{new_resource.name}_change_second" do
205
+ service_name "poise_test_#{new_resource.name}_change"
206
+ provider new_resource.service_provider if new_resource.service_provider
207
+ command "/usr/bin/poise_test #{new_resource.base_port + 6}"
208
+ end
209
+
196
210
  end
197
211
  end
198
212
  end
@@ -14,6 +14,8 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ require 'shellwords'
18
+
17
19
  require 'poise_service/service_providers/base'
18
20
 
19
21
 
@@ -29,9 +31,16 @@ module PoiseService
29
31
  ::File.unlink(pid_file) if ::File.exist?(pid_file)
30
32
  if Process.fork
31
33
  # Parent, wait for the final child to write the pid file.
34
+ now = Time.now
32
35
  until ::File.exist?(pid_file)
33
36
  sleep(1)
34
- Chef::Log.debug("[#{new_resource}] Waiting for PID file")
37
+ # After 30 seconds, show output at a higher level to avoid too much
38
+ # confusing on failed process launches.
39
+ if Time.now - now <= 30
40
+ Chef::Log.debug("[#{new_resource}] Waiting for PID file")
41
+ else
42
+ Chef::Log.warning("[#{new_resource}] Waiting for PID file at #{pid_file} to be created")
43
+ end
35
44
  end
36
45
  else
37
46
  # :nocov:
@@ -42,14 +51,17 @@ module PoiseService
42
51
  # Daemonized, set up process environment.
43
52
  Dir.chdir(new_resource.directory)
44
53
  Chef::Log.debug("[#{new_resource}] Directory changed to #{new_resource.directory}")
54
+ ENV['HOME'] = Dir.home(new_resource.user)
45
55
  new_resource.environment.each do |key, val|
46
56
  ENV[key.to_s] = val.to_s
47
57
  end
48
- Process.uid = new_resource.user
49
58
  Chef::Log.debug("[#{new_resource}] Process environment configured")
50
59
  IO.write(pid_file, Process.pid)
51
- Chef::Log.debug("[#{new_resource}] PID written to #{pid_file}, execing #{new_resource.command}")
52
- Kernel.exec(new_resource.command)
60
+ Chef::Log.debug("[#{new_resource}] PID written to #{pid_file}, dropping privs and execing")
61
+ Process::UID.change_privilege(new_resource.user)
62
+ # Split the command so we don't get an extra sh -c.
63
+ Chef::Log.debug("[#{new_resource}] Execing #{new_resource.command}")
64
+ Kernel.exec(*Shellwords.split(new_resource.command))
53
65
  # Just in case, bail out.
54
66
  exit!
55
67
  # :nocov:
@@ -94,15 +106,34 @@ module PoiseService
94
106
  def enable_service
95
107
  end
96
108
 
109
+ # Write all major service parameters to a file so that if they change, we
110
+ # can restart the service. This also makes debuggin a bit easier so you
111
+ # can still see what it thinks it was starting without sifting through
112
+ # piles of debug output.
97
113
  def create_service
114
+ service_template(run_file, 'dummy.json.erb')
98
115
  end
99
116
 
100
117
  def disable_service
101
118
  end
102
119
 
120
+ # Delete the tracking file.
103
121
  def destroy_service
122
+ file run_file do
123
+ action :delete
124
+ end
125
+
126
+ file pid_file do
127
+ action :delete
128
+ end
129
+ end
130
+
131
+ # Path to the run parameters tracking file.
132
+ def run_file
133
+ "/var/run/#{new_resource.service_name}.json"
104
134
  end
105
135
 
136
+ # Path to the PID file.
106
137
  def pid_file
107
138
  "/var/run/#{new_resource.service_name}.pid"
108
139
  end
@@ -25,12 +25,21 @@ module PoiseService
25
25
  include Chef::Mixin::ShellOut
26
26
  provides(:systemd)
27
27
 
28
+ # @api private
28
29
  def self.provides_auto?(node, resource)
29
30
  # Don't allow systemd under docker, it won't work in most cases.
30
31
  return false if node['virtualization'] && %w{docker lxc}.include?(node['virtualization']['system'])
31
32
  service_resource_hints.include?(:systemd)
32
33
  end
33
34
 
35
+ # @api private
36
+ def self.default_inversion_options(node, resource)
37
+ super.merge({
38
+ # Automatically reload systemd on changes.
39
+ auto_reload: true,
40
+ })
41
+ end
42
+
34
43
  def pid
35
44
  cmd = shell_out(%w{systemctl status} + [new_resource.service_name])
36
45
  if !cmd.error? && cmd.stdout.include?('Active: active (running)') && md = cmd.stdout.match(/Main PID: (\d+)/)
@@ -48,8 +57,19 @@ module PoiseService
48
57
  end
49
58
  end
50
59
 
60
+ def systemctl_daemon_reload
61
+ execute 'systemctl daemon-reload' do
62
+ action :nothing
63
+ user 'root'
64
+ end
65
+ end
66
+
51
67
  def create_service
52
- service_template("/etc/systemd/system/#{new_resource.service_name}.service", 'systemd.service.erb')
68
+ reloader = systemctl_daemon_reload
69
+ service_template("/etc/systemd/system/#{new_resource.service_name}.service", 'systemd.service.erb') do
70
+ notifies :run, reloader, :immediately if options['auto_reload']
71
+ variables.update(auto_reload: options['auto_reload'])
72
+ end
53
73
  end
54
74
 
55
75
  def destroy_service
@@ -35,6 +35,17 @@ module PoiseService
35
35
  service_resource_hints.include?(:upstart)
36
36
  end
37
37
 
38
+ # True restart in Upstart preserves the original config data, we want the
39
+ # more obvious behavior like everything else in the world that restart
40
+ # would re-read the updated config file. Use stop+start to get this
41
+ # behavior. http://manpages.ubuntu.com/manpages/raring/man8/initctl.8.html
42
+ def action_restart
43
+ return if options['never_restart']
44
+ action_stop
45
+ action_start
46
+ end
47
+
48
+ # Shim out reload if we have a version that predates reload support.
38
49
  def action_reload
39
50
  return if options['never_reload']
40
51
  if !upstart_features[:reload_signal] && new_resource.reload_signal != 'HUP'
@@ -16,5 +16,5 @@
16
16
 
17
17
 
18
18
  module PoiseService
19
- VERSION = '1.0.2'
19
+ VERSION = '1.0.3'
20
20
  end
@@ -37,9 +37,13 @@ else
37
37
  base_port 6000
38
38
  end
39
39
 
40
- poise_service_test 'upstart' do
41
- service_provider :upstart
42
- base_port 7000
40
+ if node['platform_family'] == 'rhel' && node['platform_version'].start_with?('5')
41
+ file '/no_upstart'
42
+ else
43
+ poise_service_test 'upstart' do
44
+ service_provider :upstart
45
+ base_port 7000
46
+ end
43
47
  end
44
48
  end
45
49
 
@@ -54,9 +54,10 @@ EOH
54
54
  let(:chefspec_options) { { platform: 'centos', version: '7.0'} }
55
55
 
56
56
  it { is_expected.to render_file('/etc/init.d/test').with_content(<<-EOH) }
57
- ( cd "/" && daemon --user "root" --pidfile "/var/run/test.pid" "myapp --serve" >/dev/null 2>&1 ) &
58
- sleep 1 # Give it some time to start before checking for a pid
59
- _pid "myapp" > "/var/run/test.pid" || return 3
57
+ Dir.chdir("/")
58
+ IO.write(pid_file, Process.pid)
59
+ Process::UID.change_privilege("root")
60
+ Kernel.exec(*["myapp", "--serve"])
60
61
  EOH
61
62
 
62
63
  context 'with an external PID file' do
@@ -66,7 +67,9 @@ EOH
66
67
  end
67
68
 
68
69
  it { is_expected.to render_file('/etc/init.d/test').with_content(<<-EOH) }
69
- ( cd "/" && daemon --user "root" --pidfile "/tmp/pid" "myapp --serve" >/dev/null 2>&1 ) &
70
+ Dir.chdir("/")
71
+ Process::UID.change_privilege("root")
72
+ Kernel.exec(*["myapp", "--serve"])
70
73
  EOH
71
74
  end # /context with an external PID file
72
75
  end # /context on CentOS
@@ -45,7 +45,7 @@ respawn limit 10 5
45
45
  umask 022
46
46
  chdir /
47
47
 
48
- exec /opt/chef/embedded/bin/ruby -e 'Process.uid = "root"; ENV["HOME"] = Dir.home("root") rescue nil; exec(*["myapp", "--serve"])'
48
+ exec /opt/chef/embedded/bin/ruby -e 'Process::UID.change_privilege("root"); ENV["HOME"] = Dir.home("root") rescue nil; exec(*["myapp", "--serve"])'
49
49
  EOH
50
50
 
51
51
  context 'with a stop signal' do
@@ -69,7 +69,7 @@ respawn limit 10 5
69
69
  umask 022
70
70
  chdir /
71
71
 
72
- exec /opt/chef/embedded/bin/ruby -e 'Process.uid = "root"; ENV["HOME"] = Dir.home("root") rescue nil; exec(*["myapp", "--serve"])'
72
+ exec /opt/chef/embedded/bin/ruby -e 'Process::UID.change_privilege("root"); ENV["HOME"] = Dir.home("root") rescue nil; exec(*["myapp", "--serve"])'
73
73
  pre-stop script
74
74
  PID=`initctl status test | sed 's/^.*process \\([0-9]*\\)$/\\1/'`
75
75
  if [ -n "$PID" ]; then
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poise-service
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Kantrowitz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-17 00:00:00.000000000 Z
11
+ date: 2015-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: halite
@@ -85,6 +85,7 @@ files:
85
85
  - README.md
86
86
  - Rakefile
87
87
  - chef/attributes/default.rb
88
+ - chef/templates/default/dummy.json.erb
88
89
  - chef/templates/default/systemd.service.erb
89
90
  - chef/templates/default/sysvinit.sh.erb
90
91
  - chef/templates/default/upstart.conf.erb