summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2009-02-02 17:19:07 -0600
committerLuke Kanies <luke@madstop.com>2009-02-06 18:08:43 -0600
commitc0fcb2137e66af8ba60a959faa221034c6832b69 (patch)
tree10f62605333979ea64445dca5d4d66d58237de97 /lib/puppet
parent700e823f7c33eb3c5b4d9e467742fd24f63bbeef (diff)
downloadpuppet-c0fcb2137e66af8ba60a959faa221034c6832b69.tar.gz
puppet-c0fcb2137e66af8ba60a959faa221034c6832b69.tar.xz
puppet-c0fcb2137e66af8ba60a959faa221034c6832b69.zip
Creating and using a new Puppet::Daemon class
This replaces the short-lived EventManager class, all of the service- and timer-related code in puppet.rb, and moves code from agent.rb, server.rb, and other places into one class responsible for starting, stopping, pids, and more. The Daemon module is no longer in existence, so it's been removed from the classes that were using it. Signed-off-by: Luke Kanies <luke@madstop.com>
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/agent.rb39
-rw-r--r--lib/puppet/agent/locker.rb1
-rwxr-xr-xlib/puppet/daemon.rb102
-rw-r--r--lib/puppet/event_manager.rb182
-rw-r--r--lib/puppet/network/http_server/mongrel.rb2
-rw-r--r--lib/puppet/network/http_server/webrick.rb2
-rw-r--r--lib/puppet/util/settings.rb19
7 files changed, 107 insertions, 240 deletions
diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb
index c91552b16..e7d40f68c 100644
--- a/lib/puppet/agent.rb
+++ b/lib/puppet/agent.rb
@@ -1,17 +1,19 @@
require 'sync'
-require 'puppet/daemon'
+require 'puppet/external/event-loop'
# A general class for triggering a run of another
# class.
class Puppet::Agent
- include Puppet::Daemon
-
require 'puppet/agent/locker'
include Puppet::Agent::Locker
- attr_reader :client_class, :client
+ attr_reader :client_class, :client, :needing_restart, :splayed
attr_accessor :stopping
+ def configure_delayed_restart
+ @needing_restart = true
+ end
+
# Just so we can specify that we are "the" instance.
def initialize(client_class)
@splayed = false
@@ -23,6 +25,16 @@ class Puppet::Agent
client_class.lockfile_path
end
+ def needing_restart?
+ @needing_restart
+ end
+
+ def restart
+ configure_delayed_restart and return if running?
+ Process.kill(:HUP, $$)
+ @needing_restart = false
+ end
+
# Perform a run with our client.
def run
if client
@@ -44,7 +56,12 @@ class Puppet::Agent
end
end
- def shutdown
+ # If the client instance is set, we're mid-run.
+ def running?
+ ! client.nil?
+ end
+
+ def stop
if self.stopping?
Puppet.notice "Already in shutdown"
return
@@ -58,8 +75,6 @@ class Puppet::Agent
Puppet.err "Could not stop %s: %s" % [client_class, detail]
end
end
-
- super
ensure
self.stopping = false
end
@@ -70,7 +85,7 @@ class Puppet::Agent
# Have we splayed already?
def splayed?
- @splayed
+ splayed
end
# Sleep when splay is enabled; else just return.
@@ -88,16 +103,12 @@ class Puppet::Agent
# timer events here.
def start
# Create our timer. Puppet will handle observing it and such.
- Puppet.newtimer(
- :interval => Puppet[:runinterval],
- :tolerance => 1,
- :start? => true
- ) do
+ timer = EventLoop::Timer.new(:interval => Puppet[:runinterval], :tolerance => 1, :start? => true) do
run()
end
# Run once before we start following the timer
- run()
+ timer.sound_alarm
end
def sync
diff --git a/lib/puppet/agent/locker.rb b/lib/puppet/agent/locker.rb
index c24fdad64..eaf19177a 100644
--- a/lib/puppet/agent/locker.rb
+++ b/lib/puppet/agent/locker.rb
@@ -30,7 +30,6 @@ module Puppet::Agent::Locker
def lockfile
unless defined?(@lockfile)
- #@lockfile = Puppet::Util::Pidlock.new(Puppet[:puppetdlockfile])
@lockfile = Puppet::Util::Pidlock.new(lockfile_path)
end
diff --git a/lib/puppet/daemon.rb b/lib/puppet/daemon.rb
index b0576124e..5f811d897 100755
--- a/lib/puppet/daemon.rb
+++ b/lib/puppet/daemon.rb
@@ -1,10 +1,11 @@
require 'puppet'
require 'puppet/util/pidlock'
+require 'puppet/external/event-loop'
# A module that handles operations common to all daemons. This is included
# into the Server and Client base classes.
-module Puppet::Daemon
- include Puppet::Util
+class Puppet::Daemon
+ attr_accessor :agent, :server, :argv
def daemonname
Puppet[:name]
@@ -17,7 +18,7 @@ module Puppet::Daemon
exit(0)
end
- setpidfile()
+ create_pidfile()
# Get rid of console logging
Puppet::Util::Log.close(:console)
@@ -38,18 +39,42 @@ module Puppet::Daemon
end
end
- # The path to the pid file for this server
+ # 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
+ unless Puppet::Util::Pidlock.new(pidfile).lock
+ raise "Could not create PID file: %s" % [pidfile]
+ end
+ end
+ end
+
+ # Provide the path to our pidfile.
def pidfile
- if Puppet[:pidfile] != ""
- Puppet[:pidfile]
- else
- File.join(Puppet[:rundir], daemonname() + ".pid")
+ 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 '%s'" % 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
- def rmpidfile
- threadlock(:pidfile) do
+ # 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)
if locker.locked?
locker.unlock or Puppet.err "Could not remove PID file %s" % [pidfile]
@@ -57,25 +82,52 @@ module Puppet::Daemon
end
end
- # Create the pid file.
- def setpidfile
- threadlock(:pidfile) do
- unless Puppet::Util::Pidlock.new(pidfile).lock
- Puppet.err("Could not create PID file: %s" % [pidfile])
- exit(74)
- end
+ def restart
+ if agent and agent.running?
+ agent.configure_delayed_restart
+ else
+ reexec
end
end
- # Shut down our server
- def shutdown
- # Remove our pid file
- rmpidfile()
+ def reopen_logs
+ Puppet::Util::Log.reopen
+ end
- # And close all logs except the console.
- Puppet::Util::Log.destinations.reject { |d| d == :console }.each do |dest|
- Puppet::Util::Log.close(dest)
+ # 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
+ {:INT => :stop, :TERM => :stop, :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
+
+ # Stop everything
+ def stop(args = {:exit => true})
+ server.stop if server
+
+ agent.stop if agent
+
+ 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
+ agent.start if agent
+ server.start if server
+
+ EventLoop.current.run
+ end
end
diff --git a/lib/puppet/event_manager.rb b/lib/puppet/event_manager.rb
deleted file mode 100644
index 50c489673..000000000
--- a/lib/puppet/event_manager.rb
+++ /dev/null
@@ -1,182 +0,0 @@
-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
diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb
index e9421c781..924c11728 100644
--- a/lib/puppet/network/http_server/mongrel.rb
+++ b/lib/puppet/network/http_server/mongrel.rb
@@ -34,7 +34,6 @@ require 'puppet/network/xmlrpc/server'
require 'puppet/network/http_server'
require 'puppet/network/client_request'
require 'puppet/network/handler'
-require 'puppet/daemon'
require 'resolv'
@@ -51,7 +50,6 @@ require 'resolv'
# </pre>
module Puppet::Network
class HTTPServer::Mongrel < ::Mongrel::HttpHandler
- include Puppet::Daemon
attr_reader :xmlrpc_server
def initialize(handlers)
diff --git a/lib/puppet/network/http_server/webrick.rb b/lib/puppet/network/http_server/webrick.rb
index 568b4e798..0e835d057 100644
--- a/lib/puppet/network/http_server/webrick.rb
+++ b/lib/puppet/network/http_server/webrick.rb
@@ -1,5 +1,4 @@
require 'puppet'
-require 'puppet/daemon'
require 'webrick'
require 'webrick/https'
require 'fcntl'
@@ -16,7 +15,6 @@ module Puppet
# The old-school, pure ruby webrick server, which is the default serving
# mechanism.
class HTTPServer::WEBrick < WEBrick::HTTPServer
- include Puppet::Daemon
include Puppet::SSLCertificates::Support
# Read the CA cert and CRL and populate an OpenSSL::X509::Store
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index b9736f5ac..0af842c8d 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -3,6 +3,7 @@ require 'sync'
require 'puppet/transportable'
require 'getoptlong'
+require 'puppet/external/event-loop'
# The class for handling configuration files.
class Puppet::Util::Settings
@@ -46,9 +47,6 @@ class Puppet::Util::Settings
# Generate the list of valid arguments, in a format that GetoptLong can
# understand, and add them to the passed option list.
def addargs(options)
- # Hackish, but acceptable. Copy the current ARGV for restarting.
- Puppet.args = ARGV.dup
-
# Add all of the config parameters as valid options.
self.each { |name, element|
element.getopt_args.each { |args| options << args }
@@ -496,16 +494,9 @@ class Puppet::Util::Settings
end
# Create a timer to check whether the file should be reparsed.
- def settimer
- if Puppet[:filetimeout] > 0
- @timer = Puppet.newtimer(
- :interval => Puppet[:filetimeout],
- :tolerance => 1,
- :start? => true
- ) do
- self.reparse()
- end
- end
+ def set_filetimeout_timer
+ return unless timeout = self[:filetimeout] and timeout > 0
+ EventLoop::Timer.new(:interval => timeout, :tolerance => 1, :start? => true) { self.reparse() }
end
# Convert the settings we manage into a catalog full of resources that model those settings.
@@ -822,7 +813,7 @@ Generated on #{Time.now}.
# Create a timer so that this file will get checked automatically
# and reparsed if necessary.
- settimer()
+ set_filetimeout_timer()
result = Hash.new { |names, name|
names[name] = {}