# class Puppet::Daemon

A module that handles operations common to all daemons. This is included into the Server and Client base classes.

### Attributes

agent[RW]
argv[RW]
server[RW]

### Public Class Methods

close_streams() click to toggle source

Close stdin/stdout/stderr so that we can finish our transition into ‘daemon’ mode. @return nil

    # File lib/puppet/daemon.rb, line 32
    def self.close_streams()
      Puppet.debug("Closing streams for daemon mode")
      begin
        $stdin.reopen "/dev/null"
        $stdout.reopen "/dev/null", "a"
        $stderr.reopen $stdout
        Puppet::Util::Log.reopen
        Puppet.debug("Finished closing streams for daemon mode")
      rescue => detail
        Puppet.err "Could not start #{Puppet.run_mode.name}: #{detail}"
        Puppet::Util::replace_file("/tmp/daemonout", 0644) do |f|
          f.puts "Could not start #{Puppet.run_mode.name}: #{detail}"
        end
        exit(12)
      end
    end

### Public Instance Methods

close_streams() click to toggle source

Convenience signature for calling ::close_streams

    # File lib/puppet/daemon.rb, line 50
    def close_streams()
      Puppet::Daemon.close_streams
    end

create_pidfile() click to toggle source

Create a pidfile for our daemon, so we can be stopped and others don’t try to start.

    # File lib/puppet/daemon.rb, line 56
    def create_pidfile
      Puppet::Util.synchronize_on(Puppet.run_mode.name,Sync::EX) do
        raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock
      end
    end

daemonize() click to toggle source

Put the daemon into the background.

    # File lib/puppet/daemon.rb, line 15
    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("/")
    end

daemonname() click to toggle source

    # File lib/puppet/daemon.rb, line 10
    def daemonname
      Puppet.run_mode.name
    end

pidfile() click to toggle source

Provide the path to our pidfile.

    # File lib/puppet/daemon.rb, line 63
    def pidfile
      Puppet[:pidfile]
    end

reexec() click to toggle source

    # File lib/puppet/daemon.rb, line 67
    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

reload() click to toggle source

    # File lib/puppet/daemon.rb, line 75
    def reload
      return unless agent
      if agent.running?
        Puppet.notice "Not triggering already-running agent"
        return
      end

      agent.run
    end

remove_pidfile() click to toggle source

Remove the pid file for our daemon.

    # File lib/puppet/daemon.rb, line 86
    def remove_pidfile
      Puppet::Util.synchronize_on(Puppet.run_mode.name,Sync::EX) do
        Puppet::Util::Pidlock.new(pidfile).unlock
      end
    end

reopen_logs() click to toggle source

    # File lib/puppet/daemon.rb, line 97
    def reopen_logs
      Puppet::Util::Log.reopen
    end

restart() click to toggle source

    # File lib/puppet/daemon.rb, line 92
    def restart
      Puppet::Application.restart!
      reexec unless agent and agent.running?
    end

run_event_loop() click to toggle source

    # File lib/puppet/daemon.rb, line 148
    def run_event_loop
      # Now, we loop waiting for either the configuration file to change, or the
      # next agent run to be due.  Fun times.
      #
      # We want to trigger the reparse if 15 seconds passed since the previous
      # wakeup, and the agent run if Puppet[:runinterval] seconds have passed
      # since the previous wakeup.
      #
      # We always want to run the agent on startup, so it was always before now.
      # Because 0 means "continuously run", `to_i` does the right thing when the
      # input is strange or badly formed by returning 0.  Integer will raise,
      # which we don't want, and we want to protect against -1 or below.
      next_agent_run = 0
      agent_run_interval = [Puppet[:runinterval], 0].max

      # We may not want to reparse; that can be disable.  Fun times.
      next_reparse = 0
      reparse_interval = Puppet[:filetimeout]

      loop do
        now = Time.now.to_i

        # We set a default wakeup of "one hour from now", which will
        # recheck everything at a minimum every hour.  Just in case something in
        # the math messes up or something; it should be inexpensive enough to
        # wake once an hour, then go back to sleep after doing nothing, if
        # someone only wants listen mode.
        next_event = now + 60 * 60

        # Handle reparsing of configuration files, if desired and required.
        # `reparse` will just check if the action is required, and would be
        # better named `reparse_if_changed` instead.
        if reparse_interval > 0 and now >= next_reparse
          Puppet.settings.reparse_config_files

          # The time to the next reparse might have changed, so recalculate
          # now.  That way we react dynamically to reconfiguration.
          reparse_interval = Puppet[:filetimeout]

          # Set up the next reparse check based on the new reparse_interval.
          if reparse_interval > 0
            next_reparse = now + reparse_interval
            next_event > next_reparse and next_event = next_reparse
          end

          # We should also recalculate the agent run interval, and adjust the
          # next time it is scheduled to run, just in case.  In the event that
          # we made no change the result will be a zero second adjustment.
          new_run_interval    = [Puppet[:runinterval], 0].max
          next_agent_run     += agent_run_interval - new_run_interval
          agent_run_interval  = new_run_interval
        end

        # Handle triggering another agent run.  This will block the next check
        # for configuration reparsing, which is a desired and deliberate
        # behaviour.  You should not change that. --daniel 2012-02-21
        if agent and now >= next_agent_run
          agent.run

          # Set up the next agent run time
          next_agent_run = now + agent_run_interval
          next_event > next_agent_run and next_event = next_agent_run
        end

        # Finally, an interruptable able sleep until the next scheduled event.
        how_long = next_event - now
        how_long > 0 and select([], [], [], how_long)
      end
    end

set_signal_traps() click to toggle source

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, line 103
    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|
        Signal.trap(signal) do
          Puppet.notice "Caught #{signal}; calling #{method}"
          send(method)
        end
      end
    end

start() click to toggle source

    # File lib/puppet/daemon.rb, line 128
    def start
      set_signal_traps

      create_pidfile

      raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server

      # Start the listening server, if required.
      server.start if server

      # now that the server has started, we've waited just about as long as possible to close
      #  our streams and become a "real" daemon process.  This is in hopes of allowing
      #  errors to have the console available as a fallback for logging for as long as
      #  possible.
      close_streams if Puppet[:daemonize]

      # Finally, loop forever running events - or, at least, until we exit.
      run_event_loop
    end

stop(args = {:exit => true}) click to toggle source

Stop everything

    # File lib/puppet/daemon.rb, line 116
    def stop(args = {:exit => true})
      Puppet::Application.stop!

      server.stop if server

      remove_pidfile

      Puppet::Util::Log.close_all

      exit if args[:exit]
    end