"""
Module for performing checks on a Fluentd logging deployment configuration
"""
import json
from openshift_checks import OpenShiftCheckException
from openshift_checks.logging.logging import LoggingCheck


class FluentdConfig(LoggingCheck):
    """Module that checks logging configuration of an integrated logging Fluentd deployment"""
    name = "fluentd_config"
    tags = ["health"]

    def is_active(self):
        logging_deployed = self.get_var("openshift_logging_install_logging", default=False)

        try:
            version = self.get_major_minor_version(self.get_var("openshift_image_tag"))
        except ValueError:
            # if failed to parse OpenShift version, perform check anyway (if logging enabled)
            return logging_deployed

        return logging_deployed and version < (3, 6)

    def run(self):
        """Check that Fluentd has running pods, and that its logging config matches Docker's logging config."""
        config_error = self.check_logging_config()
        if config_error:
            msg = ("The following Fluentd logging configuration problem was found:"
                   "\n{}".format(config_error))
            return {"failed": True, "msg": msg}

        return {}

    def check_logging_config(self):
        """Ensure that the configured Docker logging driver matches fluentd settings.
        This means that, at least for now, if the following condition is met:

            openshift_logging_fluentd_use_journal == True

        then the value of the configured Docker logging driver should be "journald".
        Otherwise, the value of the Docker logging driver should be "json-file".
        Returns an error string if the above condition is not met, or None otherwise."""
        use_journald = self.get_var("openshift_logging_fluentd_use_journal", default=True)

        # if check is running on a master, retrieve all running pods
        # and check any pod's container for the env var "USE_JOURNAL"
        group_names = self.get_var("group_names")
        if "oo_masters_to_config" in group_names:
            use_journald = self.check_fluentd_env_var()

        command = ' '.join(['docker', 'info', '--format', '"{{json .}}"'])
        command_args = dict(_raw_params=command)
        command_result = self.execute_module('command', command_args)
        if command_result.get('rc', 0) != 0 or command_result.get('failed'):
            raise OpenShiftCheckException(
                'RemoteCommandFailure',
                'Failed to execute command on remote host: %s' % command)
        docker_info = json.loads(command_result["stdout"])
        try:
            logging_driver = docker_info["LoggingDriver"]
        except KeyError:
            return "Unable to determine Docker logging driver."

        recommended_logging_driver = "journald"
        error = None

        # If fluentd is set to use journald but Docker is not, recommend setting the `--log-driver`
        # option as an inventory file variable, or adding the log driver value as part of the
        # Docker configuration in /etc/docker/daemon.json. There is no global --log-driver flag that
        # can be passed to the Docker binary; the only other recommendation that can be made, would be
        # to pass the `--log-driver` flag to the "run" sub-command of the `docker` binary when running
        # individual containers.
        if use_journald and logging_driver != "journald":
            error = ('Your Fluentd configuration is set to aggregate Docker container logs from "journald".\n'
                     'This differs from your Docker configuration, which has been set to use "{driver}" '
                     'as the default method of storing logs.\n'
                     'This discrepancy in configuration will prevent Fluentd from receiving any logs'
                     'from your Docker containers.').format(driver=logging_driver)
        elif not use_journald and logging_driver != "json-file":
            recommended_logging_driver = "json-file"
            error = ('Your Fluentd configuration is set to aggregate Docker container logs from '
                     'individual json log files per container.\n '
                     'This differs from your Docker configuration, which has been set to use '
                     '"{driver}" as the default method of storing logs.\n'
                     'This discrepancy in configuration will prevent Fluentd from receiving any logs'
                     'from your Docker containers.').format(driver=logging_driver)

        if error:
            error += ('\nTo resolve this issue, add the following variable to your Ansible inventory file:\n\n'
                      '  openshift_docker_options="--log-driver={driver}"\n\n'
                      'Alternatively, you can add the following option to your Docker configuration, located in'
                      '"/etc/docker/daemon.json":\n\n'
                      '{{ "log-driver": "{driver}" }}\n\n'
                      'See https://docs.docker.com/engine/admin/logging/json-file '
                      'for more information.').format(driver=recommended_logging_driver)

        return error

    def check_fluentd_env_var(self):
        """Read and return the value of the 'USE_JOURNAL' environment variable on a fluentd pod."""
        running_pods = self.running_fluentd_pods()

        try:
            pod_containers = running_pods[0]["spec"]["containers"]
        except KeyError:
            return "Unable to detect running containers on selected Fluentd pod."

        if not pod_containers:
            msg = ('There are no running containers on selected Fluentd pod "{}".\n'
                   'Unable to calculate expected logging driver.').format(running_pods[0]["metadata"].get("name", ""))
            raise OpenShiftCheckException(msg)

        pod_env = pod_containers[0].get("env")
        if not pod_env:
            msg = ('There are no environment variables set on the Fluentd container "{}".\n'
                   'Unable to calculate expected logging driver.').format(pod_containers[0].get("name"))
            raise OpenShiftCheckException(msg)

        for env in pod_env:
            if env["name"] == "USE_JOURNAL":
                return env.get("value", "false") != "false"

        return False

    def running_fluentd_pods(self):
        """Return a list of running fluentd pods."""
        fluentd_pods = self.get_pods_for_component("fluentd")

        running_fluentd_pods = [pod for pod in fluentd_pods if pod['status']['phase'] == 'Running']
        if not running_fluentd_pods:
            raise OpenShiftCheckException(
                'No Fluentd pods were found to be in the "Running" state. '
                'At least one Fluentd pod is required in order to perform this check.'
            )

        return running_fluentd_pods
