Skip to content

Commit

Permalink
allow config for callbaks and some fixes
Browse files Browse the repository at this point in the history
 * only complain about ini deprecation if value is set
 * set plugin config for stdout and other types
 * updated plugin docs, moved several plugins to new config
 * finished ssh docs
 * fixed some issues seen in plugins while modifying docs
 * placeholder for 'required'
 * callbacks must use _plugin_options as _options already in use
  • Loading branch information
bcoca authored and abadger committed Sep 11, 2017
1 parent 942b6fb commit 869a318
Show file tree
Hide file tree
Showing 19 changed files with 479 additions and 401 deletions.
13 changes: 11 additions & 2 deletions lib/ansible/config/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,15 @@ def _find_yaml_config_files(self):
''' Load YAML Config Files in order, check merge flags, keep origin of settings'''
pass

def get_plugin_options(self, plugin_type, name, variables=None):

options = {}
defs = self.get_configuration_definitions(plugin_type, name)
for option in defs:
options[option] = self.get_config_value(option, plugin_type=plugin_type, plugin_name=name, variables=variables)

return options

def get_configuration_definitions(self, plugin_type=None, name=None):
''' just list the possible settings, either base or for specific plugins or plugin '''

Expand All @@ -224,7 +233,7 @@ def get_configuration_definitions(self, plugin_type=None, name=None):
elif name is None:
ret = self._plugins.get(plugin_type, {})
else:
ret = {name: self._plugins.get(plugin_type, {}).get(name, {})}
ret = self._plugins.get(plugin_type, {}).get(name, {})

return ret

Expand Down Expand Up @@ -287,7 +296,7 @@ def get_config_value_and_origin(self, config, cfile=None, plugin_type=None, plug
for ini_entry in defs[config]['ini']:
value = get_ini_config_value(self._parser, ini_entry)
origin = cfile
if 'deprecated' in ini_entry:
if value is not None and 'deprecated' in ini_entry:
self.DEPRECATED.append(('[%s]%s' % (ini_entry['section'], ini_entry['key']), ini_entry['deprecated']))
except Exception as e:
sys.stderr.write("Error while loading ini config %s: %s" % (cfile, to_native(e)))
Expand Down
7 changes: 5 additions & 2 deletions lib/ansible/executor/task_queue_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ def load_callbacks(self):
raise AnsibleError("Invalid callback for stdout specified: %s" % self._stdout_callback)
else:
self._stdout_callback = callback_loader.get(self._stdout_callback)
self._stdout_callback.set_options(C.config.get_plugin_options('callback', self._stdout_callback._load_name))
stdout_callback_loaded = True
else:
raise AnsibleError("callback must be an instance of CallbackBase or the name of a callback plugin")
Expand All @@ -198,7 +199,9 @@ def load_callbacks(self):
C.DEFAULT_CALLBACK_WHITELIST is None or callback_name not in C.DEFAULT_CALLBACK_WHITELIST)):
continue

self._callback_plugins.append(callback_plugin())
callback_obj = callback_plugin()
callback_obj .set_options(C.config.get_plugin_options('callback', callback_plugin._load_name))
self._callback_plugins.append(callback_obj)

self._callbacks_loaded = True

Expand Down Expand Up @@ -366,4 +369,4 @@ def send_callback(self, method_name, *args, **kwargs):
display.warning(u"Failure using method (%s) in callback plugin (%s): %s" % (to_text(method_name), to_text(callback_plugin), to_text(e)))
from traceback import format_tb
from sys import exc_info
display.debug('Callback Exception: \n' + ' '.join(format_tb(exc_info()[2])))
display.vvv('Callback Exception: \n' + ' '.join(format_tb(exc_info()[2])))
21 changes: 14 additions & 7 deletions lib/ansible/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from abc import ABCMeta

from ansible import constants as C
from ansible.module_utils.six import with_metaclass
from ansible.module_utils.six import with_metaclass, string_types

try:
from __main__ import display
Expand All @@ -39,22 +39,29 @@


def get_plugin_class(obj):
return obj.__class__.__name__.lower().replace('module', '')
if isinstance(obj, string_types):
return obj.lower().replace('module', '')
else:
return obj.__class__.__name__.lower().replace('module', '')


class AnsiblePlugin(with_metaclass(ABCMeta, object)):

def __init__(self):
self.options = {}
self._options = {}

def get_option(self, option, hostvars=None):
if option not in self.options:
if option not in self._options:
option_value = C.config.get_config_value(option, plugin_type=get_plugin_class(self), plugin_name=self.name, variables=hostvars)
self.set_option(option, option_value)
return self.options.get(option)
return self._options.get(option)

def set_option(self, option, value):
self.options[option] = value
self._options[option] = value

def set_options(self, options):
self.options = options
self._options = options

def _check_required(self):
# FIXME: standarize required check based on config
pass
15 changes: 13 additions & 2 deletions lib/ansible/plugins/callback/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from copy import deepcopy

from ansible import constants as C
from ansible.plugins import AnsiblePlugin
from ansible.module_utils._text import to_text
from ansible.utils.color import stringc
from ansible.vars.manager import strip_internal_keys
Expand All @@ -45,15 +46,16 @@
__all__ = ["CallbackBase"]


class CallbackBase:
class CallbackBase(AnsiblePlugin):

'''
This is a base ansible callback class that does nothing. New callbacks should
use this class as a base and override any callback methods they wish to execute
custom actions.
'''

def __init__(self, display=None):
def __init__(self, display=None, options=None):

if display:
self._display = display
else:
Expand All @@ -70,9 +72,18 @@ def __init__(self, display=None):
version = getattr(self, 'CALLBACK_VERSION', '1.0')
self._display.vvvv('Loading callback plugin %s of type %s, v%s from %s' % (name, ctype, version, __file__))

self.disabled = False

self._plugin_options = {}
if options is not None:
self.set_options(options)

''' helper for callbacks, so they don't all have to include deepcopy '''
_copy_result = deepcopy

def set_options(self, options):
self._plugin_options = options

def _dump_results(self, result, indent=None, sort_keys=True, keep_invocation=False):
if result.get('_ansible_no_log', False):
return json.dumps(dict(censored="the output has been hidden due to the fact that 'no_log: true' was specified for this result"))
Expand Down
16 changes: 8 additions & 8 deletions lib/ansible/plugins/callback/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
show_skipped_hosts:
name: Show skipped hosts
description: "Toggle to control displaying skipped task/host results in a task"
default: True
env:
- name: DISPLAY_SKIPPED_HOSTS
ini:
- key: display_skipped_hosts
section: defaults
type: boolean
default: True
show_custom_stats:
name: Show custom stats
default: False
description: 'This adds the custom stats set via the set_stats plugin to the play recap'
default: False
env:
- name: ANSIBLE_SHOW_CUSTOM_STATS
ini:
Expand Down Expand Up @@ -119,7 +119,7 @@ def v2_runner_on_ok(self, result):
self._display.display(msg, color=color)

def v2_runner_on_skipped(self, result):
if C.DISPLAY_SKIPPED_HOSTS:
if self._plugin_options['show_skipped_hosts']:

delegated_vars = result._result.get('_ansible_delegated_vars', None)
self._clean_results(result._result, result._task.action)
Expand Down Expand Up @@ -248,7 +248,7 @@ def v2_runner_item_on_failed(self, result):
self._display.display(msg + " (item=%s) => %s" % (self._get_item(result._result), self._dump_results(result._result)), color=C.COLOR_ERROR)

def v2_runner_item_on_skipped(self, result):
if C.DISPLAY_SKIPPED_HOSTS:
if self._plugin_options['show_skipped_hosts']:
self._clean_results(result._result, result._task.action)
msg = "skipping: [%s] => (item=%s) " % (result._host.get_name(), self._get_item(result._result))
if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result:
Expand Down Expand Up @@ -287,7 +287,7 @@ def v2_playbook_on_stats(self, stats):
self._display.display("", screen_only=True)

# print custom stats
if C.SHOW_CUSTOM_STATS and stats.custom:
if self._plugin_options['show_custom_stats'] and stats.custom:
self._display.banner("CUSTOM STATS: ")
# per host
# TODO: come up with 'pretty format'
Expand All @@ -308,11 +308,11 @@ def v2_playbook_on_start(self, playbook):
self._display.banner("PLAYBOOK: %s" % basename(playbook._file_name))

if self._display.verbosity > 3:
if self._options is not None:
for option in dir(self._options):
if self._plugin_options is not None:
for option in dir(self._plugin_options):
if option.startswith('_') or option in ['read_file', 'ensure_value', 'read_module']:
continue
val = getattr(self._options, option)
val = getattr(self._plugin_options, option)
if val:
self._display.vvvv('%s: %s' % (option, val))

Expand Down
Loading

0 comments on commit 869a318

Please sign in to comment.