Class: Puppet::Application

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/application.rb

Overview

This class handles all the aspects of a Puppet application/executable * setting up options * setting up logs * choosing what to run * representing execution status

=== Usage An application is a subclass of Puppet::Application.

For legacy compatibility, Puppet::Application[:example].run is equivalent to Puppet::Application::Example.new.run

class Puppet::Application::Example < Puppet::Application

def preinit
    # perform some pre initialization
    @all = false
end

# run_command is called to actually run the specified command
def run_command
    send Puppet::Util::CommandLine.new.args.shift
end

# option uses metaprogramming to create a method
# and also tells the option parser how to invoke that method
option("--arg ARGUMENT") do |v|
    @args << v
end

option("--debug", "-d") do |v|
    @debug = v
end

option("--all", "-a:) do |v|
    @all = v
end

def handle_unknown(opt,arg)
    # last chance to manage an option
    ...
    # let's say to the framework we finally handle this option
    true
end

def read
    # read action
end

def write
    # writeaction
end

end

=== Preinit The preinit block is the first code to be called in your application, before option parsing, setup or command execution.

=== Options Puppet::Application uses +OptionParser+ to manage the application options. Options are defined with the +option+ method to which are passed various arguments, including the long option, the short option, a description... Refer to +OptionParser+ documentation for the exact format. * If the option method is given a block, this one will be called whenever the option is encountered in the command-line argument. * If the option method has no block, a default functionnality will be used, that stores the argument (or true/false if the option doesn't require an argument) in the global (to the application) options array. * If a given option was not defined by a the +option+ method, but it exists as a Puppet settings: * if +unknown+ was used with a block, it will be called with the option name and argument * if +unknown+ wasn't used, then the option/argument is handed to Puppet.settings.handlearg for a default behavior

--help is managed directly by the Puppet::Application class, but can be overriden.

=== Setup Applications can use the setup block to perform any initialization. The default +setup+ behaviour is to: read Puppet configuration and manage log level and destination

=== What and how to run If the +dispatch+ block is defined it is called. This block should return the name of the registered command to be run. If it doesn't exist, it defaults to execute the +main+ command if defined.

=== Execution state The class attributes/methods of Puppet::Application serve as a global place to set and query the execution status of the application: stopping, restarting, etc. The setting of the application status does not directly affect its running status; it's assumed that the various components within the application will consult these settings appropriately and affect their own processing accordingly. Control operations (signal handlers and the like) should set the status appropriately to indicate to the overall system that it's the process of stopping or restarting (or just running as usual).

So, if something in your application needs to stop the process, for some reason, you might consider:

def stop_me! # indicate that we're stopping Puppet::Application.stop! # ...do stuff... end

And, if you have some component that involves a long-running process, you might want to consider:

def my_long_process(giant_list_to_munge) giant_list_to_munge.collect do |member| # bail if we're stopping return if Puppet::Application.stop_requested? process_member(member) end end

Constant Summary

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

exit_on_fail, exit_on_fail, which, which

Class Method Details

.available_application_namesArray<String>

Returns the names of available applications



228
229
230
231
232
# File 'lib/puppet/application.rb', line 228

def available_application_names
  @loader.files_to_load.map do |fn|
    ::File.basename(fn, '.rb')
  end.uniq
end

.find(application_name) ⇒ Class

Finds the class for a given application and loads the class. This does not create an instance of the application, it only gets a handle to the class. The code for the application is expected to live in a ruby file puppet/application/#{name}.rb that is available on the $LOAD_PATH.

Raises:

  • (Puppet::Error)

    if the application class was not found.

  • (LoadError)

    if there was a problem loading the application file.



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/puppet/application.rb', line 244

def find(application_name)
  begin
    require @loader.expand(application_name.to_s.downcase)
  rescue LoadError => e
    Puppet.log_and_raise(e, "Unable to find application '#{application_name}'. #{e}")
  end

  class_name = Puppet::Util::ConstantInflector.file2constant(application_name.to_s)

  clazz = try_load_class(class_name)

  ################################################################
  #### Begin 2.7.x backward compatibility hack;
  ####  eventually we need to issue a deprecation warning here,
  ####  and then get rid of this stanza in a subsequent release.
  ################################################################
  if (clazz.nil?)
    class_name = application_name.capitalize
    clazz = try_load_class(class_name)
  end
  ################################################################
  #### End 2.7.x backward compatibility hack
  ################################################################

  if clazz.nil?
    raise Puppet::Error.new("Unable to load application class '#{class_name}' from file 'puppet/application/#{application_name}.rb'")
  end

  return clazz
end

Instance Method Details

#log_runtime_environment(extra_info = nil)

This method returns an undefined value.

Output basic information about the runtime environment for debugging purposes.



440
441
442
443
444
445
446
447
448
449
450
# File 'lib/puppet/application.rb', line 440

def log_runtime_environment(extra_info=nil)
  runtime_info = {
    'puppet_version' => Puppet.version,
    'ruby_version'   => RUBY_VERSION,
    'run_mode'       => self.class.run_mode.name,
  }
  runtime_info['default_encoding'] = Encoding.default_external if RUBY_VERSION >= '1.9.3'
  runtime_info.merge!(extra_info) unless extra_info.nil?

  Puppet.debug 'Runtime environment: ' + runtime_info.map{|k,v| k + '=' + v.to_s}.join(', ')
end

#run

This method returns an undefined value.

Execute the application.



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/puppet/application.rb', line 345

def run

  # I don't really like the names of these lifecycle phases.  It would be nice to change them to some more meaningful
  # names, and make deprecated aliases.  Also, Daniel suggests that we can probably get rid of this "plugin_hook"
  # pattern, but we need to check with PE and the community first.  --cprice 2012-03-16
  #

  exit_on_fail("get application-specific default settings") do
    plugin_hook('initialize_app_defaults') { initialize_app_defaults }
  end

  Puppet.push_context(Puppet.base_context(Puppet.settings), "Update for application settings (#{self.class.run_mode})")
  # This use of configured environment is correct, this is used to establish
  # the defaults for an application that does not override, or where an override
  # has not been made from the command line.
  #
  configured_environment_name = Puppet[:environment]
  if self.class.run_mode.name != :agent
    configured_environment = Puppet.lookup(:environments).get(configured_environment_name)
    if configured_environment.nil?
      fail(Puppet::Environments::EnvironmentNotFound, configured_environment_name)
    end
  else
    configured_environment = Puppet::Node::Environment.remote(configured_environment_name)
  end
  configured_environment = configured_environment.override_from_commandline(Puppet.settings)

  # Setup a new context using the app's configuration
  Puppet.push_context({ :current_environment => configured_environment },
                  "Update current environment from application's configuration")

  exit_on_fail("initialize")                                   { plugin_hook('preinit')       { preinit } }
  exit_on_fail("parse application options")                    { plugin_hook('parse_options') { parse_options } }
  exit_on_fail("prepare for execution")                        { plugin_hook('setup')         { setup } }
  exit_on_fail("configure routes from #{Puppet[:route_file]}") { configure_indirector_routes }
  exit_on_fail("log runtime debug info")                       { log_runtime_environment }
  exit_on_fail("run")                                          { plugin_hook('run_command')   { run_command } }
end