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

Enable all of the most common test options.

    # File lib/puppet/application/apply.rb
272 def setup_test
273   Puppet.settings.handlearg("--no-splay")
274   Puppet.settings.handlearg("--show_diff")
275   options[:verbose] = true
276   options[:detailed_exitcodes] = true
277 end
summary() click to toggle source
   # File lib/puppet/application/apply.rb
34 def summary
35   _("Apply Puppet manifests locally")
36 end

Private Instance Methods

apply_catalog(catalog) click to toggle source
    # File lib/puppet/application/apply.rb
341 def apply_catalog(catalog)
342   configurer = Puppet::Configurer.new
343   configurer.run(:catalog => catalog, :pluginsync => false)
344 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
405 def configure_node_facts(node, facts)
406   node.merge(facts.values) if facts
407   # Add server facts so $server_facts[environment] exists when doing a puppet apply
408   node.add_server_facts({})
409 end
create_loaders(env) click to toggle source
    # File lib/puppet/application/apply.rb
311 def create_loaders(env)
312   # Ignore both 'cached_puppet_lib' and pcore resource type loaders
313   Puppet::Pops::Loaders.new(env, false, false)
314 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
388 def get_configured_environment(node, manifest = nil)
389   configured_environment = node.environment || Puppet.lookup(:current_environment)
390 
391   apply_environment = manifest ?
392     configured_environment.override_with(:manifest => manifest) :
393     configured_environment
394 
395   # Modify the node descriptor to use the special apply_environment.
396   # It is based on the actual environment from the node, or the locally
397   # configured environment if the node does not specify one.
398   # If a manifest file is passed on the command line, it overrides
399   # the :manifest setting of the apply_environment.
400   node.environment = apply_environment
401   apply_environment
402 end
get_facts() click to toggle source

Returns facts or nil

    # File lib/puppet/application/apply.rb
348 def get_facts()
349   facts = nil
350   unless Puppet[:node_name_fact].empty?
351     # Collect our facts.
352     facts = Puppet::Node::Facts.indirection.find(Puppet[:node_name_value])
353     raise _("Could not find facts for %{node}") % { node: Puppet[:node_name_value] } unless facts
354 
355     Puppet[:node_name_value] = facts.values[Puppet[:node_name_fact]]
356     facts.name = Puppet[:node_name_value]
357   end
358   facts
359 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
371 def get_manifest()
372   manifest = nil
373   # Set our code or file to use.
374   if options[:code] or command_line.args.length == 0
375     Puppet[:code] = options[:code] || STDIN.read
376   else
377     manifest = command_line.args.shift
378     raise _("Could not find file %{manifest}") % { manifest: manifest } unless Puppet::FileSystem.exist?(manifest)
379     Puppet.warning(_("Only one file can be applied per run.  Skipping %{files}") % { files: command_line.args.join(', ') }) if command_line.args.size > 0
380   end
381   manifest
382 end
get_node() click to toggle source

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

    # File lib/puppet/application/apply.rb
363 def get_node()
364   node = Puppet::Node.indirection.find(Puppet[:node_name_value])
365   raise _("Could not find node %{node}") % { node: Puppet[:node_name_value] } unless node
366   node
367 end
read_catalog(text) click to toggle source
    # File lib/puppet/application/apply.rb
316 def read_catalog(text)
317   facts = get_facts()
318   node = get_node()
319   configured_environment = get_configured_environment(node)
320 
321   # TRANSLATORS "puppet apply" is a program command and should not be translated
322   Puppet.override({:current_environment => configured_environment}, _("For puppet apply")) do
323     configure_node_facts(node, facts)
324 
325     # NOTE: Does not set rich_data = true automatically (which would ensure always reading catalog with rich data
326     # on (seemingly the right thing to do)), but that would remove the ability to test what happens when a
327     # rich catalog is processed without rich_data being turned on.
328     format = Puppet::Resource::Catalog.default_format
329     begin
330       catalog = Puppet::Resource::Catalog.convert_from(format, text)
331     rescue => detail
332       raise Puppet::Error, _("Could not deserialize catalog from %{format}: %{detail}") % { format: format, detail: detail }, detail.backtrace
333     end
334     # Resolve all deferred values and replace them / mutate the catalog
335     Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog, configured_environment)
336 
337     catalog.to_ral
338   end
339 end