Class: Puppet::Configurer

Inherits:
Object show all
Includes:
FactHandler, Util
Defined in:
lib/puppet/configurer.rb

Defined Under Namespace

Modules: FactHandler Classes: Downloader, PluginHandler

Constant Summary

Constants included from Util

Util::AbsolutePathPosix, Util::AbsolutePathWindows, Util::DEFAULT_POSIX_MODE, Util::DEFAULT_WINDOWS_MODE, Util::RFC_3986_URI_REGEX

Constants included from Util::SymbolicFileMode

Util::SymbolicFileMode::SetGIDBit, Util::SymbolicFileMode::SetUIDBit, Util::SymbolicFileMode::StickyBit, Util::SymbolicFileMode::SymbolicMode, Util::SymbolicFileMode::SymbolicSpecialToBit

Constants included from Util::POSIX

Util::POSIX::LOCALE_ENV_VARS, Util::POSIX::USER_ENV_VARS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

absolute_path?, benchmark, chuser, clear_environment, default_env, deterministic_rand, deterministic_rand_int, exit_on_fail, get_env, get_environment, logmethods, merge_environment, path_to_uri, pretty_backtrace, replace_file, safe_posix_fork, set_env, symbolizehash, thinmark, uri_encode, uri_query_encode, uri_to_path, which, withenv, withumask

Methods included from Util::SymbolicFileMode

#normalize_symbolic_mode, #symbolic_mode_to_int, #valid_symbolic_mode?

Methods included from Util::POSIX

#get_posix_field, #gid, groups_of, #idfield, #methodbyid, #methodbyname, #search_posix_field, #uid

Methods included from FactHandler

#encode_facts, #facts_for_uploading, #find_facts

Constructor Details

#initialize(transaction_uuid = nil, job_id = nil) ⇒ Configurer


55
56
57
58
59
60
61
62
63
64
65
# File 'lib/puppet/configurer.rb', line 55

def initialize(transaction_uuid = nil, job_id = nil)
  @running = false
  @splayed = false
  @cached_catalog_status = 'not_used'
  @environment = Puppet[:environment]
  @transaction_uuid = transaction_uuid || SecureRandom.uuid
  @job_id = job_id
  @static_catalog = true
  @checksum_type = Puppet[:supported_checksum_types]
  @handler = Puppet::Configurer::PluginHandler.new()
end

Instance Attribute Details

#environmentObject (readonly)

Returns the value of attribute environment


19
20
21
# File 'lib/puppet/configurer.rb', line 19

def environment
  @environment
end

Class Method Details

.should_pluginsync?Boolean


26
27
28
29
30
31
32
# File 'lib/puppet/configurer.rb', line 26

def self.should_pluginsync?
  if Puppet[:use_cached_catalog]
    false
  else
    true
  end
end

.to_sObject

Provide more helpful strings to the logging that the Agent does


22
23
24
# File 'lib/puppet/configurer.rb', line 22

def self.to_s
  _("Puppet configuration client")
end

Instance Method Details

#apply_catalog(catalog, options) ⇒ Object

Apply supplied catalog and return associated application report


188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/puppet/configurer.rb', line 188

def apply_catalog(catalog, options)
  report = options[:report]
  report.configuration_version = catalog.version

  benchmark(:notice, _("Applied catalog in %{seconds} seconds")) do
    apply_catalog_time = thinmark do
      catalog.apply(options)
    end
    options[:report].add_times(:catalog_application, apply_catalog_time)
  end

  report
end

#convert_catalog(result, duration, options = {}) ⇒ Object

Convert a plain resource catalog into our full host catalog.


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/puppet/configurer.rb', line 103

def convert_catalog(result, duration, options = {})
  catalog = nil

  catalog_conversion_time = thinmark do
    # Will mutate the result and replace all Deferred values with resolved values
    facts = options[:convert_with_facts]
    if facts
      Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(facts, result)
    end

    catalog = result.to_ral
    catalog.finalize
    catalog.retrieval_duration = duration
    catalog.write_class_file
    catalog.write_resource_file
  end
  options[:report].add_times(:convert_catalog, catalog_conversion_time) if options[:report]

  catalog
end

#execute_postrun_commandObject


34
35
36
# File 'lib/puppet/configurer.rb', line 34

def execute_postrun_command
  execute_from_setting(:postrun_command)
end

#execute_prerun_commandObject


38
39
40
# File 'lib/puppet/configurer.rb', line 38

def execute_prerun_command
  execute_from_setting(:prerun_command)
end

#get_facts(options) ⇒ Object


124
125
126
127
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/configurer.rb', line 124

def get_facts(options)
  if options[:pluginsync]
    plugin_sync_time = thinmark do
      remote_environment_for_plugins = Puppet::Node::Environment.remote(@environment)
      download_plugins(remote_environment_for_plugins)

      Puppet::GettextConfig.reset_text_domain('agent')
      Puppet::ModuleTranslations.load_from_vardir(Puppet[:vardir])
    end
    options[:report].add_times(:plugin_sync, plugin_sync_time) if options[:report]
  end

  facts_hash = {}
  if Puppet::Resource::Catalog.indirection.terminus_class == :rest
    # This is a bit complicated.  We need the serialized and escaped facts,
    # and we need to know which format they're encoded in.  Thus, we
    # get a hash with both of these pieces of information.
    #
    # facts_for_uploading may set Puppet[:node_name_value] as a side effect
    facter_time = thinmark do
      facts = find_facts
      options[:convert_with_facts] =  facts
      facts_hash = encode_facts(facts) # encode for uploading # was: facts_for_uploading
    end
    options[:report].add_times(:fact_generation, facter_time) if options[:report]
  end
  facts_hash
end

#init_storageObject

Initialize and load storage


43
44
45
46
47
48
49
50
51
52
53
# File 'lib/puppet/configurer.rb', line 43

def init_storage
    Puppet::Util::Storage.load
rescue => detail
  Puppet.log_exception(detail, _("Removing corrupt state file %{file}: %{detail}") % { file: Puppet[:statefile], detail: detail })
  begin
    Puppet::FileSystem.unlink(Puppet[:statefile])
    retry
  rescue => detail
    raise Puppet::Error.new(_("Cannot remove %{file}: %{detail}") % { file: Puppet[:statefile], detail: detail }, detail)
  end
end

#prepare_and_retrieve_catalog(options, query_options) ⇒ Object


153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/puppet/configurer.rb', line 153

def prepare_and_retrieve_catalog(options, query_options)
  # set report host name now that we have the fact
  options[:report].host = Puppet[:node_name_value]
  query_options[:transaction_uuid] = @transaction_uuid
  query_options[:job_id] = @job_id
  query_options[:static_catalog] = @static_catalog

  # Query params don't enforce ordered evaluation, so munge this list into a
  # dot-separated string.
  query_options[:checksum_type] = @checksum_type.join('.')

  # apply passes in ral catalog
  catalog = options.delete(:catalog)
  return catalog if catalog

  # retrieve_catalog returns json catalog
  catalog = retrieve_catalog(query_options)
  return convert_catalog(catalog, @duration, options) if catalog

  Puppet.err _("Could not retrieve catalog; skipping run")
  nil
end

#prepare_and_retrieve_catalog_from_cache(options = {}) ⇒ Object


176
177
178
179
180
181
182
183
184
185
# File 'lib/puppet/configurer.rb', line 176

def prepare_and_retrieve_catalog_from_cache(options = {})
  result = retrieve_catalog_from_cache({:transaction_uuid => @transaction_uuid, :static_catalog => @static_catalog})
  if result
    Puppet.info _("Using cached catalog from environment '%{catalog_env}'") % { catalog_env: result.environment }
    # get facts now so that the convert_catalog method can resolve deferred values
    get_facts(options)
    return convert_catalog(result, @duration, options)
  end
  nil
end

#resubmit_factstrue, false

Submit updated facts to the Puppet Server

This method will clear all current fact values, load a fresh set of fact data, and then submit it to the Puppet Server.


453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/puppet/configurer.rb', line 453

def resubmit_facts
  ::Facter.clear
  facts = find_facts

  saved_fact_terminus = Puppet::Node::Facts.indirection.terminus_class
  begin
    Puppet::Node::Facts.indirection.terminus_class = :rest

    server = Puppet::Node::Facts::Rest.server
    Puppet.info(_("Uploading facts for %{node} to %{server}") % {
                  node: facts.name,
                  server: server})

    Puppet::Node::Facts.indirection.save(facts, nil, :environment => Puppet::Node::Environment.remote(@environment))

    return true
  ensure
    Puppet::Node::Facts.indirection.terminus_class = saved_fact_terminus
  end
rescue => detail
  Puppet.log_exception(detail, _("Failed to submit facts: %{detail}") %
                               { detail: detail })

  return false
end

#retrieve_catalog(query_options) ⇒ Object

Get the remote catalog, yo. Returns nil if no catalog can be found.


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
# File 'lib/puppet/configurer.rb', line 68

def retrieve_catalog(query_options)
  query_options ||= {}
  result = retrieve_catalog_from_cache(query_options) if Puppet[:use_cached_catalog]
  if result
    @cached_catalog_status = 'explicitly_requested'

    Puppet.info _("Using cached catalog from environment '%{environment}'") % { environment: result.environment }
  else
    result = retrieve_new_catalog(query_options)

    if !result
      if !Puppet[:usecacheonfailure]
        Puppet.warning _("Not using cache on failed catalog")
        return nil
      end

      result = retrieve_catalog_from_cache(query_options)

      if result
        # don't use use cached catalog if it doesn't match server specified environment
        if @node_environment && result.environment != @environment
          Puppet.err _("Not using cached catalog because its environment '%{catalog_env}' does not match '%{local_env}'") % { catalog_env: result.environment, local_env: @environment }
          return nil
        end

        @cached_catalog_status = 'on_failure'
        Puppet.info _("Using cached catalog from environment '%{catalog_env}'") % { catalog_env: result.environment }
      end
    end
  end

  result
end

#run(options = {}) ⇒ Object

The code that actually runs the catalog. This just passes any options on to the catalog, which accepts :tags and :ignoreschedules.


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/puppet/configurer.rb', line 205

def run(options = {})
  pool = Puppet::Network::HTTP::Pool.new(Puppet[:http_keepalive_timeout])
  # We create the report pre-populated with default settings for
  # environment and transaction_uuid very early, this is to ensure
  # they are sent regardless of any catalog compilation failures or
  # exceptions.
  options[:report] ||= Puppet::Transaction::Report.new(nil, @environment, @transaction_uuid, @job_id)
  report = options[:report]
  init_storage

  Puppet::Util::Log.newdestination(report)

  completed = nil
  begin
    Puppet.override(:http_pool => pool) do

      # Skip failover logic if the server_list setting is empty
      if Puppet.settings[:server_list].nil? || Puppet.settings[:server_list].empty?
        do_failover = false
      else
        do_failover = true
      end
      # When we are passed a catalog, that means we're in apply
      # mode. We shouldn't try to do any failover in that case.
      if options[:catalog].nil? && do_failover
        server, port = find_functional_server
        if server.nil?
          raise Puppet::Error, _("Could not select a functional puppet master from server_list: '%{server_list}'") % { server_list: Puppet.settings.value(:server_list, Puppet[:environment].to_sym, true) }
        else
          #TRANSLATORS 'server_list' is the name of a setting and should not be translated
          Puppet.debug _("Selected puppet server from the `server_list` setting: %{server}:%{port}") % { server: server, port: port }
          report.master_used = "#{server}:#{port}"
        end
        Puppet.override(server: server, serverport: port) do
          completed = run_internal(options)
        end
      else
        completed = run_internal(options)
      end
    end
  ensure
    pool.close
  end

  completed ? report.exit_status : nil
end

#save_last_run_summary(report) ⇒ Object


436
437
438
439
440
441
442
443
# File 'lib/puppet/configurer.rb', line 436

def save_last_run_summary(report)
  mode = Puppet.settings.setting(:lastrunfile).mode
  Puppet::Util.replace_file(Puppet[:lastrunfile], mode) do |fh|
    fh.print YAML.dump(report.raw_summary)
  end
rescue => detail
  Puppet.log_exception(detail, _("Could not save last run local report: %{detail}") % { detail: detail })
end

#send_report(report) ⇒ Object


428
429
430
431
432
433
434
# File 'lib/puppet/configurer.rb', line 428

def send_report(report)
  puts report.summary if Puppet[:summarize]
  save_last_run_summary(report)
  Puppet::Transaction::Report.indirection.save(report, nil, :environment => Puppet::Node::Environment.remote(@environment)) if Puppet[:report]
rescue => detail
  Puppet.log_exception(detail, _("Could not send report: %{detail}") % { detail: detail })
end