Class: Puppet::Daemon

Inherits:
Object show all
Defined in:
lib/vendor/puppet/daemon.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#agentObject

Returns the value of attribute agent.



8
9
10
# File 'lib/vendor/puppet/daemon.rb', line 8

def agent
  @agent
end

#argvObject

Returns the value of attribute argv.



8
9
10
# File 'lib/vendor/puppet/daemon.rb', line 8

def argv
  @argv
end

#serverObject

Returns the value of attribute server.



8
9
10
# File 'lib/vendor/puppet/daemon.rb', line 8

def server
  @server
end

Instance Method Details

#create_pidfileObject

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



44
45
46
47
48
# File 'lib/vendor/puppet/daemon.rb', line 44

def create_pidfile
  Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do
    raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock
  end
end

#daemonizeObject

Put the daemon into the background.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/vendor/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("/")
  begin
    $stdin.reopen "/dev/null"
    $stdout.reopen "/dev/null", "a"
    $stderr.reopen $stdout
    Puppet::Util::Log.reopen
  rescue => detail
    Puppet.err "Could not start #{Puppet[:name]}: #{detail}"
    Puppet::Util::replace_file("/tmp/daemonout", 0644) do |f|
      f.puts "Could not start #{Puppet[:name]}: #{detail}"
    end
    exit(12)
  end
end

#daemonnameObject



10
11
12
# File 'lib/vendor/puppet/daemon.rb', line 10

def daemonname
  Puppet[:name]
end

#pidfileObject

Provide the path to our pidfile.



51
52
53
# File 'lib/vendor/puppet/daemon.rb', line 51

def pidfile
  Puppet[:pidfile]
end

#reexecObject

Raises:



55
56
57
58
59
60
61
# File 'lib/vendor/puppet/daemon.rb', line 55

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

#reloadObject



63
64
65
66
67
68
69
70
71
# File 'lib/vendor/puppet/daemon.rb', line 63

def reload
  return unless agent
  if agent.running?
    Puppet.notice "Not triggering already-running agent"
    return
  end

  agent.run
end

#remove_pidfileObject

Remove the pid file for our daemon.



74
75
76
77
78
# File 'lib/vendor/puppet/daemon.rb', line 74

def remove_pidfile
  Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do
    Puppet::Util::Pidlock.new(pidfile).unlock
  end
end

#reopen_logsObject



85
86
87
# File 'lib/vendor/puppet/daemon.rb', line 85

def reopen_logs
  Puppet::Util::Log.reopen
end

#restartObject



80
81
82
83
# File 'lib/vendor/puppet/daemon.rb', line 80

def restart
  Puppet::Application.restart!
  reexec unless agent and agent.running?
end

#run_event_loopObject



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/vendor/puppet/daemon.rb', line 130

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].to_i, 0].max

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

  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

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

      # 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].to_i, 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_trapsObject

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.



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/vendor/puppet/daemon.rb', line 91

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

#startObject

Raises:



116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/vendor/puppet/daemon.rb', line 116

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

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

#stop(args = {:exit => true}) ⇒ Object

Stop everything



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/vendor/puppet/daemon.rb', line 104

def stop(args = {:exit => true})
  Puppet::Application.stop!

  server.stop if server

  remove_pidfile

  Puppet::Util::Log.close_all

  exit if args[:exit]
end