# # engine # # Playout Daemon for autoradio project # # # Copyright (C) 2017-2018 Gottfried Gaisbauer <gottfried.gaisbauer@servus.at> # # This file is part of engine. # # engine is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # any later version. # # engine is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with engine. If not, see <http://www.gnu.org/licenses/>. # import os import datetime import threading from collections import namedtuple from modules.communication.mail import AuraMailer from libraries.exceptions.auraexceptions import MailingException from libraries.exceptions.auraexceptions import DiskSpaceException # ------------------------------------------------------------------------------------------ # class DiskSpaceWatcher(threading.Thread): liquidsoapcommunicator = None exit_event = None config = None logger = None mailer = None sent_a_mail = False is_critical = False # ------------------------------------------------------------------------------------------ # def __init__(self, config, logger, liquidsoapcommunicator): threading.Thread.__init__(self) self.liquidsoapcommunicator = liquidsoapcommunicator self.config = config self.logger = logger self.mailer = AuraMailer(self.config) self.exit_event = threading.Event() # ------------------------------------------------------------------------------------------ # def run(self): # set seconds to wait try: seconds_to_wait = int(self.config.get("diskspace_check_interval")) except: seconds_to_wait = 600 while not self.exit_event.is_set(): try: # calc next time next_time = datetime.datetime.now() + datetime.timedelta(seconds=seconds_to_wait) # check disk space self.check_disk_space() # write to logger self.logger.info("Diskspace checked! Going to start next time " + str(next_time)) # and wait self.exit_event.wait(seconds_to_wait) except BrokenPipeError as e: self.logger.critical("Cannot check if recorder is running. It seems LiquidSoap is not running. Reason: " + str(e)) # ------------------------------------------------------------------------------------------ # def stop(self): self.exit_event.set() # ------------------------------------------------------------------------------------------ # def check_disk_space(self): # check disk space where aure engine is writing to self.check_recorder_disk_space() self.check_logging_disk_space() if self.is_critical: self.logger.critical("Recorder STOPPED due to LOW diskspace! FIX THIS!!!") if self.sent_a_mail: self.logger.warning("Recorder is going stop soon because of not enough diskspace! FIX THIS!") if not self.is_critical and not self.sent_a_mail: self.logger.debug("No disk space issues detected.") self.is_critical = False self.sent_a_mail = False # ------------------------------------------------------------------------------------------ # def check_recorder_disk_space(self): for i in range(5): if self.config.get("rec_" + str(i)) == "y": self.check_recorder_num_disk_space(i) # ------------------------------------------------------------------------------------------ # def check_recorder_num_disk_space(self, num): folder = self.config.get("rec_" + str(num) + "_folder") try: self.check_disk_space_of_folder(folder) # ensure recorder is running if self.liquidsoapcommunicator.is_liquidsoap_running: self.liquidsoapcommunicator.recorder_start(num) else: self.logger.warning("Cannot enable recorder. Liquidsoap is not running!") except DiskSpaceException as e: self.logger.critical(str(e)) # stop recorder when diskspace is critical if self.liquidsoapcommunicator.is_liquidsoap_running: self.liquidsoapcommunicator.recorder_stop(num) else: self.logger.warning("Cannot stop recorder. Liquidsoap is not running!") # ------------------------------------------------------------------------------------------ # def check_logging_disk_space(self): try: self.check_disk_space_of_folder(self.config.get("logdir")) except DiskSpaceException as e: self.logger.critical(str(e)) # ------------------------------------------------------------------------------------------ # def check_disk_space_of_folder(self, folder): warning_value_raw = self.config.get("diskspace_warning_value") critical_value_raw = self.config.get("diskspace_critical_value") try: warning_value = self.parse_diskspace(warning_value_raw) except ValueError: warning_value_raw = "2G" warning_value = self.parse_diskspace(warning_value_raw) try: critical_value = self.parse_diskspace(critical_value_raw) except ValueError: critical_value_raw = "200M" critical_value = self.parse_diskspace(critical_value_raw) usage = namedtuple("usage", "total used free") diskspace = os.statvfs(folder) free = diskspace.f_bavail * diskspace.f_frsize total = diskspace.f_blocks * diskspace.f_frsize used = (diskspace.f_blocks - diskspace.f_bfree) * diskspace.f_frsize if free < warning_value: subj = "Diskspace warning" msg = "Free space in " + folder + " under " + warning_value_raw + ". " + str(usage(total, used, free)) self.send_mail(subj, msg) if self.liquidsoapcommunicator.is_liquidsoap_running: self.liquidsoapcommunicator.recorder_start() else: self.logger.warning("Cannot enable recorder. Liquidsoap is not running!") self.sent_a_mail = True elif free < critical_value: subj = "Critical diskspace - Recorder stopped!" msg = "Free space in " + folder + " under " + critical_value_raw + ". " + str(usage(total, used, free)) self.send_mail(subj, msg) self.sent_a_mail = True self.is_critical = True raise DiskSpaceException("Diskspace in " + folder + " reached critical value!") # ------------------------------------------------------------------------------------------ # def send_mail(self, subj, msg): try: self.logger.info("Trying to send mail with subject " + subj + " and message " + msg + ".") self.mailer.send_admin_mail(subj, msg) except MailingException as e: self.logger.critical("Cannot send mail with subject " + subj + " and message " + msg + ". Reason: " + str(e)) # ------------------------------------------------------------------------------------------ # def parse_diskspace(self, value): if value.endswith("K") or value.endswith("k"): return int(value[:-1]) * 1024 if value.endswith("M") or value.endswith("m"): return int(value[:-1]) * 1024 * 1024 if value.endswith("G") or value.endswith("g"): return int(value[:-1]) * 1024 * 1024 * 1024 if value.endswith("T") or value.endswith("t"): return int(value[:-1]) * 1024 * 1024 * 1024 * 1024 return int(value)