#!/usr/bin/env python import argparse import subprocess import sys import syslog import re def get_command_result(command): """Executes the command and return the resulting output. Args: command: A string contains the command to be executed. Returns: A string which contains the output of command. """ command_stdout = "" try: proc_instance = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True) command_stdout, command_stderr = proc_instance.communicate() if proc_instance.returncode != 0: syslog.syslog(syslog.LOG_ERR, "[memory_checker] Failed to execute the command '{}'. Return code: '{}'" .format(command, proc_instance.returncode)) sys.exit(1) except (OSError, ValueError) as err: syslog.syslog(syslog.LOG_ERR, "[memory_checker] Failed to execute the command '{}'. Error: '{}'" .format(command, err)) sys.exit(2) return command_stdout.strip() def check_memory_usage(container_name, threshold_value): """Checks the memory usage of a container and writes an alerting messages into the syslog if the memory usage is larger than the threshold value. Args: container_name: A string represtents name of a container threshold_value: An integer indicates the threshold value (Bytes) of memory usage. Returns: None. """ command = "docker stats --no-stream --format \{{\{{.MemUsage\}}\}} {}".format(container_name) command_stdout = get_command_result(command) mem_usage = command_stdout.split("/")[0].strip() match_obj = re.match(r"\d+\.?\d*", mem_usage) if match_obj: mem_usage_value = float(mem_usage[match_obj.start():match_obj.end()]) mem_usage_unit = mem_usage[match_obj.end():] mem_usage_bytes = 0.0 if mem_usage_unit == "B": mem_usage_bytes = mem_usage_value elif mem_usage_unit == "KiB": mem_usage_bytes = mem_usage_value * 1024 elif mem_usage_unit == "MiB": mem_usage_bytes = mem_usage_value * 1024 ** 2 elif mem_usage_unit == "GiB": mem_usage_bytes = mem_usage_value * 1024 ** 3 if mem_usage_bytes > threshold_value: print("[{}]: Memory usage ({} Bytes) is larger than the threshold ({} Bytes)!" .format(container_name, mem_usage_bytes, threshold_value)) sys.exit(3) else: syslog.syslog(syslog.LOG_ERR, "[memory_checker] Failed to retrieve memory value from '{}'" .format(mem_usage)) sys.exit(4) def main(): parser = argparse.ArgumentParser(description="Check memory usage of a container \ and an alerting message will be written into syslog if memory usage \ is larger than the threshold value", usage="/usr/bin/memory_checker ") parser.add_argument("container_name", help="container name") # TODO: Currently the threshold value is hard coded as a command line argument and will # remove this in the new version since we want to read this value from 'CONFIG_DB'. parser.add_argument("threshold_value", type=int, help="threshold value in bytes") args = parser.parse_args() check_memory_usage(args.container_name, args.threshold_value) if __name__ == "__main__": main()