diff options
author | Luke Kanies <luke@madstop.com> | 2009-01-31 10:00:48 -0700 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2009-02-06 18:08:43 -0600 |
commit | bf3c72e8a1ed59daf5027c508f2d6dd95424f5bc (patch) | |
tree | 957e6013e145725147f0c40f82a868034798fce3 /lib | |
parent | fc14b81f99adc9c9308a26d322adaa59a7b7716d (diff) | |
download | puppet-bf3c72e8a1ed59daf5027c508f2d6dd95424f5bc.tar.gz puppet-bf3c72e8a1ed59daf5027c508f2d6dd95424f5bc.tar.xz puppet-bf3c72e8a1ed59daf5027c508f2d6dd95424f5bc.zip |
Adding temporary class EventManager
Most of the way through implementation of this class, I realized
that most of its functionality will never actually be used.
Thus, I'm refactoring it and the Puppet::Daemon module into a
single Puppet::Daemon class with merged functionality, and then
moving all of the daemon-like functionality out of both the
Agent and Server classes.
We'll then have a Daemon class that knows how to start and stop
services, create and remove pidfiles, and whatever else
daemons need to know how to do.
This commit is to just so I have the current code snapshot.
Signed-off-by: Luke Kanies <luke@madstop.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/puppet/event_manager.rb | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/lib/puppet/event_manager.rb b/lib/puppet/event_manager.rb new file mode 100644 index 000000000..50c489673 --- /dev/null +++ b/lib/puppet/event_manager.rb @@ -0,0 +1,182 @@ +require 'puppet/external/event-loop' + +# Manage events related to starting, stopping, and restarting +# contained services. +class Puppet::EventManager + include SignalObserver + + attr_reader :services, :threads, :timers + + def initialize + @services = [] + @threads = [] + @timers = [] + end + + # Create a new service that we're supposed to run + def add_service(service) + @services << service + end + + def newthread(&block) + @threads << Thread.new { yield } + end + + # Add a timer we need to pay attention to. + # This is only used by Puppet::Agent at the moment. + def newtimer(hash, &block) + timer = EventLoop::Timer.new(hash) + @timers << timer + + if block_given? + observe_signal(timer, :alarm, &block) + end + + # In case they need it for something else. + timer + end + + # Reload any services that can be reloaded. Really, this is just + # meant to trigger an Agent run. + def reload + done = 0 + services.find_all { |service| service.respond_to?(:run) }.each do |service| + if service.running? + Puppet.notice "Not triggering already-running %s" % service.class + next + end + + Puppet.notice "Triggering a run of %s" % service.class + + done += 1 + begin + service.run + rescue => detail + Puppet.err "Could not run service %s: %s" % [service.class, detail] + end + end + + unless done > 0 + Puppet.notice "No services were reloaded" + end + end + + def reopen_logs + Puppet::Util::Log.reopen + end + + # Relaunch the executable. + def restart + if client = @services.find { |s| s.is_a? Puppet::Network::Client.master } and client.running? + client.restart + else + command = $0 + " " + self.args.join(" ") + Puppet.notice "Restarting with '%s'" % command + Puppet.shutdown(false) + Puppet::Util::Log.reopen + exec(command) + end + 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_traps + {:INT => :shutdown, :TERM => :shutdown, :HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs}.each do |signal, method| + trap(signal) do + Puppet.notice "Caught #{signal}; calling #{method}" + send(method) + end + end + end + + # Shutdown our server process, meaning stop all services and all threads. + # Optionally, exit. + def shutdown(leave = true) + Puppet.notice "Shutting down" + stop_timers + + stop_services + + stop_threads + + if leave + exit(0) + end + end + + # Start all of our services and optionally our event loop, which blocks, + # waiting for someone, somewhere, to generate events of some kind. + def start + start_services + + start_timers + + EventLoop.current.run + end + + def start_services + # Starting everything in its own thread. Otherwise + # we might have one service stop another service from + # doing things like registering timers. + @services.dup.each do |svc| + begin + svc.start + rescue => detail + if Puppet[:trace] + puts detail.backtrace + end + @services.delete svc + Puppet.err "Could not start %s: %s" % [svc.class, detail] + end + end + + # We need to give the services a chance to register their timers before + # we try to start monitoring them. + sleep 0.5 + + unless @services.length > 0 + Puppet.notice "No remaining services; exiting" + exit(1) + end + end + + def stop_services + # Stop our services + services.each do |svc| + begin + timeout(20) do + svc.shutdown + end + rescue TimeoutError + Puppet.err "%s could not shut down within 20 seconds" % svc.class + end + end + end + + # Monitor all of the timers that have been set up. + def start_timers + timers.each do |timer| + EventLoop.current.monitor_timer timer + end + end + + def stop_timers + # Unmonitor our timers + timers.each do |timer| + EventLoop.current.ignore_timer timer + end + end + + def stop_threads + # And wait for them all to die, giving a decent amount of time + threads.each do |thr| + begin + timeout(20) do + thr.join + end + rescue TimeoutError + # Just ignore this, since we can't intelligently provide a warning + end + end + end +end |