Class: Puppet::Agent

Inherits:
Object show all
Includes:
Disabler, Locker, Util::Splayer
Defined in:
lib/puppet/agent.rb

Overview

A general class for triggering a run of another class.

Defined Under Namespace

Modules: Disabler, Locker Classes: RunTimeoutError

Constant Summary

Constants included from Disabler

Disabler::DISABLED_MESSAGE_JSON_KEY

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util::Splayer

#splay, #splayed?

Methods included from Disabler

#disable, #disable_message, #disabled?, #enable

Methods included from Locker

#lock, #lockfile_path, #running?

Constructor Details

#initialize(client_class, should_fork = true) ⇒ Agent

Returns a new instance of Agent.



27
28
29
30
# File 'lib/puppet/agent.rb', line 27

def initialize(client_class, should_fork = true)
  @should_fork = can_fork? && should_fork
  @client_class = client_class
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



25
26
27
# File 'lib/puppet/agent.rb', line 25

def client
  @client
end

#client_classObject (readonly)

Returns the value of attribute client_class.



25
26
27
# File 'lib/puppet/agent.rb', line 25

def client_class
  @client_class
end

#should_forkObject (readonly)

Returns the value of attribute should_fork.



25
26
27
# File 'lib/puppet/agent.rb', line 25

def should_fork
  @should_fork
end

Instance Method Details

#can_fork?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/puppet/agent.rb', line 32

def can_fork?
  Puppet.features.posix? && RUBY_PLATFORM != 'java'
end

#needing_restart?Boolean

Returns:

  • (Boolean)


36
37
38
# File 'lib/puppet/agent.rb', line 36

def needing_restart?
  Puppet::Application.restart_requested?
end

#run(client_options = {}) ⇒ Object

Perform a run with our client.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/puppet/agent.rb', line 41

def run(client_options = {})
  if disabled?
    log_disabled_message
    return
  end

  result = nil
  wait_for_lock_deadline = nil
  block_run = Puppet::Application.controlled_run do
    # splay may sleep for awhile when running onetime! If not onetime, then
    # the job scheduler splays (only once) so that agents assign themselves a
    # slot within the splay interval.
    do_splay = client_options.fetch(:splay, Puppet[:splay])
    if do_splay
      splay(do_splay)

      if disabled?
        log_disabled_message
        break
      end
    end

    # waiting for certs may sleep for awhile depending on onetime, waitforcert and maxwaitforcert!
    # this needs to happen before forking so that if we fail to obtain certs and try to exit, then
    # we exit the main process and not the forked child.
    ssl_context = wait_for_certificates(client_options)

    result = run_in_fork(should_fork) do
      with_client(client_options[:transaction_uuid], client_options[:job_id]) do |client|
        client_args = client_options.merge(:pluginsync => Puppet::Configurer.should_pluginsync?)
        begin
          # lock may sleep for awhile depending on waitforlock and maxwaitforlock!
          lock do
            if disabled?
              log_disabled_message
              nil
            else
              # NOTE: Timeout is pretty heinous as the location in which it
              # throws an error is entirely unpredictable, which means that
              # it can interrupt code blocks that perform cleanup or enforce
              # sanity. The only thing a Puppet agent should do after this
              # error is thrown is die with as much dignity as possible.
              Timeout.timeout(Puppet[:runtimeout], RunTimeoutError) do
                Puppet.override(ssl_context: ssl_context) do
                  client.run(client_args)
                end
              end
            end
          end
        rescue Puppet::LockError
          now = Time.now.to_i
          wait_for_lock_deadline ||= now + Puppet[:maxwaitforlock]

          if Puppet[:waitforlock] < 1
            Puppet.notice _("Run of %{client_class} already in progress; skipping  (%{lockfile_path} exists)") % { client_class: client_class, lockfile_path: lockfile_path }
            nil
          elsif now >= wait_for_lock_deadline
            Puppet.notice _("Exiting now because the maxwaitforlock timeout has been exceeded.")
            nil
          else
            Puppet.info _("Another puppet instance is already running; --waitforlock flag used, waiting for running instance to finish.")
            Puppet.info _("Will try again in %{time} seconds.") % { time: Puppet[:waitforlock] }
            sleep Puppet[:waitforlock]
            retry
          end
        rescue RunTimeoutError => detail
          Puppet.log_exception(detail, _("Execution of %{client_class} did not complete within %{runtimeout} seconds and was terminated.") %
            { client_class: client_class, runtimeout: Puppet[:runtimeout] })
          nil
        rescue StandardError => detail
          Puppet.log_exception(detail, _("Could not run %{client_class}: %{detail}") % { client_class: client_class, detail: detail })
          nil
        ensure
          Puppet.runtime[:http].close
        end
      end
    end
    true
  end
  Puppet.notice _("Shutdown/restart in progress (%{status}); skipping run") % { status: Puppet::Application.run_status.inspect } unless block_run
  result
end

#run_in_fork(forking = true) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/puppet/agent.rb', line 128

def run_in_fork(forking = true)
  return yield unless forking or Puppet.features.windows?

  atForkHandler = Puppet::Util::AtFork.get_handler

  atForkHandler.prepare

  begin
    child_pid = Kernel.fork do
      atForkHandler.child
      $0 = _("puppet agent: applying configuration")
      begin
        exit(yield || 1)
      rescue NoMemoryError
        exit(254)
      end
    end
  ensure
    atForkHandler.parent
  end

  exit_code = Process.waitpid2(child_pid)
  exit_code[1].exitstatus
end

#stopping?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/puppet/agent.rb', line 124

def stopping?
  Puppet::Application.stop_requested?
end