class Puppet::Application

This class handles all the aspects of a Puppet application/executable

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.

the option is encountered in the command-line argument.

stores the argument (or true/false if the option doesn’t require an argument) in the global (to the application) options array.

–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 defaul 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 aftect 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

Constants

CommandLineArgs
DOCPATTERN
SHOULD_PARSE_CONFIG_DEPRECATION_MSG

Attributes

run_status[RW]
command_line[R]
options[R]

Public Class Methods

[](name) click to toggle source
# File lib/puppet/application.rb, line 283
def [](name)
  find(name).new
end
available_application_names() click to toggle source

@return [Array<String>] the names of available applications @api public

# 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
banner(banner = nil) click to toggle source
clear!() click to toggle source
# File lib/puppet/application.rb, line 136
def clear!
  self.run_status = nil
end
clear?() click to toggle source

Indicates that Puppet::Application believes that it’s in usual running ::run_mode (no stop/restart request currently active).

# File lib/puppet/application.rb, line 168
def clear?
  run_status.nil?
end
clear_everything_for_tests() click to toggle source

This is for testing only

# File lib/puppet/application.rb, line 302
def clear_everything_for_tests
  @run_mode = @banner = @run_status = @option_parser_commands = nil
end
controlled_run(&block) click to toggle source

Only executes the given block if the run status of Puppet::Application is clear (no restarts, stops, etc. requested). Upon block execution, checks the run status again; if a restart has been requested during the block’s execution, then ::controlled_run will send a new HUP signal to the current process. Thus, long-running background processes can potentially finish their work before a restart.

# File lib/puppet/application.rb, line 177
def controlled_run(&block)
  return unless clear?
  result = block.call
  Process.kill(:HUP, $PID) if restart_requested?
  result
end
exit(code) click to toggle source

this is used for testing

# File lib/puppet/application.rb, line 440
def self.exit(code)
  exit(code)
end
find(application_name) click to toggle source

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`.

@param application_name [String] the name of the application to find (eg. “apply”). @return [Class] the Class instance of the application that was found. @raise [Puppet::Error] if the application class was not found. @raise [LoadError] if there was a problem loading the application file. @api public

# 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
interrupted?() click to toggle source

Indicates that one of stop! or start! was invoked on Puppet::Application, and some kind of process shutdown/short-circuit may be necessary.

# File lib/puppet/application.rb, line 162
def interrupted?
  [:restart_requested, :stop_requested].include? run_status
end
new(command_line = Puppet::Util::CommandLine.new) click to toggle source
# File lib/puppet/application.rb, line 337
def initialize(command_line = Puppet::Util::CommandLine.new)
  @command_line = CommandLineArgs.new(command_line.subcommand_name, command_line.args.dup)
  @options = {}
end
option(*options, &block) click to toggle source

used to declare code that handle an option

# File lib/puppet/application.rb, line 202
def option(*options, &block)
  long = options.find { |opt| opt =~ /^--/ }.gsub(/^--(?:\[no-\])?([^ =]+).*$/, '\1' ).gsub('-','_')
  fname = "handle_#{long}".intern
  if (block_given?)
    define_method(fname, &block)
  else
    define_method(fname) do |value|
      self.options["#{long}".to_sym] = value
    end
  end
  self.option_parser_commands << [options, fname]
end
option_parser_commands() click to toggle source
# File lib/puppet/application.rb, line 219
def option_parser_commands
  @option_parser_commands ||= (
    superclass.respond_to?(:option_parser_commands) ? superclass.option_parser_commands.dup : []
  )
  @option_parser_commands
end
restart!() click to toggle source
# File lib/puppet/application.rb, line 144
def restart!
  self.run_status = :restart_requested
end
restart_requested?() click to toggle source

Indicates that ::restart! has been invoked and components should do what is necessary to facilitate a restart.

# File lib/puppet/application.rb, line 150
def restart_requested?
  :restart_requested == run_status
end
run_mode( mode_name = nil) click to toggle source

Sets or gets the ::run_mode name. Sets the ::run_mode name if a mode_name is passed. Otherwise, gets the ::run_mode or a default ::run_mode

# File lib/puppet/application.rb, line 290
def run_mode( mode_name = nil)
  if mode_name
    Puppet.settings.preferred_run_mode = mode_name
  end

  return @run_mode if @run_mode and not mode_name

  require 'puppet/util/run_mode'
  @run_mode = Puppet::Util::RunMode[ mode_name || Puppet.settings.preferred_run_mode ]
end
should_not_parse_config() click to toggle source
# File lib/puppet/application.rb, line 192
def should_not_parse_config
  Puppet.deprecation_warning("should_not_parse_config " + SHOULD_PARSE_CONFIG_DEPRECATION_MSG)
end
should_parse_config() click to toggle source
# File lib/puppet/application.rb, line 188
def should_parse_config
  Puppet.deprecation_warning("should_parse_config " + SHOULD_PARSE_CONFIG_DEPRECATION_MSG)
end
should_parse_config?() click to toggle source
# File lib/puppet/application.rb, line 196
def should_parse_config?
  Puppet.deprecation_warning("should_parse_config? " + SHOULD_PARSE_CONFIG_DEPRECATION_MSG)
  true
end
stop!() click to toggle source
# File lib/puppet/application.rb, line 140
def stop!
  self.run_status = :stop_requested
end
stop_requested?() click to toggle source

Indicates that ::stop! has been invoked and components should do what is necessary for a clean stop.

# File lib/puppet/application.rb, line 156
def stop_requested?
  :stop_requested == run_status
end

Public Instance Methods

app_defaults() click to toggle source
# File lib/puppet/application.rb, line 323
def app_defaults()
  Puppet::Settings.app_defaults_for_run_mode(self.class.run_mode).merge(
      :name => name
  )
end
configure_indirector_routes() click to toggle source
# File lib/puppet/application.rb, line 392
def configure_indirector_routes
  route_file = Puppet[:route_file]
  if ::File.exists?(route_file)
    routes = YAML.load_file(route_file)
    application_routes = routes[name.to_s]
    Puppet::Indirector.configure_routes(application_routes) if application_routes
  end
end
handlearg(opt, val) click to toggle source
# File lib/puppet/application.rb, line 434
def handlearg(opt, val)
  opt, val = Puppet::Settings.clean_opt(opt, val)
  send(:handle_unknown, opt, val) if respond_to?(:handle_unknown)
end
help() click to toggle source
# File lib/puppet/application.rb, line 448
def help
  "No help available for puppet #{name}"
end
initialize_app_defaults() click to toggle source
# File lib/puppet/application.rb, line 329
def initialize_app_defaults()
  Puppet.settings.initialize_app_defaults(app_defaults)
end
main() click to toggle source
# File lib/puppet/application.rb, line 367
def main
  raise NotImplementedError, "No valid command or main"
end
name() click to toggle source
# File lib/puppet/application.rb, line 444
def name
  self.class.to_s.sub(/.*::/,"").downcase.to_sym
end
parse_options() click to toggle source
# File lib/puppet/application.rb, line 401
def parse_options
  # Create an option parser
  option_parser = OptionParser.new(self.class.banner)

  # He're we're building up all of the options that the application may need to handle.  The main
  # puppet settings defined in "defaults.rb" have already been parsed once (in command_line.rb) by
  # the time we get here; however, our app may wish to handle some of them specially, so we need to
  # make the parser aware of them again.  We might be able to make this a bit more efficient by
  # re-using the parser object that gets built up in command_line.rb.  --cprice 2012-03-16

  # Add all global options to it.
  Puppet.settings.optparse_addargs([]).each do |option|
    option_parser.on(*option) do |arg|
      handlearg(option[0], arg)
    end
  end

  # Add options that are local to this application, which were
  # created using the "option()" metaprogramming method.  If there
  # are any conflicts, this application's options will be favored.
  self.class.option_parser_commands.each do |options, fname|
    option_parser.on(*options) do |value|
      # Call the method that "option()" created.
      self.send(fname, value)
    end
  end

  # Scan command line.  We just hand any exceptions to our upper levels,
  # rather than printing help and exiting, so that we can meaningfully
  # respond with context-sensitive help if we want to. --daniel 2011-04-12
  option_parser.parse!(self.command_line.args)
end
preinit() click to toggle source

override to execute code before running anything else

# File lib/puppet/application.rb, line 334
def preinit
end
run() click to toggle source

Execute the application. @api public @return [void]

# 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

  require 'puppet'
  require 'puppet/util/instrumentation'
  Puppet::Util::Instrumentation.init

  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("run")                                          { plugin_hook('run_command')   { run_command } }
end
run_command() click to toggle source
# File lib/puppet/application.rb, line 371
def run_command
  main
end
setup() click to toggle source
# File lib/puppet/application.rb, line 375
def setup
  setup_logs
end
setup_logs() click to toggle source
# File lib/puppet/application.rb, line 379
def setup_logs
  if options[:debug] or options[:verbose]
    Puppet::Util::Log.newdestination(:console)
    if options[:debug]
      Puppet::Util::Log.level = :debug
    else
      Puppet::Util::Log.level = :info
    end
  end

  Puppet::Util::Log.setup_default unless options[:setdest]
end