# class Puppet::Application

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

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

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

### Public Instance Methods

[](name) click to toggle source

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

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

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

    # File lib/puppet/application.rb, line 215
    def banner(banner = nil)
      @banner ||= banner
    end

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

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

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

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

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

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

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

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

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

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() 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

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

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

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