class Puppet::Daemon
Run periodic actions in a daemonized process.
A Daemon
has 2 parts:
* config reparse * an agent that responds to #run
The config reparse will occur periodically based on Settings. The agent is run periodically and a time interval based on Settings. The config reparse will update this time interval when needed.
The Daemon
is also responsible for signal handling, starting, stopping, running the agent on demand, and reloading the entire process. It ensures that only one Daemon
is running by using a lockfile.
@api private
Constants
- SIGNAL_CHECK_INTERVAL
Attributes
Public Class Methods
Close stdin/stdout/stderr so that we can finish our transition into 'daemon' mode. @return nil
# File lib/puppet/daemon.rb 58 def self.close_streams() 59 Puppet.debug("Closing streams for daemon mode") 60 begin 61 $stdin.reopen "/dev/null" 62 $stdout.reopen "/dev/null", "a" 63 $stderr.reopen $stdout 64 Puppet::Util::Log.reopen 65 Puppet.debug("Finished closing streams for daemon mode") 66 rescue => detail 67 Puppet.err "Could not start #{Puppet.run_mode.name}: #{detail}" 68 Puppet::Util::replace_file("/tmp/daemonout", 0644) do |f| 69 f.puts "Could not start #{Puppet.run_mode.name}: #{detail}" 70 end 71 exit(12) 72 end 73 end
# File lib/puppet/daemon.rb 25 def initialize(agent, pidfile, scheduler = Puppet::Scheduler::Scheduler.new()) 26 raise Puppet::DevError, _("Daemons must have an agent") unless agent 27 @scheduler = scheduler 28 @pidfile = pidfile 29 @agent = agent 30 @signals = [] 31 end
Public Instance Methods
Convenience signature for calling Puppet::Daemon.close_streams
# File lib/puppet/daemon.rb 76 def close_streams() 77 Puppet::Daemon.close_streams 78 end
Put the daemon into the background.
# File lib/puppet/daemon.rb 38 def daemonize 39 pid = fork 40 if pid 41 Process.detach(pid) 42 exit(0) 43 end 44 45 create_pidfile 46 47 # Get rid of console logging 48 Puppet::Util::Log.close(:console) 49 50 Process.setsid 51 Dir.chdir("/") 52 53 close_streams 54 end
# File lib/puppet/daemon.rb 33 def daemonname 34 Puppet.run_mode.name 35 end
# File lib/puppet/daemon.rb 80 def reexec 81 raise Puppet::DevError, _("Cannot reexec unless ARGV arguments are set") unless argv 82 command = $0 + " " + argv.join(" ") 83 Puppet.notice "Restarting with '#{command}'" 84 stop(:exit => false) 85 exec(command) 86 end
# File lib/puppet/daemon.rb 88 def reload 89 agent.run({:splay => false}) 90 rescue Puppet::LockError 91 Puppet.notice "Not triggering already-running agent" 92 end
# File lib/puppet/daemon.rb 99 def reopen_logs 100 Puppet::Util::Log.reopen 101 end
# File lib/puppet/daemon.rb 94 def restart 95 Puppet::Application.restart! 96 reexec 97 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.
# File lib/puppet/daemon.rb 105 def set_signal_traps 106 [:INT, :TERM].each do |signal| 107 Signal.trap(signal) do 108 Puppet.notice "Caught #{signal}; exiting" 109 stop 110 end 111 end 112 113 # extended signals not supported under windows 114 if !Puppet::Util::Platform.windows? 115 signals = {:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs } 116 signals.each do |signal, method| 117 Signal.trap(signal) do 118 Puppet.notice "Caught #{signal}; storing #{method}" 119 @signals << method 120 end 121 end 122 end 123 end
# File lib/puppet/daemon.rb 136 def start 137 create_pidfile 138 run_event_loop 139 end
Stop everything
# File lib/puppet/daemon.rb 126 def stop(args = {:exit => true}) 127 Puppet::Application.stop! 128 129 remove_pidfile 130 131 Puppet::Util::Log.close_all 132 133 exit if args[:exit] 134 end
Private Instance Methods
Create a pidfile for our daemon, so we can be stopped and others don't try to start.
# File lib/puppet/daemon.rb 145 def create_pidfile 146 raise "Could not create PID file: #{@pidfile.file_path}" unless @pidfile.lock 147 end
Remove the pid file for our daemon.
# File lib/puppet/daemon.rb 150 def remove_pidfile 151 @pidfile.unlock 152 end
Loop forever running events - or, at least, until we exit.
# File lib/puppet/daemon.rb 155 def run_event_loop 156 agent_run = Puppet::Scheduler.create_job(Puppet[:runinterval], Puppet[:splay], Puppet[:splaylimit]) do 157 # Splay for the daemon is handled in the scheduler 158 agent.run(:splay => false) 159 end 160 161 reparse_run = Puppet::Scheduler.create_job(Puppet[:filetimeout]) do 162 Puppet.settings.reparse_config_files 163 agent_run.run_interval = Puppet[:runinterval] 164 if Puppet[:filetimeout] == 0 165 reparse_run.disable 166 else 167 reparse_run.run_interval = Puppet[:filetimeout] 168 end 169 end 170 171 signal_loop = Puppet::Scheduler.create_job(SIGNAL_CHECK_INTERVAL) do 172 while method = @signals.shift #rubocop:disable Lint/AssignmentInCondition 173 Puppet.notice "Processing #{method}" 174 send(method) 175 end 176 end 177 178 reparse_run.disable if Puppet[:filetimeout] == 0 179 180 @scheduler.run_loop([reparse_run, agent_run, signal_loop]) 181 end