mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-27 15:11:23 -07:00
allow config for callbaks and some fixes
* 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
This commit is contained in:
parent
942b6fb9bc
commit
869a318492
19 changed files with 480 additions and 402 deletions
|
@ -215,6 +215,15 @@ class ConfigManager(object):
|
||||||
''' Load YAML Config Files in order, check merge flags, keep origin of settings'''
|
''' Load YAML Config Files in order, check merge flags, keep origin of settings'''
|
||||||
pass
|
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):
|
def get_configuration_definitions(self, plugin_type=None, name=None):
|
||||||
''' just list the possible settings, either base or for specific plugins or plugin '''
|
''' just list the possible settings, either base or for specific plugins or plugin '''
|
||||||
|
|
||||||
|
@ -224,7 +233,7 @@ class ConfigManager(object):
|
||||||
elif name is None:
|
elif name is None:
|
||||||
ret = self._plugins.get(plugin_type, {})
|
ret = self._plugins.get(plugin_type, {})
|
||||||
else:
|
else:
|
||||||
ret = {name: self._plugins.get(plugin_type, {}).get(name, {})}
|
ret = self._plugins.get(plugin_type, {}).get(name, {})
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -287,7 +296,7 @@ class ConfigManager(object):
|
||||||
for ini_entry in defs[config]['ini']:
|
for ini_entry in defs[config]['ini']:
|
||||||
value = get_ini_config_value(self._parser, ini_entry)
|
value = get_ini_config_value(self._parser, ini_entry)
|
||||||
origin = cfile
|
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']))
|
self.DEPRECATED.append(('[%s]%s' % (ini_entry['section'], ini_entry['key']), ini_entry['deprecated']))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.stderr.write("Error while loading ini config %s: %s" % (cfile, to_native(e)))
|
sys.stderr.write("Error while loading ini config %s: %s" % (cfile, to_native(e)))
|
||||||
|
|
|
@ -176,6 +176,7 @@ class TaskQueueManager:
|
||||||
raise AnsibleError("Invalid callback for stdout specified: %s" % self._stdout_callback)
|
raise AnsibleError("Invalid callback for stdout specified: %s" % self._stdout_callback)
|
||||||
else:
|
else:
|
||||||
self._stdout_callback = callback_loader.get(self._stdout_callback)
|
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
|
stdout_callback_loaded = True
|
||||||
else:
|
else:
|
||||||
raise AnsibleError("callback must be an instance of CallbackBase or the name of a callback plugin")
|
raise AnsibleError("callback must be an instance of CallbackBase or the name of a callback plugin")
|
||||||
|
@ -198,7 +199,9 @@ class TaskQueueManager:
|
||||||
C.DEFAULT_CALLBACK_WHITELIST is None or callback_name not in C.DEFAULT_CALLBACK_WHITELIST)):
|
C.DEFAULT_CALLBACK_WHITELIST is None or callback_name not in C.DEFAULT_CALLBACK_WHITELIST)):
|
||||||
continue
|
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
|
self._callbacks_loaded = True
|
||||||
|
|
||||||
|
@ -366,4 +369,4 @@ class TaskQueueManager:
|
||||||
display.warning(u"Failure using method (%s) in callback plugin (%s): %s" % (to_text(method_name), to_text(callback_plugin), to_text(e)))
|
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 traceback import format_tb
|
||||||
from sys import exc_info
|
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])))
|
||||||
|
|
|
@ -24,7 +24,7 @@ __metaclass__ = type
|
||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
|
|
||||||
from ansible import constants as C
|
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:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -39,22 +39,29 @@ PLUGIN_PATH_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
def get_plugin_class(obj):
|
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)):
|
class AnsiblePlugin(with_metaclass(ABCMeta, object)):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.options = {}
|
self._options = {}
|
||||||
|
|
||||||
def get_option(self, option, hostvars=None):
|
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)
|
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)
|
self.set_option(option, option_value)
|
||||||
return self.options.get(option)
|
return self._options.get(option)
|
||||||
|
|
||||||
def set_option(self, option, value):
|
def set_option(self, option, value):
|
||||||
self.options[option] = value
|
self._options[option] = value
|
||||||
|
|
||||||
def set_options(self, options):
|
def set_options(self, options):
|
||||||
self.options = options
|
self._options = options
|
||||||
|
|
||||||
|
def _check_required(self):
|
||||||
|
# FIXME: standarize required check based on config
|
||||||
|
pass
|
||||||
|
|
|
@ -26,6 +26,7 @@ import warnings
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
|
from ansible.plugins import AnsiblePlugin
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.utils.color import stringc
|
from ansible.utils.color import stringc
|
||||||
from ansible.vars.manager import strip_internal_keys
|
from ansible.vars.manager import strip_internal_keys
|
||||||
|
@ -45,7 +46,7 @@ except ImportError:
|
||||||
__all__ = ["CallbackBase"]
|
__all__ = ["CallbackBase"]
|
||||||
|
|
||||||
|
|
||||||
class CallbackBase:
|
class CallbackBase(AnsiblePlugin):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
This is a base ansible callback class that does nothing. New callbacks should
|
This is a base ansible callback class that does nothing. New callbacks should
|
||||||
|
@ -53,7 +54,8 @@ class CallbackBase:
|
||||||
custom actions.
|
custom actions.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, display=None):
|
def __init__(self, display=None, options=None):
|
||||||
|
|
||||||
if display:
|
if display:
|
||||||
self._display = display
|
self._display = display
|
||||||
else:
|
else:
|
||||||
|
@ -70,9 +72,18 @@ class CallbackBase:
|
||||||
version = getattr(self, 'CALLBACK_VERSION', '1.0')
|
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._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 '''
|
''' helper for callbacks, so they don't all have to include deepcopy '''
|
||||||
_copy_result = 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):
|
def _dump_results(self, result, indent=None, sort_keys=True, keep_invocation=False):
|
||||||
if result.get('_ansible_no_log', 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"))
|
return json.dumps(dict(censored="the output has been hidden due to the fact that 'no_log: true' was specified for this result"))
|
||||||
|
|
|
@ -14,17 +14,17 @@ DOCUMENTATION:
|
||||||
show_skipped_hosts:
|
show_skipped_hosts:
|
||||||
name: Show skipped hosts
|
name: Show skipped hosts
|
||||||
description: "Toggle to control displaying skipped task/host results in a task"
|
description: "Toggle to control displaying skipped task/host results in a task"
|
||||||
|
default: True
|
||||||
env:
|
env:
|
||||||
- name: DISPLAY_SKIPPED_HOSTS
|
- name: DISPLAY_SKIPPED_HOSTS
|
||||||
ini:
|
ini:
|
||||||
- key: display_skipped_hosts
|
- key: display_skipped_hosts
|
||||||
section: defaults
|
section: defaults
|
||||||
type: boolean
|
type: boolean
|
||||||
default: True
|
|
||||||
show_custom_stats:
|
show_custom_stats:
|
||||||
name: 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'
|
description: 'This adds the custom stats set via the set_stats plugin to the play recap'
|
||||||
|
default: False
|
||||||
env:
|
env:
|
||||||
- name: ANSIBLE_SHOW_CUSTOM_STATS
|
- name: ANSIBLE_SHOW_CUSTOM_STATS
|
||||||
ini:
|
ini:
|
||||||
|
@ -119,7 +119,7 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.display(msg, color=color)
|
self._display.display(msg, color=color)
|
||||||
|
|
||||||
def v2_runner_on_skipped(self, result):
|
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)
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
||||||
self._clean_results(result._result, result._task.action)
|
self._clean_results(result._result, result._task.action)
|
||||||
|
@ -248,7 +248,7 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.display(msg + " (item=%s) => %s" % (self._get_item(result._result), self._dump_results(result._result)), color=C.COLOR_ERROR)
|
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):
|
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)
|
self._clean_results(result._result, result._task.action)
|
||||||
msg = "skipping: [%s] => (item=%s) " % (result._host.get_name(), self._get_item(result._result))
|
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:
|
if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result:
|
||||||
|
@ -287,7 +287,7 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.display("", screen_only=True)
|
self._display.display("", screen_only=True)
|
||||||
|
|
||||||
# print custom stats
|
# 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: ")
|
self._display.banner("CUSTOM STATS: ")
|
||||||
# per host
|
# per host
|
||||||
# TODO: come up with 'pretty format'
|
# TODO: come up with 'pretty format'
|
||||||
|
@ -308,11 +308,11 @@ class CallbackModule(CallbackBase):
|
||||||
self._display.banner("PLAYBOOK: %s" % basename(playbook._file_name))
|
self._display.banner("PLAYBOOK: %s" % basename(playbook._file_name))
|
||||||
|
|
||||||
if self._display.verbosity > 3:
|
if self._display.verbosity > 3:
|
||||||
if self._options is not None:
|
if self._plugin_options is not None:
|
||||||
for option in dir(self._options):
|
for option in dir(self._plugin_options):
|
||||||
if option.startswith('_') or option in ['read_file', 'ensure_value', 'read_module']:
|
if option.startswith('_') or option in ['read_file', 'ensure_value', 'read_module']:
|
||||||
continue
|
continue
|
||||||
val = getattr(self._options, option)
|
val = getattr(self._plugin_options, option)
|
||||||
if val:
|
if val:
|
||||||
self._display.vvvv('%s: %s' % (option, val))
|
self._display.vvvv('%s: %s' % (option, val))
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,14 @@ DOCUMENTATION:
|
||||||
type: notification
|
type: notification
|
||||||
short_description: Sends events to Logentries
|
short_description: Sends events to Logentries
|
||||||
description:
|
description:
|
||||||
- This callback plugin will generate JSON objects and send them to Logentries for auditing/debugging purposes.
|
- This callback plugin will generate JSON objects and send them to Logentries via TCP for auditing/debugging purposes.
|
||||||
- If you want to use an ini configuration, the file must be placed in the same directory as this plugin and named logentries.ini
|
- Before 2.4, if you wanted to use an ini configuration, the file must be placed in the same directory as this plugin and named logentries.ini
|
||||||
|
- In 2.4 and above you can just put it in the main Ansible configuration file.
|
||||||
version_added: "2.0"
|
version_added: "2.0"
|
||||||
requirements:
|
requirements:
|
||||||
- whitelisting in configuration
|
- whitelisting in configuration
|
||||||
- certifi (python library)
|
- certifi (python library)
|
||||||
- flatdict (pytnon library)
|
- flatdict (pytnon library), if you want to use the 'flatten' option
|
||||||
options:
|
options:
|
||||||
api:
|
api:
|
||||||
description: URI to the Logentries API
|
description: URI to the Logentries API
|
||||||
|
@ -22,7 +23,7 @@ DOCUMENTATION:
|
||||||
- name: LOGENTRIES_API
|
- name: LOGENTRIES_API
|
||||||
default: data.logentries.com
|
default: data.logentries.com
|
||||||
ini:
|
ini:
|
||||||
- section: defaults
|
- section: callback_logentries
|
||||||
key: api
|
key: api
|
||||||
port:
|
port:
|
||||||
description: Http port to use when connecting to the API
|
description: Http port to use when connecting to the API
|
||||||
|
@ -30,7 +31,7 @@ DOCUMENTATION:
|
||||||
- name: LOGENTRIES_PORT
|
- name: LOGENTRIES_PORT
|
||||||
default: 80
|
default: 80
|
||||||
ini:
|
ini:
|
||||||
- section: defaults
|
- section: callback_logentries
|
||||||
key: port
|
key: port
|
||||||
tls_port:
|
tls_port:
|
||||||
description: Port to use when connecting to the API when TLS is enabled
|
description: Port to use when connecting to the API when TLS is enabled
|
||||||
|
@ -38,15 +39,15 @@ DOCUMENTATION:
|
||||||
- name: LOGENTRIES_TLS_PORT
|
- name: LOGENTRIES_TLS_PORT
|
||||||
default: 443
|
default: 443
|
||||||
ini:
|
ini:
|
||||||
- section: defaults
|
- section: callback_logentries
|
||||||
key: tls_port
|
key: tls_port
|
||||||
token:
|
token:
|
||||||
description: the authentication token
|
description: The logentries "TCP token"
|
||||||
env:
|
env:
|
||||||
- name: LOGENTRIES_ANSIBLE_TOKEN
|
- name: LOGENTRIES_ANSIBLE_TOKEN
|
||||||
required: True
|
required: True
|
||||||
ini:
|
ini:
|
||||||
- section: defaults
|
- section: callback_logentries
|
||||||
key: token
|
key: token
|
||||||
use_tls:
|
use_tls:
|
||||||
description:
|
description:
|
||||||
|
@ -56,7 +57,7 @@ DOCUMENTATION:
|
||||||
default: False
|
default: False
|
||||||
type: boolean
|
type: boolean
|
||||||
ini:
|
ini:
|
||||||
- section: defaults
|
- section: callback_logentries
|
||||||
key: use_tls
|
key: use_tls
|
||||||
flatten:
|
flatten:
|
||||||
description: flatten complex data structures into a single dictionary with complex keys
|
description: flatten complex data structures into a single dictionary with complex keys
|
||||||
|
@ -65,7 +66,7 @@ DOCUMENTATION:
|
||||||
env:
|
env:
|
||||||
- name: LOGENTRIES_FLATTEN
|
- name: LOGENTRIES_FLATTEN
|
||||||
ini:
|
ini:
|
||||||
- section: defaults
|
- section: callback_logentries
|
||||||
key: flatten
|
key: flatten
|
||||||
EXAMPLES: >
|
EXAMPLES: >
|
||||||
To enable, add this to your ansible.cfg file in the defaults block
|
To enable, add this to your ansible.cfg file in the defaults block
|
||||||
|
@ -78,8 +79,8 @@ EXAMPLES: >
|
||||||
export LOGENTRIES_PORT=10000
|
export LOGENTRIES_PORT=10000
|
||||||
export LOGENTRIES_ANSIBLE_TOKEN=dd21fc88-f00a-43ff-b977-e3a4233c53af
|
export LOGENTRIES_ANSIBLE_TOKEN=dd21fc88-f00a-43ff-b977-e3a4233c53af
|
||||||
|
|
||||||
Or create a logentries.ini config file that sites next to the plugin with the following contents
|
Or in the main Ansible config file
|
||||||
[logentries]
|
[callback_logentries]
|
||||||
api = data.logentries.com
|
api = data.logentries.com
|
||||||
port = 10000
|
port = 10000
|
||||||
tls_port = 20000
|
tls_port = 20000
|
||||||
|
@ -108,8 +109,8 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_FLATDICT = False
|
HAS_FLATDICT = False
|
||||||
|
|
||||||
from ansible.module_utils.six.moves import configparser
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text, to_native
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
"""
|
"""
|
||||||
Todo:
|
Todo:
|
||||||
|
@ -118,11 +119,7 @@ Todo:
|
||||||
|
|
||||||
|
|
||||||
class PlainTextSocketAppender(object):
|
class PlainTextSocketAppender(object):
|
||||||
def __init__(self,
|
def __init__(self, display, LE_API='data.logentries.com', LE_PORT=80, LE_TLS_PORT=443):
|
||||||
verbose=True,
|
|
||||||
LE_API='data.logentries.com',
|
|
||||||
LE_PORT=80,
|
|
||||||
LE_TLS_PORT=443):
|
|
||||||
|
|
||||||
self.LE_API = LE_API
|
self.LE_API = LE_API
|
||||||
self.LE_PORT = LE_PORT
|
self.LE_PORT = LE_PORT
|
||||||
|
@ -134,7 +131,7 @@ class PlainTextSocketAppender(object):
|
||||||
# Unicode Line separator character \u2028
|
# Unicode Line separator character \u2028
|
||||||
self.LINE_SEP = u'\u2028'
|
self.LINE_SEP = u'\u2028'
|
||||||
|
|
||||||
self.verbose = verbose
|
self._display = display
|
||||||
self._conn = None
|
self._conn = None
|
||||||
|
|
||||||
def open_connection(self):
|
def open_connection(self):
|
||||||
|
@ -149,9 +146,8 @@ class PlainTextSocketAppender(object):
|
||||||
try:
|
try:
|
||||||
self.open_connection()
|
self.open_connection()
|
||||||
return
|
return
|
||||||
except Exception:
|
except Exception as e:
|
||||||
if self.verbose:
|
self._display.vvvv("Unable to connect to Logentries: %s" % str(e))
|
||||||
self._display.warning("Unable to connect to Logentries")
|
|
||||||
|
|
||||||
root_delay *= 2
|
root_delay *= 2
|
||||||
if (root_delay > self.MAX_DELAY):
|
if (root_delay > self.MAX_DELAY):
|
||||||
|
@ -160,6 +156,7 @@ class PlainTextSocketAppender(object):
|
||||||
wait_for = root_delay + random.uniform(0, root_delay)
|
wait_for = root_delay + random.uniform(0, root_delay)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
self._display.vvvv("sleeping %s before retry" % wait_for)
|
||||||
time.sleep(wait_for)
|
time.sleep(wait_for)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
|
@ -221,91 +218,76 @@ class CallbackModule(CallbackBase):
|
||||||
CALLBACK_NEEDS_WHITELIST = True
|
CALLBACK_NEEDS_WHITELIST = True
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
# TODO: allow for alternate posting methods (REST/UDP/agent/etc)
|
||||||
super(CallbackModule, self).__init__()
|
super(CallbackModule, self).__init__()
|
||||||
|
|
||||||
|
# verify dependencies
|
||||||
if not HAS_SSL:
|
if not HAS_SSL:
|
||||||
self._display.warning("Unable to import ssl module. Will send over port 80.")
|
self._display.warning("Unable to import ssl module. Will send over port 80.")
|
||||||
|
|
||||||
warn = ''
|
|
||||||
if not HAS_CERTIFI:
|
if not HAS_CERTIFI:
|
||||||
self.disabled = True
|
self.disabled = True
|
||||||
warn += 'The `certifi` python module is not installed.'
|
self._display.warning('The `certifi` python module is not installed.\nDisabling the Logentries callback plugin.')
|
||||||
|
|
||||||
if not HAS_FLATDICT:
|
|
||||||
self.disabled = True
|
|
||||||
warn += 'The `flatdict` python module is not installed.'
|
|
||||||
|
|
||||||
if warn:
|
|
||||||
self._display.warning('%s\nDisabling the Logentries callback plugin.' % warn)
|
|
||||||
|
|
||||||
config_path = os.path.abspath(os.path.dirname(__file__))
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
try:
|
|
||||||
config.readfp(open(os.path.join(config_path, 'logentries.ini')))
|
|
||||||
if config.has_option('logentries', 'api'):
|
|
||||||
self.api_uri = config.get('logentries', 'api')
|
|
||||||
if config.has_option('logentries', 'port'):
|
|
||||||
self.api_port = config.getint('logentries', 'port')
|
|
||||||
if config.has_option('logentries', 'tls_port'):
|
|
||||||
self.api_tls_port = config.getint('logentries', 'tls_port')
|
|
||||||
if config.has_option('logentries', 'use_tls'):
|
|
||||||
self.use_tls = config.getboolean('logentries', 'use_tls')
|
|
||||||
if config.has_option('logentries', 'token'):
|
|
||||||
self.token = config.get('logentries', 'token')
|
|
||||||
if config.has_option('logentries', 'flatten'):
|
|
||||||
self.flatten = config.getboolean('logentries', 'flatten')
|
|
||||||
|
|
||||||
except:
|
|
||||||
self.api_uri = os.getenv('LOGENTRIES_API')
|
|
||||||
if self.api_uri is None:
|
|
||||||
self.api_uri = 'data.logentries.com'
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.api_port = int(os.getenv('LOGENTRIES_PORT'))
|
|
||||||
if self.api_port is None:
|
|
||||||
self.api_port = 80
|
|
||||||
except TypeError:
|
|
||||||
self.api_port = 80
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.api_tls_port = int(os.getenv('LOGENTRIES_TLS_PORT'))
|
|
||||||
if self.api_tls_port is None:
|
|
||||||
self.api_tls_port = 443
|
|
||||||
except TypeError:
|
|
||||||
self.api_tls_port = 443
|
|
||||||
|
|
||||||
# this just needs to be set to use TLS
|
|
||||||
self.use_tls = os.getenv('LOGENTRIES_USE_TLS')
|
|
||||||
if self.use_tls is None:
|
|
||||||
self.use_tls = False
|
|
||||||
elif self.use_tls.lower() in ['yes', 'true']:
|
|
||||||
self.use_tls = True
|
|
||||||
|
|
||||||
self.token = os.getenv('LOGENTRIES_ANSIBLE_TOKEN')
|
|
||||||
if self.token is None:
|
|
||||||
self.disabled = True
|
|
||||||
self._display.warning('Logentries token could not be loaded. The logentries token can be provided using the `LOGENTRIES_TOKEN` environment '
|
|
||||||
'variable')
|
|
||||||
|
|
||||||
self.flatten = os.getenv('LOGENTRIES_FLATTEN')
|
|
||||||
if self.flatten is None:
|
|
||||||
self.flatten = False
|
|
||||||
elif self.flatten.lower() in ['yes', 'true']:
|
|
||||||
self.flatten = True
|
|
||||||
|
|
||||||
self.verbose = False
|
|
||||||
self.timeout = 10
|
|
||||||
self.le_jobid = str(uuid.uuid4())
|
self.le_jobid = str(uuid.uuid4())
|
||||||
|
|
||||||
if self.use_tls:
|
# FIXME: remove when done testing
|
||||||
self._appender = TLSSocketAppender(verbose=self.verbose,
|
# initialize configurable
|
||||||
LE_API=self.api_uri,
|
self.api_url = 'data.logentries.com'
|
||||||
LE_TLS_PORT=self.api_tls_port)
|
self.api_port = 80
|
||||||
else:
|
self.api_tls_port = 443
|
||||||
self._appender = PlainTextSocketAppender(verbose=self.verbose,
|
self.use_tls = False
|
||||||
LE_API=self.api_uri,
|
self.flatten = False
|
||||||
LE_PORT=self.api_port)
|
self.token = None
|
||||||
self._appender.reopen_connection()
|
|
||||||
|
# FIXME: make configurable, move to options
|
||||||
|
self.timeout = 10
|
||||||
|
|
||||||
|
# FIXME: remove testing
|
||||||
|
# self.set_options({'api': 'data.logentries.com', 'port': 80,
|
||||||
|
# 'tls_port': 10000, 'use_tls': True, 'flatten': False, 'token': 'ae693734-4c5b-4a44-8814-1d2feb5c8241'})
|
||||||
|
|
||||||
|
def set_option(self, name, value):
|
||||||
|
raise AnsibleError("The Logentries callabck plugin does not suport setting individual options.")
|
||||||
|
|
||||||
|
def set_options(self, options):
|
||||||
|
|
||||||
|
super(CallbackModule, self).set_options(options)
|
||||||
|
|
||||||
|
# get options
|
||||||
|
try:
|
||||||
|
self.api_url = self._plugin_options['api']
|
||||||
|
self.api_port = self._plugin_options['port']
|
||||||
|
self.api_tls_port = self._plugin_options['tls_port']
|
||||||
|
self.use_tls = self._plugin_options['use_tls']
|
||||||
|
self.flatten = self._plugin_options['flatten']
|
||||||
|
except KeyError as e:
|
||||||
|
self._display.warning("Missing option for Logentries callback plugin: %s" % to_native(e))
|
||||||
|
self.disabled = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.token = self._plugin_options['token']
|
||||||
|
except KeyError as e:
|
||||||
|
self._display.warning('Logentries token was not provided, this is required for this callback to operate, disabling')
|
||||||
|
self.disabled = True
|
||||||
|
|
||||||
|
if self.flatten and not HAS_FLATDICT:
|
||||||
|
self.disabled = True
|
||||||
|
self._display.warning('You have chosen to flatten and the `flatdict` python module is not installed.\nDisabling the Logentries callback plugin.')
|
||||||
|
|
||||||
|
self._initialize_connections()
|
||||||
|
|
||||||
|
def _initialize_connections(self):
|
||||||
|
|
||||||
|
if not self.disabled:
|
||||||
|
if self.use_tls:
|
||||||
|
self._display.vvvv("Connecting to %s:%s with TLS" % (self.api_url, self.api_tls_port))
|
||||||
|
self._appender = TLSSocketAppender(display=self._display, LE_API=self.api_url, LE_TLS_PORT=self.api_tls_port)
|
||||||
|
else:
|
||||||
|
self._display.vvvv("Connecting to %s:%s" % (self.api_url, self.api_port))
|
||||||
|
self._appender = PlainTextSocketAppender(display=self._display, LE_API=self.api_url, LE_PORT=self.api_port)
|
||||||
|
self._appender.reopen_connection()
|
||||||
|
|
||||||
def emit_formatted(self, record):
|
def emit_formatted(self, record):
|
||||||
if self.flatten:
|
if self.flatten:
|
||||||
|
@ -318,43 +300,34 @@ class CallbackModule(CallbackBase):
|
||||||
msg = record.rstrip('\n')
|
msg = record.rstrip('\n')
|
||||||
msg = "{} {}".format(self.token, msg)
|
msg = "{} {}".format(self.token, msg)
|
||||||
self._appender.put(msg)
|
self._appender.put(msg)
|
||||||
|
self._display.vvvv("Sent event to logentries")
|
||||||
|
|
||||||
|
def _set_info(self, host, res):
|
||||||
|
return {'le_jobid': self.le_jobid, 'hostname': host, 'results': res}
|
||||||
|
|
||||||
def runner_on_ok(self, host, res):
|
def runner_on_ok(self, host, res):
|
||||||
results = {}
|
results = self._set_info(host, res)
|
||||||
results['le_jobid'] = self.le_jobid
|
|
||||||
results['hostname'] = host
|
|
||||||
results['results'] = res
|
|
||||||
results['status'] = 'OK'
|
results['status'] = 'OK'
|
||||||
self.emit_formatted(results)
|
self.emit_formatted(results)
|
||||||
|
|
||||||
def runner_on_failed(self, host, res, ignore_errors=False):
|
def runner_on_failed(self, host, res, ignore_errors=False):
|
||||||
results = {}
|
results = self._set_info(host, res)
|
||||||
results['le_jobid'] = self.le_jobid
|
|
||||||
results['hostname'] = host
|
|
||||||
results['results'] = res
|
|
||||||
results['status'] = 'FAILED'
|
results['status'] = 'FAILED'
|
||||||
self.emit_formatted(results)
|
self.emit_formatted(results)
|
||||||
|
|
||||||
def runner_on_skipped(self, host, item=None):
|
def runner_on_skipped(self, host, item=None):
|
||||||
results = {}
|
results = self._set_info(host, item)
|
||||||
results['le_jobid'] = self.le_jobid
|
del results['results']
|
||||||
results['hostname'] = host
|
|
||||||
results['status'] = 'SKIPPED'
|
results['status'] = 'SKIPPED'
|
||||||
self.emit_formatted(results)
|
self.emit_formatted(results)
|
||||||
|
|
||||||
def runner_on_unreachable(self, host, res):
|
def runner_on_unreachable(self, host, res):
|
||||||
results = {}
|
results = self._set_info(host, res)
|
||||||
results['le_jobid'] = self.le_jobid
|
|
||||||
results['hostname'] = host
|
|
||||||
results['results'] = res
|
|
||||||
results['status'] = 'UNREACHABLE'
|
results['status'] = 'UNREACHABLE'
|
||||||
self.emit_formatted(results)
|
self.emit_formatted(results)
|
||||||
|
|
||||||
def runner_on_async_failed(self, host, res, jid):
|
def runner_on_async_failed(self, host, res, jid):
|
||||||
results = {}
|
results = self._set_info(host, res)
|
||||||
results['le_jobid'] = self.le_jobid
|
|
||||||
results['hostname'] = host
|
|
||||||
results['results'] = res
|
|
||||||
results['jid'] = jid
|
results['jid'] = jid
|
||||||
results['status'] = 'ASYNC_FAILED'
|
results['status'] = 'ASYNC_FAILED'
|
||||||
self.emit_formatted(results)
|
self.emit_formatted(results)
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
# (C) 2017, Tennis Smith, http://github.com/gamename
|
# (c) 2017, Tennis Smith, http://github.com/gamename
|
||||||
#
|
# (c) 2017 Ansible Project
|
||||||
# This file is free software: you can redistribute it and/or modify
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# File is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# See <http://www.gnu.org/licenses/> for a copy of the
|
|
||||||
# GNU General Public License
|
|
||||||
|
|
||||||
#
|
'''
|
||||||
# This will track the use of each role during the life of a playbook's
|
DOCUMENTATION:
|
||||||
# execution. The total time spent in each role will be printed at the
|
callback: profile_roles
|
||||||
# end.
|
type: aggregate
|
||||||
#
|
short_description: adds timing information to roles
|
||||||
|
version_added: "2.4"
|
||||||
|
description:
|
||||||
|
- This callback module provides profiling for ansible roles.
|
||||||
|
requirements:
|
||||||
|
- whitelisting in configuration
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Make coding more python3-ish
|
||||||
# Make coding more python3-ish
|
# Make coding more python3-ish
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|
||||||
|
@ -117,11 +114,9 @@ class CallbackModule(CallbackBase):
|
||||||
|
|
||||||
# Print the timings starting with the largest one
|
# Print the timings starting with the largest one
|
||||||
for result in self.totals.most_common():
|
for result in self.totals.most_common():
|
||||||
msg = u"{0:-<70}{1:->9}".format(result[0] + u' ',
|
msg = u"{0:-<70}{1:->9}".format(result[0] + u' ', u' {0:.02f}s'.format(result[1]))
|
||||||
u' {0:.02f}s'.format(result[1]))
|
|
||||||
self._display.display(msg)
|
self._display.display(msg)
|
||||||
|
|
||||||
msg_total = u"{0:-<70}{1:->9}".format(u'total ',
|
msg_total = u"{0:-<70}{1:->9}".format(u'total ', u' {0:.02f}s'.format(total_time))
|
||||||
u' {0:.02f}s'.format(total_time))
|
|
||||||
self._display.display(filled("", fchar="~"))
|
self._display.display(filled("", fchar="~"))
|
||||||
self._display.display(msg_total)
|
self._display.display(msg_total)
|
||||||
|
|
|
@ -2,29 +2,60 @@
|
||||||
# (C) 2015, Tom Paine, <github@aioue.net>
|
# (C) 2015, Tom Paine, <github@aioue.net>
|
||||||
# (C) 2014, Jharrod LaFon, @JharrodLaFon
|
# (C) 2014, Jharrod LaFon, @JharrodLaFon
|
||||||
# (C) 2012-2013, Michael DeHaan, <michael.dehaan@gmail.com>
|
# (C) 2012-2013, Michael DeHaan, <michael.dehaan@gmail.com>
|
||||||
#
|
# (C) 2017 Ansible Project
|
||||||
# This file is free software: you can redistribute it and/or modify
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# File is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# See <http://www.gnu.org/licenses/> for a copy of the
|
|
||||||
# GNU General Public License
|
|
||||||
|
|
||||||
# Provides per-task timing, ongoing playbook elapsed time and
|
'''
|
||||||
# ordered list of top 20 longest running tasks at end
|
DOCUMENTATION:
|
||||||
|
callback: profile_tasks
|
||||||
|
type: aggregate
|
||||||
|
short_description: adds time information to tasks
|
||||||
|
version_added: "2.0"
|
||||||
|
description:
|
||||||
|
- Ansible callback plugin for timing individual tasks and overall execution time.
|
||||||
|
- "Mashup of 2 excellent original works: https://github.com/jlafon/ansible-profile,
|
||||||
|
https://github.com/junaid18183/ansible_home/blob/master/ansible_plugins/callback_plugins/timestamp.py.old"
|
||||||
|
- "Format: ``<task start timestamp> (<length of previous task>) <current elapsed playbook execution time>``"
|
||||||
|
- It also lists the top/bottom time consuming tasks in the summary (configurable)
|
||||||
|
- Before 2.4 only the environment variables were available for configuration.
|
||||||
|
requirements:
|
||||||
|
- whitelisting in configuration
|
||||||
|
options:
|
||||||
|
output_limit:
|
||||||
|
description: Number of tasks to display in the summary
|
||||||
|
default: 20
|
||||||
|
env:
|
||||||
|
- name: PROFILE_TASKS_TASK_OUTPUT_LIMIT
|
||||||
|
ini:
|
||||||
|
- section: callback_profile_tasks
|
||||||
|
key: task_output_limit
|
||||||
|
sort_order:
|
||||||
|
description: Adjust the sorting output of summary tasks
|
||||||
|
choices: ['descending', 'ascending', 'none']
|
||||||
|
default: 'descending'
|
||||||
|
env:
|
||||||
|
- name: PROFILE_TASKS_SORT_ORDER
|
||||||
|
ini:
|
||||||
|
- section: callback_profile_tasks
|
||||||
|
key: sort_order
|
||||||
|
#EXAMPLES: > '
|
||||||
|
#
|
||||||
|
# TASK: [ensure messaging security group exists] ********************************
|
||||||
|
# Thursday 11 June 2017 22:50:53 +0100 (0:00:00.721) 0:00:05.322 *********
|
||||||
|
# ok: [localhost]
|
||||||
|
#
|
||||||
|
# TASK: [ensure db security group exists] ***************************************
|
||||||
|
# Thursday 11 June 2017 22:50:54 +0100 (0:00:00.558) 0:00:05.880 *********
|
||||||
|
# changed: [localhost]
|
||||||
|
# '
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Make coding more python3-ish
|
||||||
# Make coding more python3-ish
|
# Make coding more python3-ish
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import os
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from ansible.module_utils.six.moves import reduce
|
from ansible.module_utils.six.moves import reduce
|
||||||
|
@ -82,19 +113,32 @@ class CallbackModule(CallbackBase):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.stats = collections.OrderedDict()
|
self.stats = collections.OrderedDict()
|
||||||
self.current = None
|
self.current = None
|
||||||
self.sort_order = os.getenv('PROFILE_TASKS_SORT_ORDER', True)
|
|
||||||
self.task_output_limit = os.getenv('PROFILE_TASKS_TASK_OUTPUT_LIMIT', 20)
|
|
||||||
|
|
||||||
if self.sort_order == 'ascending':
|
self.sort_order = None
|
||||||
self.sort_order = False
|
self.task_output_limit = None
|
||||||
|
|
||||||
if self.task_output_limit == 'all':
|
|
||||||
self.task_output_limit = None
|
|
||||||
else:
|
|
||||||
self.task_output_limit = int(self.task_output_limit)
|
|
||||||
|
|
||||||
super(CallbackModule, self).__init__()
|
super(CallbackModule, self).__init__()
|
||||||
|
|
||||||
|
def set_options(self, options):
|
||||||
|
|
||||||
|
super(CallbackModule, self).set_options(options)
|
||||||
|
|
||||||
|
self.sort_order = self._plugin_options['sort_order']
|
||||||
|
if self.sort_order is not None:
|
||||||
|
if self.sort_order == 'ascending':
|
||||||
|
self.sort_order = False
|
||||||
|
elif self.sort_order == 'descending':
|
||||||
|
self.sort_order = True
|
||||||
|
elif self.sort_order == 'none':
|
||||||
|
self.sort_order = None
|
||||||
|
|
||||||
|
self.task_output_limit = self._plugin_options['output_limit']
|
||||||
|
if self.task_output_limit is not None:
|
||||||
|
if self.task_output_limit == 'all':
|
||||||
|
self.task_output_limit = None
|
||||||
|
else:
|
||||||
|
self.task_output_limit = int(self.task_output_limit)
|
||||||
|
|
||||||
def _record_task(self, task):
|
def _record_task(self, task):
|
||||||
"""
|
"""
|
||||||
Logs the start of each task
|
Logs the start of each task
|
||||||
|
@ -126,7 +170,7 @@ class CallbackModule(CallbackBase):
|
||||||
results = self.stats.items()
|
results = self.stats.items()
|
||||||
|
|
||||||
# Sort the tasks by the specified sort
|
# Sort the tasks by the specified sort
|
||||||
if self.sort_order != 'none':
|
if self.sort_order is not None:
|
||||||
results = sorted(
|
results = sorted(
|
||||||
self.stats.items(),
|
self.stats.items(),
|
||||||
key=lambda x: x[1]['time'],
|
key=lambda x: x[1]['time'],
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
profile\_tasks.py
|
|
||||||
=================
|
|
||||||
|
|
||||||
Ansible plugin for timing individual tasks and overall execution time.
|
|
||||||
|
|
||||||
Mashup of 2 excellent original works:
|
|
||||||
|
|
||||||
- https://github.com/jlafon/ansible-profile
|
|
||||||
- https://github.com/junaid18183/ansible_home/blob/master/ansible_plugins/callback_plugins/timestamp.py.old
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
Add ``profile_tasks`` to the ``callback_whitelist`` in ``ansible.cfg``.
|
|
||||||
|
|
||||||
Run playbooks as normal.
|
|
||||||
|
|
||||||
Certain options are configurable using environment variables. You can specify ``ascending`` or ``none`` for
|
|
||||||
the environment variable ``PROFILE_TASKS_SORT_ORDER`` to adjust sorting output. If you want to see more than
|
|
||||||
20 tasks in the output you can set ``PROFILE_TASKS_TASK_OUTPUT_LIMIT`` to any number, or the special value
|
|
||||||
``all`` to get a list of all tasks.
|
|
||||||
|
|
||||||
Features
|
|
||||||
--------
|
|
||||||
|
|
||||||
Tasks
|
|
||||||
~~~~~
|
|
||||||
|
|
||||||
Ongoing timing of each task as it happens.
|
|
||||||
|
|
||||||
| Format:
|
|
||||||
| ``<task start timestamp> (<length of previous task>) <current elapsed playbook execution time>``
|
|
||||||
|
|
||||||
Task output example:
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
TASK: [ensure messaging security group exists] ********************************
|
|
||||||
Thursday 11 June 2017 22:50:53 +0100 (0:00:00.721) 0:00:05.322 *********
|
|
||||||
ok: [localhost]
|
|
||||||
|
|
||||||
TASK: [ensure db security group exists] ***************************************
|
|
||||||
Thursday 11 June 2017 22:50:54 +0100 (0:00:00.558) 0:00:05.880 *********
|
|
||||||
changed: [localhost]
|
|
||||||
|
|
||||||
Play Recap
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
Recap includes ending timestamp, total playbook execution time and a
|
|
||||||
sorted list of the top longest running tasks.
|
|
||||||
|
|
||||||
No more wondering how old the results in a terminal window are.
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
ansible <args here>
|
|
||||||
<normal output here>
|
|
||||||
PLAY RECAP ********************************************************************
|
|
||||||
Thursday 11 June 2016 22:51:00 +0100 (0:00:01.011) 0:00:43.247 *********
|
|
||||||
===============================================================================
|
|
||||||
old_and_slow : install tons of packages -------------------------------- 20.03s
|
|
||||||
/home/bob/ansible/roles/old_and_slow/tasks/main.yml:4 -------------------------
|
|
||||||
db : second task to run ------------------------------------------------- 2.03s
|
|
||||||
/home/bob/ansible/roles/db/tasks/main.yml:4 -----------------------------------
|
|
||||||
setup ------------------------------------------------------------------- 0.42s
|
|
||||||
None --------------------------------------------------------------------------
|
|
||||||
www : first task to run ------------------------------------------------- 0.03s
|
|
||||||
/home/bob/ansible/roles/www/tasks/main.yml:1 ----------------------------------
|
|
||||||
fast_task : first task to run ------------------------------------------- 0.01s
|
|
||||||
/home/bob/ansible/roles/fast_task.yml:1 ---------------------------------------
|
|
||||||
|
|
||||||
Compatibility
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Ansible 2.0+
|
|
|
@ -1,61 +1,59 @@
|
||||||
# (c) Fastly, inc 2016
|
# (c) Fastly, inc 2016
|
||||||
#
|
# (c) 2017 Ansible Project
|
||||||
# This file is part of Ansible
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
selective.py callback plugin.
|
DOCUMENTATION:
|
||||||
|
callback: selective
|
||||||
This callback only prints tasks that have been tagged with `print_action` or that have failed.
|
callback_type: stdout
|
||||||
Tasks that are not printed are placed with a '.'.
|
requirements:
|
||||||
|
- set as main display callback
|
||||||
For example:
|
short_description: only print certain tasks
|
||||||
|
version_added: "2.4"
|
||||||
- debug: msg="This will not be printed"
|
description:
|
||||||
- debug: msg="But this will"
|
- This callback only prints tasks that have been tagged with `print_action` or that have failed.
|
||||||
tags: [print_action]"
|
This allows operators to focus on the tasks that provide value only.
|
||||||
|
- Tasks that are not printed are placed with a '.'.
|
||||||
This allows operators to focus on the tasks that provide value only.
|
- If you increase verbosity all tasks are printed.
|
||||||
|
options:
|
||||||
If you increase verbosity all tasks are printed.
|
nocolor:
|
||||||
|
default: False
|
||||||
|
description: This setting allows suppressing colorizing output
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_NOCOLOR
|
||||||
|
- name: ANSIBLE_SELECTIVE_DONT_COLORIZE
|
||||||
|
ini:
|
||||||
|
- section: defaults
|
||||||
|
- key: nocolor
|
||||||
|
type: boolean
|
||||||
|
EXAMPLES:
|
||||||
|
- debug: msg="This will not be printed"
|
||||||
|
- debug: msg="But this will"
|
||||||
|
tags: [print_action]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|
||||||
import difflib
|
import difflib
|
||||||
import os
|
|
||||||
|
|
||||||
|
from ansible import constants as C
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DONT_COLORIZE = False
|
||||||
COLORS = {
|
COLORS = {
|
||||||
'normal': '\033[0m',
|
'normal': '\033[0m',
|
||||||
'ok': '\033[92m',
|
'ok': C.COLOR_OK,
|
||||||
'bold': '\033[1m',
|
'bold': '\033[1m',
|
||||||
'not_so_bold': '\033[1m\033[34m',
|
'not_so_bold': '\033[1m\033[34m',
|
||||||
'changed': '\033[93m',
|
'changed': C.COLOR_CHANGED,
|
||||||
'failed': '\033[91m',
|
'failed': C.COLOR_ERROR,
|
||||||
'endc': '\033[0m',
|
'endc': '\033[0m',
|
||||||
'skipped': '\033[96m',
|
'skipped': C.COLOR_SKIP,
|
||||||
}
|
}
|
||||||
|
|
||||||
DONT_COLORIZE = os.getenv('ANSIBLE_SELECTIVE_DONT_COLORIZE', default=False)
|
|
||||||
|
|
||||||
|
|
||||||
def dict_diff(prv, nxt):
|
def dict_diff(prv, nxt):
|
||||||
"""Return a dict of keys that differ with another config object."""
|
"""Return a dict of keys that differ with another config object."""
|
||||||
|
@ -89,6 +87,13 @@ class CallbackModule(CallbackBase):
|
||||||
self.last_task_name = None
|
self.last_task_name = None
|
||||||
self.printed_last_task = False
|
self.printed_last_task = False
|
||||||
|
|
||||||
|
def set_options(self, options):
|
||||||
|
|
||||||
|
super(CallbackModule, self).set_options(options)
|
||||||
|
|
||||||
|
global DONT_COLORIZE
|
||||||
|
DONT_COLORIZE = self._plugin_options['nocolor']
|
||||||
|
|
||||||
def _print_task(self, task_name=None):
|
def _print_task(self, task_name=None):
|
||||||
if task_name is None:
|
if task_name is None:
|
||||||
task_name = self.last_task_name
|
task_name = self.last_task_name
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
DOCUMENTATION:
|
DOCUMENTATION:
|
||||||
callback: skippy
|
callback: skippy
|
||||||
callback_type: stdout
|
callback_type: stdout
|
||||||
requires: set as display
|
requirements:
|
||||||
|
- set as main display callback
|
||||||
short_description: Ansible screen output that ignores skipped status
|
short_description: Ansible screen output that ignores skipped status
|
||||||
version_added: "2.0"
|
version_added: "2.0"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -1,20 +1,45 @@
|
||||||
# (C) 2014-2015, Matt Martz <matt@sivel.net>
|
# (C) 2014-2015, Matt Martz <matt@sivel.net>
|
||||||
|
# (C) 2017 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
# This file is part of Ansible
|
'''
|
||||||
#
|
DOCUMENTATION:
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
callback: slack
|
||||||
# it under the terms of the GNU General Public License as published by
|
callback_type: notification
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
requirements:
|
||||||
# (at your option) any later version.
|
- whitelist in configuration
|
||||||
#
|
- prettytable (python library)
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
short_description: Sends play events to a Slack channel
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
version_added: "2.1"
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
description:
|
||||||
# GNU General Public License for more details.
|
- This is an ansible callback plugin that sends status updates to a Slack channel during playbook execution.
|
||||||
#
|
- Before 2.4 only environment variables were available for configuring this plugin
|
||||||
# You should have received a copy of the GNU General Public License
|
options:
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
webhook_url:
|
||||||
|
required: True
|
||||||
|
description: Slack Webhook URL
|
||||||
|
env:
|
||||||
|
- name: SLACK_WEBHOOK_URL
|
||||||
|
ini:
|
||||||
|
- section: callback_slack
|
||||||
|
key: webhook_url
|
||||||
|
channel:
|
||||||
|
default: "#ansible"
|
||||||
|
description: Slack room to post in.
|
||||||
|
env:
|
||||||
|
- name: SLACK_CHANNEL
|
||||||
|
ini:
|
||||||
|
- section: callback_slack
|
||||||
|
key: channel
|
||||||
|
username:
|
||||||
|
description: Username to post as.
|
||||||
|
env:
|
||||||
|
- name: SLACK_USERNAME
|
||||||
|
default: ansible
|
||||||
|
ini:
|
||||||
|
- section: callback_slack
|
||||||
|
key: username
|
||||||
|
'''
|
||||||
# Make coding more python3-ish
|
# Make coding more python3-ish
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
@ -42,17 +67,6 @@ except ImportError:
|
||||||
class CallbackModule(CallbackBase):
|
class CallbackModule(CallbackBase):
|
||||||
"""This is an ansible callback plugin that sends status
|
"""This is an ansible callback plugin that sends status
|
||||||
updates to a Slack channel during playbook execution.
|
updates to a Slack channel during playbook execution.
|
||||||
|
|
||||||
This plugin makes use of the following environment variables:
|
|
||||||
SLACK_WEBHOOK_URL (required): Slack Webhook URL
|
|
||||||
SLACK_CHANNEL (optional): Slack room to post in. Default: #ansible
|
|
||||||
SLACK_USERNAME (optional): Username to post as. Default: ansible
|
|
||||||
SLACK_INVOCATION (optional): Show command line invocation
|
|
||||||
details. Default: False
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
prettytable
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
CALLBACK_VERSION = 2.0
|
CALLBACK_VERSION = 2.0
|
||||||
CALLBACK_TYPE = 'notification'
|
CALLBACK_TYPE = 'notification'
|
||||||
|
@ -64,9 +78,9 @@ class CallbackModule(CallbackBase):
|
||||||
self.disabled = False
|
self.disabled = False
|
||||||
|
|
||||||
if cli:
|
if cli:
|
||||||
self._options = cli.options
|
self._plugin_options = cli.options
|
||||||
else:
|
else:
|
||||||
self._options = None
|
self._plugin_options = None
|
||||||
|
|
||||||
super(CallbackModule, self).__init__(display=display)
|
super(CallbackModule, self).__init__(display=display)
|
||||||
|
|
||||||
|
@ -76,13 +90,10 @@ class CallbackModule(CallbackBase):
|
||||||
'installed. Disabling the Slack callback '
|
'installed. Disabling the Slack callback '
|
||||||
'plugin.')
|
'plugin.')
|
||||||
|
|
||||||
self.webhook_url = os.getenv('SLACK_WEBHOOK_URL')
|
self.webhook_url = self._plugin_options['webook_url']
|
||||||
self.channel = os.getenv('SLACK_CHANNEL', '#ansible')
|
self.channel = self._plugin_options['channel']
|
||||||
self.username = os.getenv('SLACK_USERNAME', 'ansible')
|
self.username = self._plugin_options['username']
|
||||||
self.show_invocation = boolean(
|
self.show_invocation = (self._display.verbosity > 1)
|
||||||
os.getenv('SLACK_INVOCATION', self._display.verbosity > 1),
|
|
||||||
strict=False
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.webhook_url is None:
|
if self.webhook_url is None:
|
||||||
self.disabled = True
|
self.disabled = True
|
||||||
|
@ -91,12 +102,13 @@ class CallbackModule(CallbackBase):
|
||||||
'the `SLACK_WEBHOOK_URL` environment '
|
'the `SLACK_WEBHOOK_URL` environment '
|
||||||
'variable.')
|
'variable.')
|
||||||
|
|
||||||
self.playbook_name = None
|
else:
|
||||||
|
self.playbook_name = None
|
||||||
|
|
||||||
# This is a 6 character identifier provided with each message
|
# This is a 6 character identifier provided with each message
|
||||||
# This makes it easier to correlate messages when there are more
|
# This makes it easier to correlate messages when there are more
|
||||||
# than 1 simultaneous playbooks running
|
# than 1 simultaneous playbooks running
|
||||||
self.guid = uuid.uuid4().hex[:6]
|
self.guid = uuid.uuid4().hex[:6]
|
||||||
|
|
||||||
def send_msg(self, attachments):
|
def send_msg(self, attachments):
|
||||||
payload = {
|
payload = {
|
||||||
|
@ -125,13 +137,13 @@ class CallbackModule(CallbackBase):
|
||||||
'*Playbook initiated* (_%s_)' % self.guid
|
'*Playbook initiated* (_%s_)' % self.guid
|
||||||
]
|
]
|
||||||
invocation_items = []
|
invocation_items = []
|
||||||
if self._options and self.show_invocation:
|
if self._plugin_options and self.show_invocation:
|
||||||
tags = self._options.tags
|
tags = self._plugin_options.tags
|
||||||
skip_tags = self._options.skip_tags
|
skip_tags = self._plugin_options.skip_tags
|
||||||
extra_vars = self._options.extra_vars
|
extra_vars = self._plugin_options.extra_vars
|
||||||
subset = self._options.subset
|
subset = self._plugin_options.subset
|
||||||
inventory = os.path.basename(
|
inventory = os.path.basename(
|
||||||
os.path.realpath(self._options.inventory)
|
os.path.realpath(self._plugin_options.inventory)
|
||||||
)
|
)
|
||||||
|
|
||||||
invocation_items.append('Inventory: %s' % inventory)
|
invocation_items.append('Inventory: %s' % inventory)
|
||||||
|
@ -145,7 +157,7 @@ class CallbackModule(CallbackBase):
|
||||||
invocation_items.append('Extra Vars: %s' %
|
invocation_items.append('Extra Vars: %s' %
|
||||||
' '.join(extra_vars))
|
' '.join(extra_vars))
|
||||||
|
|
||||||
title.append('by *%s*' % self._options.remote_user)
|
title.append('by *%s*' % self._plugin_options.remote_user)
|
||||||
|
|
||||||
title.append('\n\n*%s*' % self.playbook_name)
|
title.append('\n\n*%s*' % self.playbook_name)
|
||||||
msg_items = [' '.join(title)]
|
msg_items = [' '.join(title)]
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
# (c) 2017, Frederic Van Espen <github@freh.be>
|
# (c) 2017, Frederic Van Espen <github@freh.be>
|
||||||
#
|
# (c) 2017 Ansible Project
|
||||||
# This file is part of Ansible
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
DOCUMENTATION:
|
||||||
|
callback: stderr
|
||||||
|
callback_type: stdout
|
||||||
|
requirements:
|
||||||
|
- set as main display callback
|
||||||
|
short_description: Splits output, sending failed tasks to stderr
|
||||||
|
version_added: "2.4"
|
||||||
|
description:
|
||||||
|
- This is the stderr callback plugin, it behaves like the default callback plugin but sends error output to stderr.
|
||||||
|
- Also it does not output skipped host/task/item status
|
||||||
|
'''
|
||||||
# Make coding more python3-ish
|
# Make coding more python3-ish
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
|
@ -1,3 +1,44 @@
|
||||||
|
# (c) 2017 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
'''
|
||||||
|
DOCUMENTATION:
|
||||||
|
callback: syslog_json
|
||||||
|
callback_type: notification
|
||||||
|
requirements:
|
||||||
|
- whietlist in configuration
|
||||||
|
short_description: sends JSON events to syslog
|
||||||
|
version_added: "1.9"
|
||||||
|
description:
|
||||||
|
- This plugin logs ansible-playbook and ansible runs to a syslog server in JSON format
|
||||||
|
- Before 2.4 only environment variables were available for configuration
|
||||||
|
options:
|
||||||
|
server:
|
||||||
|
description: syslog server that will recieve the event
|
||||||
|
env:
|
||||||
|
- name: SYSLOG_SERVER
|
||||||
|
default: localhost
|
||||||
|
ini:
|
||||||
|
- section: callback_syslog_json
|
||||||
|
key: syslog_server
|
||||||
|
port:
|
||||||
|
description: prot on which the syslog server is listening
|
||||||
|
env:
|
||||||
|
- name: SYSLOG_PORT
|
||||||
|
default: 514
|
||||||
|
ini:
|
||||||
|
- section: callback_syslog_json
|
||||||
|
key: syslog_port
|
||||||
|
facility:
|
||||||
|
description: syslog facitliy to log as
|
||||||
|
env:
|
||||||
|
- name: SYSLOG_FACILITY
|
||||||
|
default: user
|
||||||
|
ini:
|
||||||
|
- section: callback_syslog_json
|
||||||
|
key: syslog_facility
|
||||||
|
'''
|
||||||
|
|
||||||
# Make coding more python3-ish
|
# Make coding more python3-ish
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
@ -16,15 +57,8 @@ from ansible.plugins.callback import CallbackBase
|
||||||
class CallbackModule(CallbackBase):
|
class CallbackModule(CallbackBase):
|
||||||
"""
|
"""
|
||||||
logs ansible-playbook and ansible runs to a syslog server in json format
|
logs ansible-playbook and ansible runs to a syslog server in json format
|
||||||
make sure you have in ansible.cfg:
|
|
||||||
callback_plugins = <path_to_callback_plugins_folder>
|
|
||||||
and put the plugin in <path_to_callback_plugins_folder>
|
|
||||||
|
|
||||||
This plugin makes use of the following environment variables:
|
|
||||||
SYSLOG_SERVER (optional): defaults to localhost
|
|
||||||
SYSLOG_PORT (optional): defaults to 514
|
|
||||||
SYSLOG_FACILITY (optional): defaults to user
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CALLBACK_VERSION = 2.0
|
CALLBACK_VERSION = 2.0
|
||||||
CALLBACK_TYPE = 'aggregate'
|
CALLBACK_TYPE = 'aggregate'
|
||||||
CALLBACK_NAME = 'syslog_json'
|
CALLBACK_NAME = 'syslog_json'
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
# (c) 2017 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
'''
|
||||||
|
DOCUMENTATION:
|
||||||
|
callback: timer
|
||||||
|
callback_type: aggregate
|
||||||
|
requirements:
|
||||||
|
- whitelist in configuration
|
||||||
|
short_description: Adds time to play stats
|
||||||
|
version_added: "2.0"
|
||||||
|
description:
|
||||||
|
- This callback just adds total play duration to the play stats.
|
||||||
|
'''
|
||||||
# Make coding more python3-ish
|
# Make coding more python3-ish
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
# (c) 2012-2014, Ansible, Inc
|
# (c) 2012-2014, Ansible, Inc
|
||||||
#
|
# (c) 2017 Ansible Project
|
||||||
# This file is part of Ansible
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
#
|
'''
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
DOCUMENTATION:
|
||||||
# it under the terms of the GNU General Public License as published by
|
callback: tree
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
callback_type: notification
|
||||||
# (at your option) any later version.
|
requirements:
|
||||||
#
|
- invoked in the command line
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
short_description: Save host events to files
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
version_added: "2.0"
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
description:
|
||||||
# GNU General Public License for more details.
|
- "This callback is used by the Ansible (adhoc) command line option `-t|--tree`"
|
||||||
#
|
- This produces a JSON dump of events in a directory, a file for each host, the directory used MUST be passed as a commadn line option.
|
||||||
# You should have received a copy of the GNU General Public License
|
'''
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,11 @@ DOCUMENTATION:
|
||||||
private_key_file:
|
private_key_file:
|
||||||
description:
|
description:
|
||||||
- Key or certificate file used for authentication
|
- Key or certificate file used for authentication
|
||||||
|
ini:
|
||||||
|
- section: defaults
|
||||||
|
key: private_key_file
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_PRIVATE_KEY_FILE
|
||||||
vars:
|
vars:
|
||||||
- name: ansible_private_key_file
|
- name: ansible_private_key_file
|
||||||
timeout:
|
timeout:
|
||||||
|
|
|
@ -69,10 +69,11 @@ DOCUMENTATION:
|
||||||
description: Extra exclusive to the 'ssh' CLI
|
description: Extra exclusive to the 'ssh' CLI
|
||||||
vars:
|
vars:
|
||||||
- name: ansible_ssh_extra_args
|
- name: ansible_ssh_extra_args
|
||||||
ssh_retries:
|
retries:
|
||||||
# constant: ANSIBLE_SSH_RETRIES
|
# constant: ANSIBLE_SSH_RETRIES
|
||||||
description: Number of attempts to connect.
|
description: Number of attempts to connect.
|
||||||
default: 3
|
default: 3
|
||||||
|
type: integer
|
||||||
env:
|
env:
|
||||||
- name: ANSIBLE_SSH_RETRIES
|
- name: ANSIBLE_SSH_RETRIES
|
||||||
ini:
|
ini:
|
||||||
|
@ -118,14 +119,54 @@ DOCUMENTATION:
|
||||||
- {key: pipelining, section: ssh_connection}
|
- {key: pipelining, section: ssh_connection}
|
||||||
type: boolean
|
type: boolean
|
||||||
vars: [{name: ansible_ssh_pipelining}]
|
vars: [{name: ansible_ssh_pipelining}]
|
||||||
# TODO:
|
private_key_file:
|
||||||
# ANSIBLE_SSH_RETRIES
|
description:
|
||||||
|
- Path to private key file to use for authentication
|
||||||
|
ini:
|
||||||
|
- section: defaults
|
||||||
|
key: private_key_file
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_PRIVATE_KEY_FILE
|
||||||
|
vars:
|
||||||
|
- name: ansible_private_key_file
|
||||||
|
- name: ansible_ssh_private_key_file
|
||||||
|
|
||||||
# self._play_context.private_key_file
|
control_path:
|
||||||
# ANSIBLE_SSH_CONTROL_PATH
|
default: null
|
||||||
# ANSIBLE_SSH_CONTROL_PATH_DIR
|
description:
|
||||||
# DEFAULT_SFTP_BATCH_MODE
|
- This is the location to save ssh's ControlPath sockets, it uses ssh's variable substitution.
|
||||||
# DEFAULT_SCP_IF_SSH
|
- Since 2.3, if null, ansible will generate a unique hash. Use `%(directory)s` to indicate where to use the control dir path setting.
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_SSH_CONTROL_PATH
|
||||||
|
ini:
|
||||||
|
- key: control_path
|
||||||
|
section: ssh_connection
|
||||||
|
control_path_dir:
|
||||||
|
default: ~/.ansible/cp
|
||||||
|
description:
|
||||||
|
- This sets the directory to use for ssh control path if the control path setting is null.
|
||||||
|
- Also, provides the `%(directory)s` variable for the control path setting.
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_SSH_CONTROL_PATH_DIR
|
||||||
|
ini:
|
||||||
|
- section: ssh_connection
|
||||||
|
key: control_path_dir
|
||||||
|
sftp_batch_mode:
|
||||||
|
default: True
|
||||||
|
description: 'TODO: write it'
|
||||||
|
env: [{name: ANSIBLE_SFTP_BATCH_MODE}]
|
||||||
|
ini:
|
||||||
|
- {key: sftp_batch_mode, section: ssh_connection}
|
||||||
|
type: boolean
|
||||||
|
scp_if_ssh:
|
||||||
|
default: smart
|
||||||
|
description:
|
||||||
|
- "Prefered method to use when transfering files over ssh"
|
||||||
|
- When set to smart, Ansible will try them until one succeeds or they all fail
|
||||||
|
- If set to True, it will force 'scp', if False it will use 'sftp'
|
||||||
|
env: [{name: ANSIBLE_SCP_IF_SSH}]
|
||||||
|
ini:
|
||||||
|
- {key: scp_if_ssh, section: ssh_connection}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|
|
@ -205,14 +205,17 @@ class PluginLoader:
|
||||||
''' Reads plugin docs to find configuration setting definitions, to push to config manager for later use '''
|
''' Reads plugin docs to find configuration setting definitions, to push to config manager for later use '''
|
||||||
|
|
||||||
# plugins w/o class name don't support config
|
# plugins w/o class name don't support config
|
||||||
if self.class_name and self.class_name in ('Connection'):
|
if self.class_name:
|
||||||
# FIXME: expand from just connection
|
type_name = get_plugin_class(self.class_name)
|
||||||
type_name = get_plugin_class(self)
|
|
||||||
dstring = read_docstring(path, verbose=False, ignore_errors=False)
|
# FIXME: expand from just connection and callback
|
||||||
if dstring.get('doc', False):
|
if type_name in ('connection', 'callback'):
|
||||||
if 'options' in dstring['doc'] and isinstance(dstring['doc']['options'], dict):
|
dstring = read_docstring(path, verbose=False, ignore_errors=False)
|
||||||
C.config.initialize_plugin_configuration_definitions(type_name, name, dstring['doc']['options'])
|
|
||||||
display.debug('Loaded config def from plugin (%s/%s)' % (type_name, name))
|
if dstring.get('doc', False):
|
||||||
|
if 'options' in dstring['doc'] and isinstance(dstring['doc']['options'], dict):
|
||||||
|
C.config.initialize_plugin_configuration_definitions(type_name, name, dstring['doc']['options'])
|
||||||
|
display.debug('Loaded config def from plugin (%s/%s)' % (type_name, name))
|
||||||
|
|
||||||
def add_directory(self, directory, with_subdir=False):
|
def add_directory(self, directory, with_subdir=False):
|
||||||
''' Adds an additional directory to the search path '''
|
''' Adds an additional directory to the search path '''
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue