poise-service 1.0.2 → 1.0.3

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
  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