summaryrefslogtreecommitdiffstats
path: root/roles/openshift_health_checker/openshift_checks
diff options
context:
space:
mode:
authorjuanvallejo <jvallejo@redhat.com>2017-03-24 18:54:09 -0400
committerLuke Meyer <lmeyer@redhat.com>2017-06-01 15:16:35 -0400
commit055082c1679cb253758bc16e0a6ca37f70d0bc65 (patch)
tree9c63e5ca8918d46e9cb66f2408506e937efc51f3 /roles/openshift_health_checker/openshift_checks
parent1015166e2d7fe02a2f6a42cea53b1d64a119a80e (diff)
downloadopenshift-055082c1679cb253758bc16e0a6ca37f70d0bc65.tar.gz
openshift-055082c1679cb253758bc16e0a6ca37f70d0bc65.tar.bz2
openshift-055082c1679cb253758bc16e0a6ca37f70d0bc65.tar.xz
openshift-055082c1679cb253758bc16e0a6ca37f70d0bc65.zip
add docker storage, docker driver checks
Diffstat (limited to 'roles/openshift_health_checker/openshift_checks')
-rw-r--r--roles/openshift_health_checker/openshift_checks/docker_storage.py110
-rw-r--r--roles/openshift_health_checker/openshift_checks/docker_storage_driver.py50
2 files changed, 160 insertions, 0 deletions
diff --git a/roles/openshift_health_checker/openshift_checks/docker_storage.py b/roles/openshift_health_checker/openshift_checks/docker_storage.py
new file mode 100644
index 000000000..2dfe10a02
--- /dev/null
+++ b/roles/openshift_health_checker/openshift_checks/docker_storage.py
@@ -0,0 +1,110 @@
+# pylint: disable=missing-docstring
+import json
+
+from openshift_checks import OpenShiftCheck, OpenShiftCheckException, get_var
+
+
+class DockerStorage(OpenShiftCheck):
+ """Check Docker storage sanity.
+
+ Check for thinpool usage during a containerized installation
+ """
+
+ name = "docker_storage"
+ tags = ["preflight"]
+
+ max_thinpool_data_usage_percent = 90.0
+ max_thinpool_meta_usage_percent = 90.0
+
+ @classmethod
+ def is_active(cls, task_vars):
+ """Only run on hosts that depend on Docker."""
+ is_containerized = get_var(task_vars, "openshift", "common", "is_containerized")
+ is_node = "nodes" in get_var(task_vars, "group_names", default=[])
+ return (super(DockerStorage, cls).is_active(task_vars) and is_containerized) or is_node
+
+ def run(self, tmp, task_vars):
+ try:
+ self.max_thinpool_data_usage_percent = float(get_var(task_vars, "max_thinpool_data_usage_percent",
+ default=self.max_thinpool_data_usage_percent))
+ self.max_thinpool_meta_usage_percent = float(get_var(task_vars, "max_thinpool_metadata_usage_percent",
+ default=self.max_thinpool_meta_usage_percent))
+ except ValueError as err:
+ return {
+ "failed": True,
+ "msg": "Unable to convert thinpool data usage limit to float: {}".format(str(err))
+ }
+
+ err_msg = self.check_thinpool_usage(task_vars)
+ if err_msg:
+ return {"failed": True, "msg": err_msg}
+
+ return {}
+
+ def check_thinpool_usage(self, task_vars):
+ lvs = self.get_lvs_data(task_vars)
+ lv_data = self.extract_thinpool_obj(lvs)
+
+ data_percent = self.get_thinpool_data_usage(lv_data)
+ metadata_percent = self.get_thinpool_metadata_usage(lv_data)
+
+ if data_percent > self.max_thinpool_data_usage_percent:
+ msg = "thinpool data usage above maximum threshold of {threshold}%"
+ return msg.format(threshold=self.max_thinpool_data_usage_percent)
+
+ if metadata_percent > self.max_thinpool_meta_usage_percent:
+ msg = "thinpool metadata usage above maximum threshold of {threshold}%"
+ return msg.format(threshold=self.max_thinpool_meta_usage_percent)
+
+ return ""
+
+ def get_lvs_data(self, task_vars):
+ lvs_cmd = "/sbin/lvs --select vg_name=docker --select lv_name=docker-pool --report-format json"
+ result = self.exec_cmd(lvs_cmd, task_vars)
+
+ if result.get("failed", False):
+ msg = "no thinpool usage data returned by the host: {}"
+ raise OpenShiftCheckException(msg.format(result.get("msg", "")))
+
+ try:
+ data_json = json.loads(result.get("stdout", ""))
+ except ValueError as err:
+ raise OpenShiftCheckException("Invalid JSON value returned by lvs command: {}".format(str(err)))
+
+ data = data_json.get("report")
+ if not data:
+ raise OpenShiftCheckException("no thinpool usage data returned by the host.")
+
+ return data
+
+ @staticmethod
+ def get_thinpool_data_usage(thinpool_lv_data):
+ data = thinpool_lv_data.get("data_percent")
+ if not data:
+ raise OpenShiftCheckException("no thinpool usage data returned by the host.")
+
+ return float(data)
+
+ @staticmethod
+ def get_thinpool_metadata_usage(thinpool_lv_data):
+ data = thinpool_lv_data.get("metadata_percent")
+ if not data:
+ raise OpenShiftCheckException("no thinpool usage data returned by the host.")
+
+ return float(data)
+
+ @staticmethod
+ def extract_thinpool_obj(thinpool_data):
+ if not thinpool_data or not thinpool_data[0]:
+ raise OpenShiftCheckException("no thinpool usage data returned by the host.")
+
+ lv_data = thinpool_data[0].get("lv")
+ if not lv_data or not lv_data[0]:
+ raise OpenShiftCheckException("no thinpool usage data returned by the host.")
+
+ return lv_data[0]
+
+ def exec_cmd(self, cmd_str, task_vars):
+ return self.execute_module("command", {
+ "_raw_params": cmd_str,
+ }, task_vars)
diff --git a/roles/openshift_health_checker/openshift_checks/docker_storage_driver.py b/roles/openshift_health_checker/openshift_checks/docker_storage_driver.py
new file mode 100644
index 000000000..94ea7ba9c
--- /dev/null
+++ b/roles/openshift_health_checker/openshift_checks/docker_storage_driver.py
@@ -0,0 +1,50 @@
+# pylint: disable=missing-docstring
+from openshift_checks import OpenShiftCheck, get_var
+
+
+class DockerStorageDriver(OpenShiftCheck):
+ """Check Docker storage driver compatibility.
+
+ This check ensures that Docker is using a supported storage driver,
+ and that Loopback is not being used (if using devicemapper).
+ """
+
+ name = "docker_storage_driver"
+ tags = ["preflight"]
+
+ storage_drivers = ["devicemapper", "overlay2"]
+
+ @classmethod
+ def is_active(cls, task_vars):
+ """Skip non-containerized installations."""
+ is_containerized = get_var(task_vars, "openshift", "common", "is_containerized")
+ return super(DockerStorageDriver, cls).is_active(task_vars) and is_containerized
+
+ def run(self, tmp, task_vars):
+ info = self.execute_module("docker_info", {}, task_vars).get("info", {})
+
+ if not self.is_supported_storage_driver(info):
+ msg = "Unsupported Docker storage driver detected. Supported storage drivers: {drivers}"
+ return {"failed": True, "msg": msg.format(drivers=', '.join(self.storage_drivers))}
+
+ if self.is_using_loopback_device(info):
+ msg = "Use of loopback devices is discouraged. Try running Docker with `--storage-opt dm.thinpooldev`"
+ return {"failed": True, "msg": msg}
+
+ return {}
+
+ def is_supported_storage_driver(self, docker_info):
+ return docker_info.get("Driver", "") in self.storage_drivers
+
+ @staticmethod
+ def is_using_loopback_device(docker_info):
+ # Loopback device usage is only an issue if using devicemapper.
+ # Skip this check if using any other storage driver.
+ if docker_info.get("Driver", "") != "devicemapper":
+ return False
+
+ for status in docker_info.get("DriverStatus", []):
+ if status[0] == "Data loop file":
+ return bool(status[1])
+
+ return False