class Puppet::Agent

A general class for triggering a run of another class.

Attributes

client[R]
client_class[R]
should_fork[R]

Public Class Methods

new(client_class, should_fork=true) click to toggle source
   # File lib/puppet/agent.rb
26 def initialize(client_class, should_fork=true)
27   @should_fork = can_fork? && should_fork
28   @client_class = client_class
29 end

Public Instance Methods

can_fork?() click to toggle source
   # File lib/puppet/agent.rb
31 def can_fork?
32   Puppet.features.posix? && RUBY_PLATFORM != 'java'
33 end
needing_restart?() click to toggle source
   # File lib/puppet/agent.rb
35 def needing_restart?
36   Puppet::Application.restart_requested?
37 end
run(client_options = {}) click to toggle source

Perform a run with our client.

    # File lib/puppet/agent.rb
 40 def run(client_options = {})
 41   if disabled?
 42     log_disabled_message
 43     return
 44   end
 45 
 46   result = nil
 47   wait_for_lock_deadline = nil
 48   block_run = Puppet::Application.controlled_run do
 49     # splay may sleep for awhile when running onetime! If not onetime, then
 50     # the job scheduler splays (only once) so that agents assign themselves a
 51     # slot within the splay interval.
 52     do_splay = client_options.fetch(:splay, Puppet[:splay])
 53     if do_splay
 54       splay(do_splay)
 55 
 56       if disabled?
 57         log_disabled_message
 58         break
 59       end
 60     end
 61 
 62     # waiting for certs may sleep for awhile depending on onetime, waitforcert and maxwaitforcert!
 63     # this needs to happen before forking so that if we fail to obtain certs and try to exit, then
 64     # we exit the main process and not the forked child.
 65     ssl_context = wait_for_certificates(client_options)
 66 
 67     result = run_in_fork(should_fork) do
 68       with_client(client_options[:transaction_uuid], client_options[:job_id]) do |client|
 69         client_args = client_options.merge(:pluginsync => Puppet::Configurer.should_pluginsync?)
 70         begin
 71           # lock may sleep for awhile depending on waitforlock and maxwaitforlock!
 72           lock do
 73             if disabled?
 74               log_disabled_message
 75               nil
 76             else
 77               # NOTE: Timeout is pretty heinous as the location in which it
 78               # throws an error is entirely unpredictable, which means that
 79               # it can interrupt code blocks that perform cleanup or enforce
 80               # sanity. The only thing a Puppet agent should do after this
 81               # error is thrown is die with as much dignity as possible.
 82               Timeout.timeout(Puppet[:runtimeout], RunTimeoutError) do
 83                 Puppet.override(ssl_context: ssl_context) do
 84                   client.run(client_args)
 85                 end
 86               end
 87             end
 88           end
 89         rescue Puppet::LockError
 90           now = Time.now.to_i
 91           wait_for_lock_deadline ||= now + Puppet[:maxwaitforlock]
 92 
 93           if Puppet[:waitforlock] < 1
 94             Puppet.notice _("Run of %{client_class} already in progress; skipping  (%{lockfile_path} exists)") % { client_class: client_class, lockfile_path: lockfile_path }
 95             nil
 96           elsif now >= wait_for_lock_deadline
 97             Puppet.notice _("Exiting now because the maxwaitforlock timeout has been exceeded.")
 98             nil
 99           else
100             Puppet.info _("Another puppet instance is already running; --waitforlock flag used, waiting for running instance to finish.")
101             Puppet.info _("Will try again in %{time} seconds.") % {time: Puppet[:waitforlock]}
102             sleep Puppet[:waitforlock]
103             retry
104           end
105         rescue RunTimeoutError => detail
106           Puppet.log_exception(detail, _("Execution of %{client_class} did not complete within %{runtimeout} seconds and was terminated.") %
107             {client_class: client_class, runtimeout: Puppet[:runtimeout]})
108           nil
109         rescue StandardError => detail
110           Puppet.log_exception(detail, _("Could not run %{client_class}: %{detail}") % { client_class: client_class, detail: detail })
111           nil
112         ensure
113           Puppet.runtime[:http].close
114         end
115       end
116     end
117     true
118   end
119   Puppet.notice _("Shutdown/restart in progress (%{status}); skipping run") % { status: Puppet::Application.run_status.inspect } unless block_run
120   result
121 end
run_in_fork(forking = true) { || ... } click to toggle source
    # File lib/puppet/agent.rb
127 def run_in_fork(forking = true)
128   return yield unless forking or Puppet.features.windows?
129 
130   atForkHandler = Puppet::Util::AtFork.get_handler
131 
132   atForkHandler.prepare
133 
134   begin
135     child_pid = Kernel.fork do
136       atForkHandler.child
137       $0 = _("puppet agent: applying configuration")
138       begin
139         exit(yield || 1)
140       rescue NoMemoryError
141         exit(254)
142       end
143     end
144   ensure
145     atForkHandler.parent
146   end
147 
148   exit_code = Process.waitpid2(child_pid)
149   exit_code[1].exitstatus
150 end
stopping?() click to toggle source
    # File lib/puppet/agent.rb
123 def stopping?
124   Puppet::Application.stop_requested?
125 end

Private Instance Methods

log_disabled_message() click to toggle source
    # File lib/puppet/agent.rb
174 def log_disabled_message
175   Puppet.notice _("Skipping run of %{client_class}; administratively disabled (Reason: '%{disable_message}');\nUse 'puppet agent --enable' to re-enable.") % { client_class: client_class, disable_message: disable_message }
176 end
wait_for_certificates(options) click to toggle source
    # File lib/puppet/agent.rb
168 def wait_for_certificates(options)
169   waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : Puppet[:waitforcert])
170   sm = Puppet::SSL::StateMachine.new(waitforcert: waitforcert, onetime: Puppet[:onetime])
171   sm.ensure_client_certificate
172 end
with_client(transaction_uuid, job_id = nil) { |client| ... } click to toggle source

Create and yield a client instance, keeping a reference to it during the yield.

    # File lib/puppet/agent.rb
156 def with_client(transaction_uuid, job_id = nil)
157   begin
158     @client = client_class.new(transaction_uuid, job_id)
159   rescue StandardError => detail
160     Puppet.log_exception(detail, _("Could not create instance of %{client_class}: %{detail}") % { client_class: client_class, detail: detail })
161     return
162   end
163   yield @client
164 ensure
165   @client = nil
166 end