1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
require 'puppet'
require 'puppet/util/pidlock'
require 'puppet/external/event-loop'
require 'puppet/application'
# A module that handles operations common to all daemons. This is included
# into the Server and Client base classes.
class Puppet::Daemon
attr_accessor :agent, :server, :argv
def daemonname
Puppet[:name]
end
# Put the daemon into the background.
def daemonize
if pid = fork
Process.detach(pid)
exit(0)
end
create_pidfile
# Get rid of console logging
Puppet::Util::Log.close(:console)
Process.setsid
Dir.chdir("/")
begin
$stdin.reopen "/dev/null"
$stdout.reopen "/dev/null", "a"
$stderr.reopen $stdout
Puppet::Util::Log.reopen
rescue => detail
Puppet.err "Could not start #{Puppet[:name]}: #{detail}"
Puppet::Util::secure_open("/tmp/daemonout", "w") { |f|
f.puts "Could not start #{Puppet[:name]}: #{detail}"
}
exit(12)
end
end
# Create a pidfile for our daemon, so we can be stopped and others
# don't try to start.
def create_pidfile
Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock
end
end
# Provide the path to our pidfile.
def pidfile
Puppet[:pidfile]
end
def reexec
raise Puppet::DevError, "Cannot reexec unless ARGV arguments are set" unless argv
command = $0 + " " + argv.join(" ")
Puppet.notice "Restarting with '#{command}'"
stop(:exit => false)
exec(command)
end
def reload
return unless agent
if agent.running?
Puppet.notice "Not triggering already-running agent"
return
end
agent.run
end
# Remove the pid file for our daemon.
def remove_pidfile
Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
locker = Puppet::Util::Pidlock.new(pidfile)
locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked?
end
end
def restart
Puppet::Application.restart!
reexec unless agent and agent.running?
end
def reopen_logs
Puppet::Util::Log.reopen
end
# Trap a couple of the main signals. This should probably be handled
# in a way that anyone else can register callbacks for traps, but, eh.
def set_signal_traps
signals = {:INT => :stop, :TERM => :stop }
# extended signals not supported under windows
signals.update({:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs }) unless Puppet.features.microsoft_windows?
signals.each do |signal, method|
trap(signal) do
Puppet.notice "Caught #{signal}; calling #{method}"
send(method)
end
end
end
# Stop everything
def stop(args = {:exit => true})
Puppet::Application.stop!
server.stop if server
remove_pidfile
Puppet::Util::Log.close_all
exit if args[:exit]
end
def start
set_signal_traps
create_pidfile
raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server
server.start if server
agent.start if agent
EventLoop.current.run
end
end
|