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 59 def self.close_streams() 60 Puppet.debug("Closing streams for daemon mode") 61 begin 62 $stdin.reopen "/dev/null" 63 $stdout.reopen "/dev/null", "a" 64 $stderr.reopen $stdout 65 Puppet::Util::Log.reopen 66 Puppet.debug("Finished closing streams for daemon mode") 67 rescue => detail 68 Puppet.err "Could not start #{Puppet.run_mode.name}: #{detail}" 69 Puppet::Util::replace_file("/tmp/daemonout", 0644) do |f| 70 f.puts "Could not start #{Puppet.run_mode.name}: #{detail}" 71 end 72 exit(12) 73 end 74 end
# File lib/puppet/daemon.rb 26 def initialize(agent, pidfile, scheduler = Puppet::Scheduler::Scheduler.new()) 27 raise Puppet::DevError, _("Daemons must have an agent") unless agent 28 @scheduler = scheduler 29 @pidfile = pidfile 30 @agent = agent 31 @signals = [] 32 end
Public Instance Methods
Convenience signature for calling Puppet::Daemon.close_streams
# File lib/puppet/daemon.rb 77 def close_streams() 78 Puppet::Daemon.close_streams 79 end
Put the daemon into the background.
# File lib/puppet/daemon.rb 39 def daemonize 40 pid = fork 41 if pid 42 Process.detach(pid) 43 exit(0) 44 end 45 46 create_pidfile 47 48 # Get rid of console logging 49 Puppet::Util::Log.close(:console) 50 51 Process.setsid 52 Dir.chdir("/") 53 54 close_streams 55 end
# File lib/puppet/daemon.rb 34 def daemonname 35 Puppet.run_mode.name 36 end
# File lib/puppet/daemon.rb 81 def reexec 82 raise Puppet::DevError, _("Cannot reexec unless ARGV arguments are set") unless argv 83 command = $0 + " " + argv.join(" ") 84 Puppet.notice "Restarting with '#{command}'" 85 stop(:exit => false) 86 exec(command) 87 end
# File lib/puppet/daemon.rb 89 def reload 90 agent.run({:splay => false}) 91 rescue Puppet::LockError 92 Puppet.notice "Not triggering already-running agent" 93 end
# File lib/puppet/daemon.rb 100 def reopen_logs 101 Puppet::Util::Log.reopen 102 end
# File lib/puppet/daemon.rb 95 def restart 96 Puppet::Application.restart! 97 reexec 98 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 106 def set_signal_traps 107 [:INT, :TERM].each do |signal| 108 Signal.trap(signal) do 109 Puppet.notice "Caught #{signal}; exiting" 110 stop 111 end 112 end 113 114 # extended signals not supported under windows 115 if !Puppet::Util::Platform.windows? 116 signals = {:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs } 117 signals.each do |signal, method| 118 Signal.trap(signal) do 119 Puppet.notice "Caught #{signal}; storing #{method}" 120 @signals << method 121 end 122 end 123 end 124 end
# File lib/puppet/daemon.rb 137 def start 138 create_pidfile 139 run_event_loop 140 end
Stop everything
# File lib/puppet/daemon.rb 127 def stop(args = {:exit => true}) 128 Puppet::Application.stop! 129 130 remove_pidfile 131 132 Puppet::Util::Log.close_all 133 134 exit if args[:exit] 135 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 146 def create_pidfile 147 raise "Could not create PID file: #{@pidfile.file_path}" unless @pidfile.lock 148 end
Remove the pid file for our daemon.
# File lib/puppet/daemon.rb 151 def remove_pidfile 152 @pidfile.unlock 153 end
Loop forever running events - or, at least, until we exit.
# File lib/puppet/daemon.rb 156 def run_event_loop 157 agent_run = Puppet::Scheduler.create_job(Puppet[:runinterval], Puppet[:splay], Puppet[:splaylimit]) do 158 # Splay for the daemon is handled in the scheduler 159 agent.run(:splay => false) 160 end 161 162 reparse_run = Puppet::Scheduler.create_job(Puppet[:filetimeout]) do 163 Puppet.settings.reparse_config_files 164 agent_run.run_interval = Puppet[:runinterval] 165 if Puppet[:filetimeout] == 0 166 reparse_run.disable 167 else 168 reparse_run.run_interval = Puppet[:filetimeout] 169 end 170 end 171 172 signal_loop = Puppet::Scheduler.create_job(SIGNAL_CHECK_INTERVAL) do 173 while method = @signals.shift #rubocop:disable Lint/AssignmentInCondition 174 Puppet.notice "Processing #{method}" 175 send(method) 176 end 177 end 178 179 reparse_run.disable if Puppet[:filetimeout] == 0 180 181 @scheduler.run_loop([reparse_run, agent_run, signal_loop]) 182 end