From 47d5e7a7b93d2c990aa61e16fbfb932a3b95e098 Mon Sep 17 00:00:00 2001 From: Pavlo Shchelokovskyy Date: Mon, 19 Jun 2017 08:43:22 +0000 Subject: [PATCH] [ansible] add journald and syslog loggers since DevStack is now using systemd, we can leverage that when setting up callback_plugin used by Ansible started by ansble-deploy driver. This patch adds two more options to the ironic_log callback plugin configuration file - use_journal and use_syslog. When set, they will override respective values from ironic config. The callback plugin config is set to force usage of journald by default in the devstack plugin. Change-Id: I5c788dd6621c95a28aecc727a3988ad4f101b2a8 --- devstack/plugin.sh | 12 +- .../playbooks/callback_plugins/ironic_log.ini | 15 ++- .../playbooks/callback_plugins/ironic_log.py | 115 +++++++++++------- .../ansible-journald-9a13cdd23f4a30ba.yaml | 5 + 4 files changed, 95 insertions(+), 52 deletions(-) create mode 100644 releasenotes/notes/ansible-journald-9a13cdd23f4a30ba.yaml diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 324088b..06b39d9 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -23,6 +23,15 @@ function update_ironic_enabled_drivers { # setting IRONIC_ENABLED_DRIVERS will not take affect. Update ironic # configuration explicitly. iniset $IRONIC_CONF_FILE DEFAULT enabled_drivers "$IRONIC_ENABLED_DRIVERS" + + # set logging for ansible-deploy + # NOTE(pas-ha) w/o systemd or syslog, there will be no output of single + # ansible tasks to ironic log, only in the stdout returned by processutils + if [[ "$USE_SYSTEMD" == "True" ]]; then + iniset $IRONIC_STAGING_DRIVERS_DIR/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.ini ironic use_journal "True" + elif [[ "$SYSLOG" == "True" ]]; then + iniset $IRONIC_STAGING_DRIVERS_DIR/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.ini ironic use_syslog "True" + fi } function install_ironic_staging_drivers { @@ -96,9 +105,6 @@ function set_ansible_deploy_driver { --driver-info ansible_deploy_username=tc \ --driver-info ansible_deploy_key_file=$ansible_key_file done - # TODO(pas-ha) setup logging ansible callback plugin to log to specific file - # for now all ansible logs are seen in ir-cond logs when run in debug logging mode - # as stdout returned by processutils.execute } echo_summary "ironic-staging-drivers plugin.sh was called..." diff --git a/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.ini b/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.ini index e42a1c7..456edae 100644 --- a/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.ini +++ b/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.ini @@ -1,8 +1,15 @@ [ironic] # If Ironic's config is not in one of default oslo_config locations, # specify the path to it here -#config_file = None +#config_file = -# If running a testing system with only stderr logging (e.g. DevStack) -# specify an actual file to log into here, for example Ironic-Conductor one. -#log_file = None +# Force usage of journald +# use_journal = False + +# Force usage of syslog +#use_syslog = False + +# Force usage of given file to log to. +# Useful for a testing system with only stderr logging +# (e.g. DevStack deployed w/o systemd) +#log_file = diff --git a/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.py b/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.py index 6442053..765b7d8 100644 --- a/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.py +++ b/ironic_staging_drivers/ansible/playbooks/callback_plugins/ironic_log.py @@ -16,42 +16,62 @@ import os from oslo_config import cfg from oslo_log import log as logging +from oslo_utils import strutils import pbr.version CONF = cfg.CONF DOMAIN = 'ironic' +VERSION = pbr.version.VersionInfo(DOMAIN).release_string() -# parse callback plugin config and Ironic config, setup logging -basename = os.path.splitext(__file__)[0] -config = ConfigParser.ConfigParser() -ironic_config = None -ironic_log_file = None -try: - config.readfp(open(basename + ".ini")) - if config.has_option('ironic', 'config_file'): - ironic_config = config.get('ironic', 'config_file') - if config.has_option('ironic', 'log_file'): - ironic_log_file = config.get('ironic', 'log_file') -except Exception: - pass -version_info = pbr.version.VersionInfo(DOMAIN) +# find and parse callback config file +def parse_callback_config(): + basename = os.path.splitext(__file__)[0] + config = ConfigParser.ConfigParser() + callback_config = {'ironic_config': None, + 'ironic_log_file': None, + 'use_journal': False, + 'use_syslog': False} + try: + config.readfp(open(basename + ".ini")) + if config.has_option('ironic', 'config_file'): + callback_config['ironic_config'] = config.get( + 'ironic', 'config_file') + if config.has_option('ironic', 'log_file'): + callback_config['ironic_log_file'] = config.get( + 'ironic', 'log_file') + if config.has_option('ironic', 'use_journal'): + callback_config['use_journal'] = strutils.bool_from_string( + config.get('ironic', 'use_journal')) + if config.has_option('ironic', 'use_syslog'): + callback_config['use_syslog'] = strutils.bool_from_string( + config.get('ironic', 'use_syslog')) + except Exception: + pass + return callback_config -LOG = logging.getLogger(__name__, project=DOMAIN, - version=version_info.release_string()) -logging.register_options(CONF) -conf_kwargs = dict(args=[], project=DOMAIN, - version=version_info.release_string()) -if ironic_config: - conf_kwargs['default_config_files'] = [ironic_config] -CONF(**conf_kwargs) +def setup_log(): -if ironic_log_file: - CONF.set_override("log_file", ironic_log_file) + logging.register_options(CONF) -logging.setup(CONF, DOMAIN) + conf_kwargs = dict(args=[], project=DOMAIN, version=VERSION) + callback_config = parse_callback_config() + + if callback_config['ironic_config']: + conf_kwargs['default_config_files'] = [ + callback_config['ironic_config']] + CONF(**conf_kwargs) + + if callback_config['use_journal']: + CONF.set_override('use_journal', True) + if callback_config['use_syslog']: + CONF.set_override('use_syslog', True) + if callback_config['ironic_log_file']: + CONF.set_override("log_file", callback_config['ironic_log_file']) + + logging.setup(CONF, DOMAIN) class CallbackModule(object): @@ -62,6 +82,8 @@ class CallbackModule(object): CALLBACK_NEEDS_WHITELIST = True def __init__(self, display=None): + setup_log() + self.log = logging.getLogger(__name__) self.node = None def runner_msg_dict(self, result): @@ -76,41 +98,44 @@ class CallbackModule(object): node = self.node or "Node" name = task.get_name() if name == 'setup': - LOG.debug("Processing task %(name)s.", dict(name=name)) + self.log.debug("Processing task %(name)s.", dict(name=name)) else: - LOG.debug("Processing task %(name)s on node %(node)s.", - dict(name=name, node=node)) + self.log.debug("Processing task %(name)s on node %(node)s.", + dict(name=name, node=node)) def v2_runner_on_failed(self, result, *args, **kwargs): - LOG.error("Ansible task %(name)s failed on node %(node)s: %(res)s", - self.runner_msg_dict(result)) + self.log.error( + "Ansible task %(name)s failed on node %(node)s: %(res)s", + self.runner_msg_dict(result)) def v2_runner_on_ok(self, result): msg_dict = self.runner_msg_dict(result) if msg_dict['name'] == 'setup': - LOG.info("Ansible task 'setup' complete on node %(node)s", - msg_dict) + self.log.info("Ansible task 'setup' complete on node %(node)s", + msg_dict) else: - LOG.info("Ansible task %(name)s complete on node %(node)s: " - "%(res)s", msg_dict) + self.log.info("Ansible task %(name)s complete on node %(node)s: " + "%(res)s", msg_dict) def v2_runner_on_unreachable(self, result): - LOG.error("Node %(node)s was unreachable for Ansible task %(name)s: " - "%(res)s", self.runner_msg_dict(result)) + self.log.error( + "Node %(node)s was unreachable for Ansible task %(name)s: %(res)s", + self.runner_msg_dict(result)) def v2_runner_on_async_poll(self, result): - LOG.debug("Polled ansible task %(name)s for complete " - "on node %(node)s: %(res)s", - self.runner_msg_dict(result)) + self.log.debug("Polled ansible task %(name)s for complete " + "on node %(node)s: %(res)s", + self.runner_msg_dict(result)) def v2_runner_on_async_ok(self, result): - LOG.info("Async Ansible task %(name)s complete on node %(node)s: " - "%(res)s", self.runner_msg_dict(result)) + self.log.info("Async Ansible task %(name)s complete on node %(node)s: " + "%(res)s", self.runner_msg_dict(result)) def v2_runner_on_async_failed(self, result): - LOG.error("Async Ansible task %(name)s failed on node %(node)s: " - "%(res)s", self.runner_msg_dict(result)) + self.log.error("Async Ansible task %(name)s failed on node %(node)s: " + "%(res)s", self.runner_msg_dict(result)) def v2_runner_on_skipped(self, result): - LOG.debug("Ansible task %(name)s skipped on node %(node)s: %(res)s", - self.runner_msg_dict(result)) + self.log.debug( + "Ansible task %(name)s skipped on node %(node)s: %(res)s", + self.runner_msg_dict(result)) diff --git a/releasenotes/notes/ansible-journald-9a13cdd23f4a30ba.yaml b/releasenotes/notes/ansible-journald-9a13cdd23f4a30ba.yaml new file mode 100644 index 0000000..00139d1 --- /dev/null +++ b/releasenotes/notes/ansible-journald-9a13cdd23f4a30ba.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + ``ironic_log`` Ansible callback plugin for ansible-deploy driver can now be + configured to force usage of journald or syslog for logging Ansible events.