mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
task logging revamp
* allow global no_log setting, no need to set at play or task level, but can be overriden by them * allow turning off syslog only on task execution from target host (manage_syslog), overlaps with no_log functionality * created log function for task modules to use, now we can remove all syslog references, will use systemd journal if present * added debug flag to modules, so they can make it call new log function conditionally * added debug logging in module's run_command
This commit is contained in:
parent
b757798f3e
commit
37a918438b
6 changed files with 79 additions and 45 deletions
|
@ -177,6 +177,13 @@ fact_caching = memory
|
||||||
#retry_files_enabled = False
|
#retry_files_enabled = False
|
||||||
#retry_files_save_path = ~/.ansible-retry
|
#retry_files_save_path = ~/.ansible-retry
|
||||||
|
|
||||||
|
|
||||||
|
# prevents logging of task data, off by default
|
||||||
|
#no_log = False
|
||||||
|
|
||||||
|
# prevents logging of tasks, but only on the targets, data is still logged on the master/controller
|
||||||
|
#managed_syslog = True
|
||||||
|
|
||||||
[privilege_escalation]
|
[privilege_escalation]
|
||||||
#become=True
|
#become=True
|
||||||
#become_method=sudo
|
#become_method=sudo
|
||||||
|
|
|
@ -154,6 +154,10 @@ DEFAULT_LOG_PATH = get_config(p, DEFAULTS, 'log_path', 'ANSIB
|
||||||
DEFAULT_FORCE_HANDLERS = get_config(p, DEFAULTS, 'force_handlers', 'ANSIBLE_FORCE_HANDLERS', False, boolean=True)
|
DEFAULT_FORCE_HANDLERS = get_config(p, DEFAULTS, 'force_handlers', 'ANSIBLE_FORCE_HANDLERS', False, boolean=True)
|
||||||
DEFAULT_INVENTORY_IGNORE = get_config(p, DEFAULTS, 'inventory_ignore_extensions', 'ANSIBLE_INVENTORY_IGNORE', ["~", ".orig", ".bak", ".ini", ".cfg", ".retry", ".pyc", ".pyo"], islist=True)
|
DEFAULT_INVENTORY_IGNORE = get_config(p, DEFAULTS, 'inventory_ignore_extensions', 'ANSIBLE_INVENTORY_IGNORE', ["~", ".orig", ".bak", ".ini", ".cfg", ".retry", ".pyc", ".pyo"], islist=True)
|
||||||
|
|
||||||
|
# disclosure
|
||||||
|
DEFAULT_NO_LOG = get_config(p, DEFAULTS, 'no_log', 'ANSIBLE_NO_LOG', False, boolean=True)
|
||||||
|
DEFAULT_MANAGED_SYSLOG = get_config(p, DEFAULTS, 'managed_syslog', 'ANSIBLE_MANAGED_SYSLOG', True, boolean=True)
|
||||||
|
|
||||||
# selinux
|
# selinux
|
||||||
DEFAULT_SELINUX_SPECIAL_FS = get_config(p, 'selinux', 'special_context_filesystems', None, 'fuse, nfs, vboxsf, ramfs', islist=True)
|
DEFAULT_SELINUX_SPECIAL_FS = get_config(p, 'selinux', 'special_context_filesystems', None, 'fuse, nfs, vboxsf, ramfs', islist=True)
|
||||||
|
|
||||||
|
|
|
@ -393,6 +393,7 @@ class AnsibleModule(object):
|
||||||
self.check_mode = False
|
self.check_mode = False
|
||||||
self.no_log = no_log
|
self.no_log = no_log
|
||||||
self.cleanup_files = []
|
self.cleanup_files = []
|
||||||
|
self.debug = False
|
||||||
|
|
||||||
self.aliases = {}
|
self.aliases = {}
|
||||||
|
|
||||||
|
@ -407,14 +408,12 @@ class AnsibleModule(object):
|
||||||
|
|
||||||
self.params = self._load_params()
|
self.params = self._load_params()
|
||||||
|
|
||||||
self._legal_inputs = ['_ansible_check_mode', '_ansible_no_log']
|
self._legal_inputs = ['_ansible_check_mode', '_ansible_no_log', '_ansible_debug']
|
||||||
|
|
||||||
|
# append to legal_inputs and then possibly check against them
|
||||||
self.aliases = self._handle_aliases()
|
self.aliases = self._handle_aliases()
|
||||||
|
|
||||||
if check_invalid_arguments:
|
self._check_arguments(check_invalid_arguments)
|
||||||
self._check_invalid_arguments()
|
|
||||||
self._check_for_check_mode()
|
|
||||||
self._check_for_no_log()
|
|
||||||
|
|
||||||
# check exclusive early
|
# check exclusive early
|
||||||
if not bypass_checks:
|
if not bypass_checks:
|
||||||
|
@ -955,25 +954,21 @@ class AnsibleModule(object):
|
||||||
|
|
||||||
return aliases_results
|
return aliases_results
|
||||||
|
|
||||||
def _check_for_check_mode(self):
|
def _check_arguments(self, check_invalid_arguments):
|
||||||
for (k,v) in self.params.iteritems():
|
for (k,v) in self.params.iteritems():
|
||||||
|
|
||||||
if k == '_ansible_check_mode' and v:
|
if k == '_ansible_check_mode' and v:
|
||||||
if not self.supports_check_mode:
|
if not self.supports_check_mode:
|
||||||
self.exit_json(skipped=True, msg="remote module does not support check mode")
|
self.exit_json(skipped=True, msg="remote module does not support check mode")
|
||||||
self.check_mode = True
|
self.check_mode = True
|
||||||
break
|
|
||||||
|
|
||||||
def _check_for_no_log(self):
|
elif k == '_ansible_no_log':
|
||||||
for (k,v) in self.params.iteritems():
|
|
||||||
if k == '_ansible_no_log':
|
|
||||||
self.no_log = self.boolean(v)
|
self.no_log = self.boolean(v)
|
||||||
|
|
||||||
def _check_invalid_arguments(self):
|
elif k == '_ansible_debug':
|
||||||
for (k,v) in self.params.iteritems():
|
self.debug = self.boolean(v)
|
||||||
# these should be in legal inputs already
|
|
||||||
#if k in ('_ansible_check_mode', '_ansible_no_log'):
|
elif check_invalid_arguments and k not in self._legal_inputs:
|
||||||
# continue
|
|
||||||
if k not in self._legal_inputs:
|
|
||||||
self.fail_json(msg="unsupported parameter for module: %s" % k)
|
self.fail_json(msg="unsupported parameter for module: %s" % k)
|
||||||
|
|
||||||
def _count_terms(self, check):
|
def _count_terms(self, check):
|
||||||
|
@ -1215,6 +1210,36 @@ class AnsibleModule(object):
|
||||||
params = dict()
|
params = dict()
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
def _log_to_syslog(self, msg):
|
||||||
|
module = 'ansible-%s' % os.path.basename(__file__)
|
||||||
|
syslog.openlog(str(module), 0, syslog.LOG_USER)
|
||||||
|
syslog.syslog(syslog.LOG_INFO, msg)
|
||||||
|
|
||||||
|
def log(self, msg, log_args=None):
|
||||||
|
|
||||||
|
if not self.no_log:
|
||||||
|
|
||||||
|
if log_args is None:
|
||||||
|
log_args = dict()
|
||||||
|
|
||||||
|
module = 'ansible-%s' % os.path.basename(__file__)
|
||||||
|
|
||||||
|
# 6655 - allow for accented characters
|
||||||
|
if isinstance(msg, unicode):
|
||||||
|
# We should never get here as msg should be type str, not unicode
|
||||||
|
msg = msg.encode('utf-8')
|
||||||
|
|
||||||
|
if (has_journal):
|
||||||
|
journal_args = [("MODULE", os.path.basename(__file__))]
|
||||||
|
for arg in log_args:
|
||||||
|
journal_args.append((arg.upper(), str(log_args[arg])))
|
||||||
|
try:
|
||||||
|
journal.send("%s %s" % (module, msg), **dict(journal_args))
|
||||||
|
except IOError:
|
||||||
|
# fall back to syslog since logging to journal failed
|
||||||
|
self._log_to_syslog(msg)
|
||||||
|
else:
|
||||||
|
self._log_to_syslog(msg)
|
||||||
|
|
||||||
def _log_invocation(self):
|
def _log_invocation(self):
|
||||||
''' log that ansible ran the module '''
|
''' log that ansible ran the module '''
|
||||||
|
@ -1240,7 +1265,6 @@ class AnsibleModule(object):
|
||||||
param_val = param_val.encode('utf-8')
|
param_val = param_val.encode('utf-8')
|
||||||
log_args[param] = heuristic_log_sanitize(param_val)
|
log_args[param] = heuristic_log_sanitize(param_val)
|
||||||
|
|
||||||
module = 'ansible-%s' % os.path.basename(__file__)
|
|
||||||
msg = []
|
msg = []
|
||||||
for arg in log_args:
|
for arg in log_args:
|
||||||
arg_val = log_args[arg]
|
arg_val = log_args[arg]
|
||||||
|
@ -1254,24 +1278,9 @@ class AnsibleModule(object):
|
||||||
else:
|
else:
|
||||||
msg = 'Invoked'
|
msg = 'Invoked'
|
||||||
|
|
||||||
# 6655 - allow for accented characters
|
self.log(msg, log_args=log_args)
|
||||||
if isinstance(msg, unicode):
|
|
||||||
# We should never get here as msg should be type str, not unicode
|
|
||||||
msg = msg.encode('utf-8')
|
|
||||||
|
|
||||||
if (has_journal):
|
|
||||||
journal_args = [("MODULE", os.path.basename(__file__))]
|
|
||||||
for arg in log_args:
|
|
||||||
journal_args.append((arg.upper(), str(log_args[arg])))
|
|
||||||
try:
|
|
||||||
journal.send("%s %s" % (module, msg), **dict(journal_args))
|
|
||||||
except IOError:
|
|
||||||
# fall back to syslog since logging to journal failed
|
|
||||||
syslog.openlog(str(module), 0, syslog.LOG_USER)
|
|
||||||
syslog.syslog(syslog.LOG_INFO, msg) #1
|
|
||||||
else:
|
|
||||||
syslog.openlog(str(module), 0, syslog.LOG_USER)
|
|
||||||
syslog.syslog(syslog.LOG_INFO, msg) #2
|
|
||||||
|
|
||||||
def _set_cwd(self):
|
def _set_cwd(self):
|
||||||
try:
|
try:
|
||||||
|
@ -1656,6 +1665,14 @@ class AnsibleModule(object):
|
||||||
self.fail_json(rc=e.errno, msg="Could not open %s, %s" % (cwd, str(e)))
|
self.fail_json(rc=e.errno, msg="Could not open %s, %s" % (cwd, str(e)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
if self.debug:
|
||||||
|
if isinstance(args, list):
|
||||||
|
running = ' '.join(args)
|
||||||
|
else:
|
||||||
|
running = args
|
||||||
|
self.log('Executing: ' + running)
|
||||||
|
|
||||||
cmd = subprocess.Popen(args, **kwargs)
|
cmd = subprocess.Popen(args, **kwargs)
|
||||||
|
|
||||||
# the communication logic here is essentially taken from that
|
# the communication logic here is essentially taken from that
|
||||||
|
|
|
@ -206,9 +206,6 @@ class PlayContext(Base):
|
||||||
if play.become_user:
|
if play.become_user:
|
||||||
self.become_user = play.become_user
|
self.become_user = play.become_user
|
||||||
|
|
||||||
# non connection related
|
|
||||||
self.no_log = play.no_log
|
|
||||||
|
|
||||||
if play.force_handlers is not None:
|
if play.force_handlers is not None:
|
||||||
self.force_handlers = play.force_handlers
|
self.force_handlers = play.force_handlers
|
||||||
|
|
||||||
|
@ -234,8 +231,6 @@ class PlayContext(Base):
|
||||||
# general flags (should we move out?)
|
# general flags (should we move out?)
|
||||||
if options.verbosity:
|
if options.verbosity:
|
||||||
self.verbosity = options.verbosity
|
self.verbosity = options.verbosity
|
||||||
#if options.no_log:
|
|
||||||
# self.no_log = boolean(options.no_log)
|
|
||||||
if options.check:
|
if options.check:
|
||||||
self.check_mode = boolean(options.check)
|
self.check_mode = boolean(options.check)
|
||||||
if hasattr(options, 'force_handlers') and options.force_handlers:
|
if hasattr(options, 'force_handlers') and options.force_handlers:
|
||||||
|
@ -322,6 +317,10 @@ class PlayContext(Base):
|
||||||
if task._local_action:
|
if task._local_action:
|
||||||
setattr(new_info, 'connection', 'local')
|
setattr(new_info, 'connection', 'local')
|
||||||
|
|
||||||
|
# set no_log to default if it was not previouslly set
|
||||||
|
if new_info.no_log is None:
|
||||||
|
new_info.no_log = C.DEFAULT_NO_LOG
|
||||||
|
|
||||||
return new_info
|
return new_info
|
||||||
|
|
||||||
def make_become_cmd(self, cmd, executable=None):
|
def make_become_cmd(self, cmd, executable=None):
|
||||||
|
|
|
@ -351,9 +351,13 @@ class ActionBase:
|
||||||
module_args['_ansible_check_mode'] = True
|
module_args['_ansible_check_mode'] = True
|
||||||
|
|
||||||
# set no log in the module arguments, if required
|
# set no log in the module arguments, if required
|
||||||
if self._play_context.no_log:
|
if self._play_context.no_log or not C.DEFAULT_MANAGED_SYSLOG:
|
||||||
module_args['_ansible_no_log'] = True
|
module_args['_ansible_no_log'] = True
|
||||||
|
|
||||||
|
# set debug in the module arguments, if required
|
||||||
|
if C.DEFAULT_DEBUG:
|
||||||
|
module_args['_ansible_debug'] = True
|
||||||
|
|
||||||
(module_style, shebang, module_data) = self._configure_module(module_name=module_name, module_args=module_args, task_vars=task_vars)
|
(module_style, shebang, module_data) = self._configure_module(module_name=module_name, module_args=module_args, task_vars=task_vars)
|
||||||
if not shebang:
|
if not shebang:
|
||||||
raise AnsibleError("module is missing interpreter line")
|
raise AnsibleError("module is missing interpreter line")
|
||||||
|
|
|
@ -79,7 +79,6 @@ class TestPlayContext(unittest.TestCase):
|
||||||
self.assertEqual(play_context.remote_user, 'mock')
|
self.assertEqual(play_context.remote_user, 'mock')
|
||||||
self.assertEqual(play_context.password, '')
|
self.assertEqual(play_context.password, '')
|
||||||
self.assertEqual(play_context.port, 1234)
|
self.assertEqual(play_context.port, 1234)
|
||||||
self.assertEqual(play_context.no_log, True)
|
|
||||||
self.assertEqual(play_context.become, True)
|
self.assertEqual(play_context.become, True)
|
||||||
self.assertEqual(play_context.become_method, "mock")
|
self.assertEqual(play_context.become_method, "mock")
|
||||||
self.assertEqual(play_context.become_user, "mockroot")
|
self.assertEqual(play_context.become_user, "mockroot")
|
||||||
|
@ -87,11 +86,11 @@ class TestPlayContext(unittest.TestCase):
|
||||||
mock_task = MagicMock()
|
mock_task = MagicMock()
|
||||||
mock_task.connection = 'mocktask'
|
mock_task.connection = 'mocktask'
|
||||||
mock_task.remote_user = 'mocktask'
|
mock_task.remote_user = 'mocktask'
|
||||||
|
mock_task.no_log = mock_play.no_log
|
||||||
mock_task.become = True
|
mock_task.become = True
|
||||||
mock_task.become_method = 'mocktask'
|
mock_task.become_method = 'mocktask'
|
||||||
mock_task.become_user = 'mocktaskroot'
|
mock_task.become_user = 'mocktaskroot'
|
||||||
mock_task.become_pass = 'mocktaskpass'
|
mock_task.become_pass = 'mocktaskpass'
|
||||||
mock_task.no_log = False
|
|
||||||
mock_task._local_action = False
|
mock_task._local_action = False
|
||||||
|
|
||||||
all_vars = dict(
|
all_vars = dict(
|
||||||
|
@ -106,12 +105,16 @@ class TestPlayContext(unittest.TestCase):
|
||||||
self.assertEqual(play_context.connection, 'mock_inventory')
|
self.assertEqual(play_context.connection, 'mock_inventory')
|
||||||
self.assertEqual(play_context.remote_user, 'mocktask')
|
self.assertEqual(play_context.remote_user, 'mocktask')
|
||||||
self.assertEqual(play_context.port, 4321)
|
self.assertEqual(play_context.port, 4321)
|
||||||
self.assertEqual(play_context.no_log, False)
|
self.assertEqual(play_context.no_log, True)
|
||||||
self.assertEqual(play_context.become, True)
|
self.assertEqual(play_context.become, True)
|
||||||
self.assertEqual(play_context.become_method, "mocktask")
|
self.assertEqual(play_context.become_method, "mocktask")
|
||||||
self.assertEqual(play_context.become_user, "mocktaskroot")
|
self.assertEqual(play_context.become_user, "mocktaskroot")
|
||||||
self.assertEqual(play_context.become_pass, "mocktaskpass")
|
self.assertEqual(play_context.become_pass, "mocktaskpass")
|
||||||
|
|
||||||
|
mock_task.no_log = False
|
||||||
|
play_context = play_context.set_task_and_variable_override(task=mock_task, variables=all_vars, templar=mock_templar)
|
||||||
|
self.assertEqual(play_context.no_log, False)
|
||||||
|
|
||||||
def test_play_context_make_become_cmd(self):
|
def test_play_context_make_become_cmd(self):
|
||||||
(options, args) = self._parser.parse_args([])
|
(options, args) = self._parser.parse_args([])
|
||||||
play_context = PlayContext(options=options)
|
play_context = PlayContext(options=options)
|
||||||
|
|
Loading…
Reference in a new issue