Skip to content

Commit

Permalink
move fluentd config check to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
juanvallejo committed Jun 27, 2017
1 parent a7a2729 commit 75f7a0f
Show file tree
Hide file tree
Showing 4 changed files with 322 additions and 161 deletions.
173 changes: 173 additions & 0 deletions roles/openshift_health_checker/openshift_checks/fluentd_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
"""
Module for performing checks on an Fluentd logging deployment configuration
"""

from openshift_checks import OpenShiftCheck, OpenShiftCheckException, get_var

import json
import os


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

logging_namespace = None

@classmethod
def is_active(cls, task_vars):
return super(FluentdConfig, cls).is_active(task_vars)

def run(self, tmp, task_vars):
"""Check that Fluentd has running pods, and that its logging config matches Docker's logging config."""

self.logging_namespace = get_var(task_vars, "openshift_logging_namespace", default="logging")
fluentd_pods, error = self.get_pods_for_component(
self.execute_module,
self.logging_namespace,
"fluentd",
task_vars,
)
if error:
return {"failed": True, "changed": False, "msg": error}

running_fluentd_pods = self.running_pods(fluentd_pods)
if not len(running_fluentd_pods):
msg = ('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 {"failed": True, "changed": False, "msg": msg}

config_error = self.check_logging_config(fluentd_pods, task_vars)
if config_error:
msg = ("The following Fluentd logging configuration problem was found:"
"\n-------\n"
"{}".format(config_error))
return {"failed": True, "changed": False, "msg": msg}

return {"failed": False, "changed": False, "msg": 'No problems found with Fluentd logging configuration.'}

def check_logging_config(self, fluentd_pods, task_vars):
"""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."""

pod_name = fluentd_pods[0]["metadata"]["name"]
try:
use_journald = self.exec_oc(
self.execute_module,
self.logging_namespace,
"exec {} /bin/printenv USE_JOURNAL".format(pod_name),
[], task_vars
)
except OpenShiftCheckException as error:
if "false" not in str(error):
return str(error)

use_journald = False

docker_info = self.execute_module("docker_info", {}, task_vars)
if not docker_info.get("info", False):
return "No information was returned by the Docker client. Unable to verify the logging driver in use."

if not docker_info["info"].get("LoggingDriver", False):
return "No logging driver information was returned by the Docker client."

logging_driver = docker_info["info"]["LoggingDriver"]
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.\n').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.\n').format(driver=logging_driver)

if error:
error += ('To 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 get_pods_for_component(self, execute_module, namespace, logging_component, task_vars):
"""Get all pods for a given component. Returns: list of pods for component, error string."""
pod_output = self.exec_oc(
execute_module,
namespace,
"get pods -l component={} -o json".format(logging_component),
[],
task_vars
)
try:
pods = json.loads(pod_output)
if not pods or not pods.get('items'):
raise ValueError()
except ValueError:
# successful run but non-parsing data generally means there were no pods in the namespace
return None, 'There are no pods in the {} namespace. Is logging deployed?'.format(namespace)

return pods['items'], None

@staticmethod
def running_pods(pods):
"""Returns: list of pods in a running state."""
return [
pod for pod in pods
if pod['status']['phase'] == 'Running'
]

@staticmethod
def exec_oc(execute_module=None, namespace="logging", cmd_str="", extra_args=None, task_vars=None):
"""Execute an 'oc' command in the remote host.
Returns: output of command and namespace,
or raises OpenShiftCheckException on error."""
config_base = get_var(task_vars, "openshift", "common", "config_base")
args = {
"namespace": namespace,
"config_file": os.path.join(config_base, "master", "admin.kubeconfig"),
"cmd": cmd_str,
"extra_args": list(extra_args) if extra_args else [],
}

result = execute_module("ocutil", args, task_vars)
if result.get("failed"):
msg = (
'Unexpected error using `oc` to validate the logging stack components.\n'
'Error executing `oc {cmd}`:\n'
'{error}'
).format(cmd=args['cmd'], error=result['result'])

if result['result'] == '[Errno 2] No such file or directory':
msg = (
"This host is supposed to be a master but does not have the `oc` command where expected.\n"
"Has an installation been run on this host yet?"
)
raise OpenShiftCheckException(msg)

return result.get("result", "")
69 changes: 0 additions & 69 deletions roles/openshift_health_checker/openshift_checks/logging/fluentd.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,78 +35,9 @@ def run(self, tmp, task_vars):
"{}".format(check_error))
return {"failed": True, "changed": False, "msg": msg}

config_error = self.check_logging_config(fluentd_pods, task_vars)
if config_error:
msg = ("The following Fluentd logging configuration problem was found:"
"\n-------\n"
"{}".format(config_error))
return {"failed": True, "changed": False, "msg": msg}

# TODO(lmeyer): run it all again for the ops cluster
return {"failed": False, "changed": False, "msg": 'No problems found with Fluentd deployment.'}

def check_logging_config(self, fluentd_pods, task_vars):
"""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."""

pod_name = fluentd_pods[0]["metadata"]["name"]
try:
use_journald = self._exec_oc("exec {} /bin/printenv USE_JOURNAL".format(pod_name), [], task_vars)
except OpenShiftCheckException as error:
if "false" not in str(error):
return str(error)

use_journald = False

docker_info = self.execute_module("docker_info", {}, task_vars)
if not docker_info.get("info", False):
return "No information was returned by the Docker client. Unable to verify the logging driver in use."

if not docker_info["info"].get("LoggingDriver", False):
return "No logging driver information was returned by the Docker client."

logging_driver = docker_info["info"]["LoggingDriver"]
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.\n').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.\n').format(driver=logging_driver)

if error:
error += ('To 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

@staticmethod
def _filter_fluentd_labeled_nodes(nodes_by_name, node_selector):
"""Filter to all nodes with fluentd label. Returns dict(name: node), error string"""
Expand Down
Loading

0 comments on commit 75f7a0f

Please sign in to comment.