class QB::Ansible::QB::Ansible::QB::Ansible::Module
Attributes
The raw parsed arguments. Used for backwards-compatibility with how {QB::Ansible::Module} used to work before {NRSER::Props} and {#arg}.
@todo
May want to get rid of this once using props is totally flushed out. It should at least be deal with in the constructor somehow so this can be changed to an `attr_reader`.
@return [Hash<String, VALUE>]
Optional information on the source of the arguments.
@return [nil | Hash<Symbol, Object>]
The response that will be returned to Ansible
(JSON-encoded and written to `STDOUT`).
@return [QB::Ansible::Module::Response]
Public Class Methods
Is the module being run from Ansible
via it's “WANT_JSON” mode?
Tests if `argv` is a single string argument that is a file path.
@param [Array<String>] argv
The CLI argument strings.
@return [Boolean]
`true` if `argv` looks like it came from Ansible's "WANT_JSON" mode.
# File lib/qb/ansible/module.rb, line 202 def self.WANT_JSON_mode? argv = ARGV ARGV.length == 1 && File.file?( ARGV[0] ) end
@todo Document arg method.
@param [type] arg_name
@todo Add name param description.
@return [return_type]
@todo Document return value.
# File lib/qb/ansible/module.rb, line 333 def self.arg *args, **opts name, opts = t.match args.length, # Normal {.prop} form 1, ->( _ ){ [ args[0], opts ] }, # Backwards-compatible form 2, ->( _ ){ [ args[0], opts.merge( type: args[1] ) ] } prop name, **opts end
Load the raw arguments.
# File lib/qb/ansible/module.rb, line 245 def self.load_args if WANT_JSON_mode? load_args_from_JSON_file ARGV[0] else load_args_from_CLI_options end end
Load args from a file in JSON format.
@param [String | Pathname] file_path
File path to load from.
@return [Array<(Hash, Hash?)>]
Tuple of: 1. `args:` - `Hash<String, *>` 2. `args_source:` - `nil | Hash{ type: :file, path: String, contents: String }`
# File lib/qb/ansible/module.rb, line 220 def self.load_args_from_JSON_file file_path file_contents = File.read file_path args = JSON.load( file_contents ).with_indifferent_access t.hash_( keys: t.str ).check( args ) do |type:, value:| binding.erb <<~END JSON file contents must load into a `Hash<String, *>` Loaded value (of class <%= value.class %>): <%= value.pretty_inspect %> END end [ args, { type: :file, path: file_path.to_s, contents: file_contents, } ] end
Run the module!
@return (see run!
)
# File lib/qb/ansible/module.rb, line 258 def self.run! handle_run_error do setup_io! args, args_source = load_args run_from_args! args, args_source: args_source end end
Create and run an instance and populate it's args by loading JSON from a file path.
Used to run via Ansible's “WANT_JSON” mode.
@param [String | Pathname] file_path
Path to the JSON file containing the args.
@return (see run!
)
# File lib/qb/ansible/module.rb, line 280 def self.run_from_JSON_args_file! file_path file_contents = File.read file_path args = JSON.load file_contents t.hash_( keys: t.str ).check( args ) do |type:, value:| binding.erb <<~END JSON file contents must load into a `Hash<String, *>` Loaded value (of class <%= value.class %>): <%= value.pretty_inspect %> END end run_from_args! args, args_source: { type: :file, path: file_path, contents: file_contents, } end
Run from a hash-like of argument names mapped to values, with optional info about the source of the arguments.
@param [#each_pair] args
Argument names (String or Symbol) mapped to their value data.
@return (see run!
)
# File lib/qb/ansible/module.rb, line 313 def self.run_from_args! args, args_source: nil logger.trace "Running from args", args: args, args_source: args_source instance = self.from_data args instance.args_source = args_source instance.args = args instance.run! end
# File lib/qb/ansible/module.rb, line 118 def self.setup_io! # Initialize $qb_stdio_client ||= QB::IPC::STDIO::Client.new.connect! if $qb_stdio_client.log.connected? && NRSER::Log.appender.nil? # SemanticLogger::Processor.logger = \ SemanticLogger::Processor.instance.appender.logger = \ SemanticLogger::Appender::File.new( io: $stderr, level: :warn, formatter: Formatters::Processor.new, ) NRSER::Log.setup! \ application: 'qb', sync: true, dest: { io: $qb_stdio_client.log.socket, formatter: Formatters::JSON.new, } end end
Private Class Methods
Wrap a “run” call with error handling.
@private
@param [Proc<() => RESULT] &block
@return [RESULT]
On success, returns the result of `&block`.
@raise [SystemExit]
Any exception raised in `&block` is logged at `fatal` level, then `exit false` is called, raising a {SystemExit} error. The only exception: if `&block` raises a {SystemExit} error, that error is simply re-raised without any logging. This should allow nesting {.handle_run_error} calls, since the first `rescue` will log any error and raise {SystemExit}, which will then simply be bubbled-up by {.handle_run_error} wrappers further up the call chain.
# File lib/qb/ansible/module.rb, line 163 def self.handle_run_error &block begin block.call rescue SystemExit => error # Bubble {SystemExit} up to exit normally raise rescue Exception => error # Everything else is unexpected, and needs to be logged in a way that's # more useful than the JSON-ified crap Ansible would normally print # If we don't have a logger setup, log to real `STDERR` so we get # *something* back in the Ansible output, even if it's JSON mess if NRSER::Log.appender.nil? NRSER::Log.setup! application: 'qb', dest: STDERR end # Log it out logger.fatal error # And GTFO exit false end end
Public Instance Methods
# File lib/qb/ansible/module.rb, line 470 def changed! facts = {} response.changed = true unless facts.empty? response.facts.merge! facts end done end
Forward args to {QB.debug} if we are connected to a QB
STDERR stream (write to STDERR).
@param args see QB.debug
# File lib/qb/ansible/module.rb, line 413 def debug *args logger.debug payload: args end
# File lib/qb/ansible/module.rb, line 481 def done exit_json response.to_data( add_class: false ).compact end
# File lib/qb/ansible/module.rb, line 486 def exit_json hash # print JSON response to process' actual STDOUT (instead of $stdout, # which may be pointing to the qb parent process) STDOUT.print JSON.pretty_generate( hash.stringify_keys ) exit true end
# File lib/qb/ansible/module.rb, line 495 def fail msg, **values fail_response = QB::Ansible::Module::Response.new \ failed: true, msg: msg.to_s, warnings: response.warnings, depreciations: response.depreciations STDOUT.print \ JSON.pretty_generate( fail_response.to_data( add_class: false ).compact ) exit false end
Old logging function - use `#logger.info` instead.
@deprecated
# File lib/qb/ansible/module.rb, line 422 def info msg logger.info msg end
# File lib/qb/ansible/module.rb, line 454 def run! result = main case result when nil # pass when Hash response.facts.merge! result else raise "result of #main should be nil or Hash, found #{ result.inspect }" end done end
Append a warning message to the {#response}'s {Response#warnings} array and log it.
@todo
Should be incorporated into {#logger}? Seems like it would need one of: 1. `on_...` hooks, like `Logger#on_warn`, etc. This might be nice but I'd rather hold off on throwing more shit into {NRSER::Log::Logger} for the time being if possible. 2. Adding a custom appender when we run a module that has a ref to the module instance and so it's {Response}.
@param [String] msg
Non-empty string.
@return [nil]
# File lib/qb/ansible/module.rb, line 447 def warn msg logger.warn msg response.warnings << msg nil end