class Puppet::Application::Apply

Public Instance Methods

app_defaults() click to toggle source
Calls superclass method Puppet::Application#app_defaults
    # File lib/puppet/application/apply.rb
172 def app_defaults
173   super.merge({
174     :default_file_terminus => :file_server,
175     :write_catalog_summary => false
176   })
177 end
apply() click to toggle source
    # File lib/puppet/application/apply.rb
192 def apply
193   if options[:catalog] == "-"
194     text = $stdin.read
195   else
196     text = Puppet::FileSystem.read(options[:catalog], :encoding => 'utf-8')
197   end
198   env = Puppet.lookup(:environments).get(Puppet[:environment])
199   Puppet.override(:current_environment => env, :loaders => create_loaders(env)) do
200     catalog = read_catalog(text)
201     apply_catalog(catalog)
202   end
203 end
help() click to toggle source
    # File lib/puppet/application/apply.rb
 41   def help
 42     <<-HELP
 43 
 44 puppet-apply(8) -- #{summary}
 45 ========
 46 
 47 SYNOPSIS
 48 --------
 49 Applies a standalone Puppet manifest to the local system.
 50 
 51 
 52 USAGE
 53 -----
 54 puppet apply [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
 55   [-e|--execute] [--detailed-exitcodes] [-L|--loadclasses]
 56   [-l|--logdest syslog|eventlog|<ABS FILEPATH>|console] [--noop]
 57   [--catalog <catalog>] [--write-catalog-summary] <file>
 58 
 59 
 60 DESCRIPTION
 61 -----------
 62 This is the standalone puppet execution tool; use it to apply
 63 individual manifests.
 64 
 65 When provided with a modulepath, via command line or config file, puppet
 66 apply can effectively mimic the catalog that would be served by puppet
 67 master with access to the same modules, although there are some subtle
 68 differences. When combined with scheduling and an automated system for
 69 pushing manifests, this can be used to implement a serverless Puppet
 70 site.
 71 
 72 Most users should use 'puppet agent' and 'puppet master' for site-wide
 73 manifests.
 74 
 75 
 76 OPTIONS
 77 -------
 78 Any setting that's valid in the configuration
 79 file is a valid long argument for puppet apply. For example, 'tags' is a
 80 valid setting, so you can specify '--tags <class>,<tag>'
 81 as an argument.
 82 
 83 See the configuration file documentation at
 84 https://puppet.com/docs/puppet/latest/configuration.html for the
 85 full list of acceptable parameters. You can generate a commented list of all
 86 configuration options by running puppet with
 87 '--genconfig'.
 88 
 89 * --debug:
 90   Enable full debugging.
 91 
 92 * --detailed-exitcodes:
 93   Provide extra information about the run via exit codes. If enabled, 'puppet
 94   apply' will use the following exit codes:
 95 
 96   0: The run succeeded with no changes or failures; the system was already in
 97   the desired state.
 98 
 99   1: The run failed.
100 
101   2: The run succeeded, and some resources were changed.
102 
103   4: The run succeeded, and some resources failed.
104 
105   6: The run succeeded, and included both changes and failures.
106 
107 * --help:
108   Print this help message
109 
110 * --loadclasses:
111   Load any stored classes. 'puppet agent' caches configured classes
112   (usually at /etc/puppetlabs/puppet/classes.txt), and setting this option causes
113   all of those classes to be set in your puppet manifest.
114 
115 * --logdest:
116   Where to send log messages. Choose between 'syslog' (the POSIX syslog
117   service), 'eventlog' (the Windows Event Log), 'console', or the path to a log
118   file. Defaults to 'console'.
119   Multiple destinations can be set using a comma separated list
120   (eg: `/path/file1,console,/path/file2`)"
121 
122   A path ending with '.json' will receive structured output in JSON format. The
123   log file will not have an ending ']' automatically written to it due to the
124   appending nature of logging. It must be appended manually to make the content
125   valid JSON.
126 
127   A path ending with '.jsonl' will receive structured output in JSON Lines
128   format.
129 
130 * --noop:
131   Use 'noop' mode where Puppet runs in a no-op or dry-run mode. This
132   is useful for seeing what changes Puppet will make without actually
133   executing the changes.
134 
135 * --execute:
136   Execute a specific piece of Puppet code
137 
138 * --test:
139   Enable the most common options used for testing. These are 'verbose',
140   'detailed-exitcodes' and 'show_diff'.
141 
142 * --verbose:
143   Print extra information.
144 
145 * --catalog:
146   Apply a JSON catalog (such as one generated with 'puppet master --compile'). You can
147   either specify a JSON file or pipe in JSON from standard input.
148 
149 * --write-catalog-summary
150   After compiling the catalog saves the resource list and classes list to the node
151   in the state directory named classes.txt and resources.txt
152 
153 EXAMPLE
154 -------
155     $ puppet apply -l /tmp/manifest.log manifest.pp
156     $ puppet apply --modulepath=/root/dev/modules -e "include ntpd::server"
157     $ puppet apply --catalog catalog.json
158 
159 
160 AUTHOR
161 ------
162 Luke Kanies
163 
164 
165 COPYRIGHT
166 ---------
167 Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
168 
169     HELP
170   end
main() click to toggle source
    # File lib/puppet/application/apply.rb
205 def main
206   manifest          = get_manifest() # Get either a manifest or nil if apply should use content of Puppet[:code]
207   splay                              # splay if needed
208   facts             = get_facts()    # facts or nil
209   node              = get_node()     # node or error
210   apply_environment = get_configured_environment(node, manifest)
211 
212   # TRANSLATORS "puppet apply" is a program command and should not be translated
213   Puppet.override({:current_environment => apply_environment, :loaders => create_loaders(apply_environment)}, _("For puppet apply")) do
214     configure_node_facts(node, facts)
215 
216     # Allow users to load the classes that puppet agent creates.
217     if options[:loadclasses]
218       file = Puppet[:classfile]
219       if Puppet::FileSystem.exist?(file)
220         unless FileTest.readable?(file)
221           $stderr.puts _("%{file} is not readable") % { file: file }
222           exit(63)
223         end
224         node.classes = Puppet::FileSystem.read(file, :encoding => 'utf-8').split(/[\s]+/)
225       end
226     end
227 
228     begin
229       # Compile the catalog
230       starttime = Time.now
231 
232       # When compiling, the compiler traps and logs certain errors
233       # Those that do not lead to an immediate exit are caught by the general
234       # rule and gets logged.
235       #
236       catalog =
237       begin
238         Puppet::Resource::Catalog.indirection.find(node.name, :use_node => node)
239       rescue Puppet::Error
240         # already logged and handled by the compiler, including Puppet::ParseErrorWithIssue
241         exit(1)
242       end
243 
244       # Resolve all deferred values and replace them / mutate the catalog
245       Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog, apply_environment, Puppet[:preprocess_deferred])
246 
247       # Translate it to a RAL catalog
248       catalog = catalog.to_ral
249 
250       catalog.finalize
251 
252       catalog.retrieval_duration = Time.now - starttime
253 
254       # We accept either the global option `--write_catalog_summary`
255       # corresponding to the new setting, or the application option
256       # `--write-catalog-summary`. The latter is needed to maintain backwards
257       # compatibility.
258       #
259       # Puppet settings parse global options using PuppetOptionParser, but it
260       # only recognizes underscores, not dashes.
261       # The base application parses app specific options using ruby's builtin
262       # OptionParser. As of ruby 2.4, it will accept either underscores or
263       # dashes, but prefer dashes.
264       #
265       # So if underscores are used, the PuppetOptionParser will parse it and
266       # store that in Puppet[:write_catalog_summary]. If dashes are used,
267       # OptionParser will parse it, and set Puppet[:write_catalog_summary]. In
268       # either case, settings will contain the correct value.
269       if Puppet[:write_catalog_summary]
270         catalog.write_class_file
271         catalog.write_resource_file
272       end
273 
274       exit_status = apply_catalog(catalog)
275 
276       if not exit_status
277         exit(1)
278       elsif options[:detailed_exitcodes] then
279         exit(exit_status)
280       else
281         exit(0)
282       end
283     rescue => detail
284       Puppet.log_exception(detail)
285       exit(1)
286     end
287   end
288 end
run_command() click to toggle source
    # File lib/puppet/application/apply.rb
179 def run_command
180   if options[:catalog]
181     apply
182   else
183     main
184   end
185 ensure
186   if @profiler
187     Puppet::Util::Profiler.remove_profiler(@profiler)
188     @profiler.shutdown
189   end
190 end
setup() click to toggle source
    # File lib/puppet/application/apply.rb
298 def setup
299   setup_test if options[:test]
300 
301   exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
302 
303   handle_logdest_arg(Puppet[:logdest])
304   Puppet::Util::Log.newdestination(:console) unless options[:setdest]
305 
306   Signal.trap(:INT) do
307     $stderr.puts _("Exiting")
308     exit(1)
309   end
310 
311   Puppet.settings.use :main, :agent, :ssl
312 
313 
314   if Puppet[:catalog_cache_terminus]
315     Puppet::Resource::Catalog.indirection.cache_class = Puppet[:catalog_cache_terminus]
316   end
317 
318   # we want the last report to be persisted locally
319   Puppet::Transaction::Report.indirection.cache_class = :yaml
320 
321   set_log_level
322 
323   if Puppet[:profile]
324     @profiler = Puppet::Util::Profiler.add_profiler(Puppet::Util::Profiler::Aggregate.new(Puppet.method(:info), "apply"))
325   end
326 end
setup_test() click to toggle source

Enable all of the most common test options.

    # File lib/puppet/application/apply.rb
291 def setup_test
292   Puppet.settings.handlearg("--no-splay")
293   Puppet.settings.handlearg("--show_diff")
294   options[:verbose] = true
295   options[:detailed_exitcodes] = true
296 end
summary() click to toggle source
   # File lib/puppet/application/apply.rb
37 def summary
38   _("Apply Puppet manifests locally")
39 end

Private Instance Methods

apply_catalog(catalog) click to toggle source
    # File lib/puppet/application/apply.rb
360 def apply_catalog(catalog)
361   configurer = Puppet::Configurer.new
362   configurer.run(:catalog => catalog, :pluginsync => false)
363 end
configure_node_facts(node, facts) click to toggle source

Mixes the facts into the node, and mixes in server facts

    # File lib/puppet/application/apply.rb
424 def configure_node_facts(node, facts)
425   node.merge(facts.values) if facts
426   # Add server facts so $server_facts[environment] exists when doing a puppet apply
427   node.add_server_facts({})
428 end
create_loaders(env) click to toggle source
    # File lib/puppet/application/apply.rb
330 def create_loaders(env)
331   # Ignore both 'cached_puppet_lib' and pcore resource type loaders
332   Puppet::Pops::Loaders.new(env, false, false)
333 end
get_configured_environment(node, manifest = nil) click to toggle source

Returns a configured environment, if a manifest is given it overrides what is configured for the environment specified by the node (or the current_environment found in the Puppet context). The node's resolved environment is modified if needed.

    # File lib/puppet/application/apply.rb
407 def get_configured_environment(node, manifest = nil)
408   configured_environment = node.environment || Puppet.lookup(:current_environment)
409 
410   apply_environment = manifest ?
411     configured_environment.override_with(:manifest => manifest) :
412     configured_environment
413 
414   # Modify the node descriptor to use the special apply_environment.
415   # It is based on the actual environment from the node, or the locally
416   # configured environment if the node does not specify one.
417   # If a manifest file is passed on the command line, it overrides
418   # the :manifest setting of the apply_environment.
419   node.environment = apply_environment
420   apply_environment
421 end
get_facts() click to toggle source

Returns facts or nil

    # File lib/puppet/application/apply.rb
367 def get_facts()
368   facts = nil
369   unless Puppet[:node_name_fact].empty?
370     # Collect our facts.
371     facts = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value])
372     raise _("Could not find facts for %{node}") % { node: Puppet[:node_name_value] } unless facts
373 
374     Puppet[:node_name_value] = facts.values[Puppet[:node_name_fact]]
375     facts.name = Puppet[:node_name_value]
376   end
377   facts
378 end
get_manifest() click to toggle source

Returns either a manifest (filename) or nil if apply should use content of Puppet

    # File lib/puppet/application/apply.rb
390 def get_manifest()
391   manifest = nil
392   # Set our code or file to use.
393   if options[:code] or command_line.args.length == 0
394     Puppet[:code] = options[:code] || STDIN.read
395   else
396     manifest = command_line.args.shift
397     raise _("Could not find file %{manifest}") % { manifest: manifest } unless Puppet::FileSystem.exist?(manifest)
398     Puppet.warning(_("Only one file can be applied per run.  Skipping %{files}") % { files: command_line.args.join(', ') }) if command_line.args.size > 0
399   end
400   manifest
401 end
get_node() click to toggle source

Returns the node or raises and error if node not found.

    # File lib/puppet/application/apply.rb
382 def get_node()
383   node = Puppet::Node.indirection.find(Puppet[:node_name_value])
384   raise _("Could not find node %{node}") % { node: Puppet[:node_name_value] } unless node
385   node
386 end
read_catalog(text) click to toggle source
    # File lib/puppet/application/apply.rb
335 def read_catalog(text)
336   facts = get_facts()
337   node = get_node()
338   configured_environment = get_configured_environment(node)
339 
340   # TRANSLATORS "puppet apply" is a program command and should not be translated
341   Puppet.override({:current_environment => configured_environment}, _("For puppet apply")) do
342     configure_node_facts(node, facts)
343 
344     # NOTE: Does not set rich_data = true automatically (which would ensure always reading catalog with rich data
345     # on (seemingly the right thing to do)), but that would remove the ability to test what happens when a
346     # rich catalog is processed without rich_data being turned on.
347     format = Puppet::Resource::Catalog.default_format
348     begin
349       catalog = Puppet::Resource::Catalog.convert_from(format, text)
350     rescue => detail
351       raise Puppet::Error, _("Could not deserialize catalog from %{format}: %{detail}") % { format: format, detail: detail }, detail.backtrace
352     end
353     # Resolve all deferred values and replace them / mutate the catalog
354     Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog, configured_environment, Puppet[:preprocess_deferred])
355 
356     catalog.to_ral
357   end
358 end