From df23d4d0d4c7bcbb11f96ceba83570d0a6721c99 Mon Sep 17 00:00:00 2001 From: telecaster Date: Mon, 9 Dec 2024 16:10:52 +0100 Subject: [PATCH] add nagios scripts (to copy in /home/sonde-nagios) --- bin/monitoring/nagios/check_disk | 61 +++++ bin/monitoring/nagios/check_domain.py | 55 +++++ bin/monitoring/nagios/check_inode | 58 +++++ bin/monitoring/nagios/check_load | Bin 0 -> 51568 bytes bin/monitoring/nagios/check_md_raid | 263 ++++++++++++++++++++++ bin/monitoring/nagios/check_mem.sh | 38 ++++ bin/monitoring/nagios/check_smartdisk | 122 ++++++++++ bin/monitoring/nagios/check_ssl | 24 ++ bin/monitoring/nagios/check_telecaster.py | 104 +++++++++ 9 files changed, 725 insertions(+) create mode 100755 bin/monitoring/nagios/check_disk create mode 100755 bin/monitoring/nagios/check_domain.py create mode 100755 bin/monitoring/nagios/check_inode create mode 100755 bin/monitoring/nagios/check_load create mode 100755 bin/monitoring/nagios/check_md_raid create mode 100755 bin/monitoring/nagios/check_mem.sh create mode 100755 bin/monitoring/nagios/check_smartdisk create mode 100755 bin/monitoring/nagios/check_ssl create mode 100755 bin/monitoring/nagios/check_telecaster.py diff --git a/bin/monitoring/nagios/check_disk b/bin/monitoring/nagios/check_disk new file mode 100755 index 0000000..4a1fcb8 --- /dev/null +++ b/bin/monitoring/nagios/check_disk @@ -0,0 +1,61 @@ +#!/bin/sh + +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin + +# Arguments before traitement + +warninglevel=10% +criticallevel=5% +filetest=/ + +#Get Arguments + +while test "$#" -gt 0 ; do + if test "$1" = "-w"; then + shift + warninglevel=$1 + fi + if test "$1" = "-p"; then + shift + filetest=$1 + fi + if test "$1" = "-c"; then + shift + criticallevel=$1 + fi + shift +done + +# Get real values + +valueinfo=`df $filetest | tail -n +2 | awk '{ print $5 }'` +realspace=`df -h $filetest | tail -n +2 | awk '{ print $4 }'` + +# Delete the % before testing + +warninglevelreduced=`echo $warninglevel | tr -d %` +criticallevelreduced=`echo $criticallevel | tr -d %` +valuetest=`echo $valueinfo | tr -d %` +valuetest=$((100 - $valuetest)) + +# Test if we are in critical situation +msg="- free space: $filetest $realspace ($valuetest %)" + +if [ $valuetest -le $criticallevelreduced ] +then + echo DISK CRITICAL $msg + exit 2 +fi + +# Test if we are in warning situation + +if [ $valuetest -le $warninglevelreduced ] +then + echo DISK WARNING $msg + exit 1 +fi + +# All is fine +echo DISK OK $msg +exit 0 + diff --git a/bin/monitoring/nagios/check_domain.py b/bin/monitoring/nagios/check_domain.py new file mode 100755 index 0000000..bfe315b --- /dev/null +++ b/bin/monitoring/nagios/check_domain.py @@ -0,0 +1,55 @@ +#!/usr/bin/python3 +import sys, os, re, subprocess +from datetime import date as da + +def check_domain(dom=""): + OK_STATE = 0 + WARNING_STATE = 1 + CRITICAL_STATE = 2 + if not dom: + sys.exit(WARNING_STATE) + dom = re.sub('^[^.]*\.(?=[a-zA-Z0-9_\-]*\.\w)', '', dom) + try: + res = subprocess.check_output(["whois", dom], encoding='utf-8') + except subprocess.CalledProcessError as e: + # HACK : sometimes whois exits with 1 but still give info... + if e.returncode == 1: + res = e.output + else: + print("The domain {0} seems to be dead".format(dom)) + sys.exit(CRITICAL_STATE) + lst = ['Expiry', 'Expires', 'Expiration', 'paid-till'] + res = res.split('\n') + st = "" + + for item in res: + for word in lst: + if word in item and ':' in item: + val = item.split(':', 1)[1].strip() + if val: + st = val + + if not st: + print("The probe must be checked for domain {0}").format(dom) + sys.exit(WARNING_STATE) + + if "fr" in dom: # For .fr TLDs + st = st.split('/') + if len(st) > 1: + tmp = st[0] + st[0] = st[2] + st[2] = tmp + st = "/".join(st) + st = subprocess.check_output(["date", "-d", st, "+%Y/%m/%d"], encoding='utf-8') + st = st.split('/') + remaining = ((da(int(st[0]),int(st[1]),int(st[2]))-da.today())).days + print("There are {0} days remaining until expiration of {1}".format(remaining, dom)) + if remaining > 30: + sys.exit(OK_STATE) + elif remaining < 30 and remaining > 7: + sys.exit(WARNING_STATE) + elif remaining < 7: + sys.exit(CRITICAL_STATE) + +if __name__ == '__main__': + check_domain(sys.argv[1]) diff --git a/bin/monitoring/nagios/check_inode b/bin/monitoring/nagios/check_inode new file mode 100755 index 0000000..5fba60c --- /dev/null +++ b/bin/monitoring/nagios/check_inode @@ -0,0 +1,58 @@ +#!/bin/sh + +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin + +# Arguments before traitement + +warninglevel=80% +criticallevel=90% +filetest=/ + +#Get Arguments + +while test "$#" -gt 0 ; do + if test "$1" = "-w"; then + shift + warninglevel=$1 + fi + if test "$1" = "-p"; then + shift + filetest=$1 + fi + if test "$1" = "-c"; then + shift + criticallevel=$1 + fi + shift +done + +# Delete the % before testing + +valueinfo=`df -i $filetest | tail -n +2 | awk '{ print $5 }'` +valuetest=`df -i $filetest | tail -n +2 | awk '{ print $5 }'` + +warninglevelreduced=`echo $warninglevel | tr -d %` +criticallevelreduced=`echo $criticallevel | tr -d %` +valuetestreduced=`echo $valuetest | tr -d %` + +# Test if we are in critical situation + +if [ $criticallevelreduced -le $valuetestreduced ] + then echo INODE CRITICAL - Inode occupation = $valueinfo +exit 2 +fi + +# Test if we are in warning situation + +if [ $warninglevelreduced -le $valuetestreduced ] + then echo INODE WARNING - Inode occupation = $valueinfo +exit 1 +fi + +# Test if we are in normal time + +if [ $valuetestreduced -le $warninglevelreduced ] + then echo INODE OK - Inode occupation = $valueinfo +exit 0 +fi + diff --git a/bin/monitoring/nagios/check_load b/bin/monitoring/nagios/check_load new file mode 100755 index 0000000000000000000000000000000000000000..1a03cf1e3db3b8e6901e274c697470fe0a72b47b GIT binary patch literal 51568 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 KSEt3GuYUm9Fz0>% literal 0 HcmV?d00001 diff --git a/bin/monitoring/nagios/check_md_raid b/bin/monitoring/nagios/check_md_raid new file mode 100755 index 0000000..6cab984 --- /dev/null +++ b/bin/monitoring/nagios/check_md_raid @@ -0,0 +1,263 @@ +#!/usr/bin/env python3 +# +# Copyright Hari Sekhon 2007 +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +""" This plugin for Nagios uses the standard mdadm program to get the status + of all the linux md arrays on the local machine using the mdadm utility""" + +__version__ = "0.7.3" + +import os +import re +import sys +from optparse import OptionParser + +# Standard Nagios return codes +OK = 0 +WARNING = 1 +CRITICAL = 2 +UNKNOWN = 3 + +# Full path to the mdadm utility check on the Raid state +BIN = "/sbin/mdadm" +SUDO = "/usr/bin/sudo" + +if not os.path.isfile(BIN): + print("No raid, No Check") + sys.exit(0) + +def end(status, message): + """exits the plugin with first arg as the return code and the second + arg as the message to output""" + + if status == OK: + print("RAID OK: %s" % message) + sys.exit(OK) + elif status == WARNING: + print("RAID WARNING: %s" % message) + sys.exit(WARNING) + elif status == CRITICAL: + print("RAID CRITICAL: %s" % message) + sys.exit(CRITICAL) + else: + print("UNKNOWN: %s" % message) + sys.exit(UNKNOWN) + +if not os.path.exists(BIN): + end(UNKNOWN, "Raid utility '%s' cannot be found" % BIN) + +if not os.access(BIN, os.X_OK): + end(UNKNOWN, "Raid utility '%s' is not executable" % BIN) + + +def find_arrays(verbosity): + """finds all MD arrays on local machine using mdadm and returns a list of + them, or exits UNKNOWN if no MD arrays are found""" + + if verbosity >= 3: + print("finding all MD arrays via: %s --detail --scan" % BIN) + devices_output = os.popen("%s %s --detail --scan" %(SUDO, BIN)).readlines() + raid_devices = [] + for line in devices_output: + if "ARRAY" in line: + raid_device = line.split()[1] + if verbosity >= 2: + print("found array %s" % raid_device) + raid_devices.append(raid_device) + + if len(raid_devices) == 0: + end(OK, "no MD raid devices found on this machine") + else: + raid_devices.sort() + return raid_devices + + +def test_raid(verbosity): + """checks all MD arrays on local machine, returns status code""" + + raid_devices = find_arrays(verbosity) + + status = OK + message = "" + arrays_not_ok = 0 + number_arrays = len(raid_devices) + for array in raid_devices: + if verbosity >= 2: + print('Now testing raid device "%s"' % array) + + detailed_output = os.popen("%s %s --detail %s" % (SUDO, BIN, array) ).readlines() + + if verbosity >= 3: + for line in detailed_output: + print(line) + + state = "unknown" + for line in detailed_output: + if "State :" in line: + state = line.split(":")[-1].strip() + re_clean = re.compile('^clean(, no-errors)?$') + if not re_clean.match(state) and state != "active" and state != "active, recovering": + arrays_not_ok += 1 + raidlevel = detailed_output[3].split()[-1] + shortname = array.split("/")[-1].upper() + if state == "dirty": + # This happens when the array is under heavy usage but it's \ + # normal and the array recovers within seconds + continue + +# added by Yanga Yann + + elif "clean, recovering" in state: + extra_info = None + for line in detailed_output: + if "Rebuild Status" in line: + extra_info = line + message += 'Array "%s" is in state ' % shortname + if extra_info: + message += '"%s" (%s) - %s' \ + % (state, raidlevel, extra_info) + + else: + message += '"%s" (%s)' % (state, raidlevel) + message += ", " + + if status == OK: + status = OK + + + elif "clean, degraded, recovering" in state: + extra_info = None + for line in detailed_output: + if "Rebuild Status" in line: + extra_info = line + message += 'Array "%s" is in state ' % shortname + if extra_info: + message += '"%s" (%s) - %s' \ + % (state, raidlevel, extra_info) + + else: + message += '"%s" (%s)' % (state, raidlevel) + message += ", " + + if status == OK: + status = WARNING + + elif "clean, checking" in state: + extra_info = None + for line in detailed_output: + if "Rebuild Status" in line: + extra_info = line + message += 'Array "%s" is in state ' % shortname + if extra_info: + message += '"%s" (%s) - %s' \ + % (state, raidlevel, extra_info) + + else: + message += '"%s" (%s)' % (state, raidlevel) + message += ", " + + if status == OK: + status = WARNING + + elif "active, checking" in state: + extra_info = None + for line in detailed_output: + if "Rebuild Status" in line: + extra_info = line + message += 'Array "%s" is in state ' % shortname + if extra_info: + message += '"%s" (%s) - %s' \ + % (state, raidlevel, extra_info) + + else: + message += '"%s" (%s)' % (state, raidlevel) + message += ", " + + if status == OK: + status = WARNING + + + +# end + + elif state == "unknown": + message += 'State of Raid Array "%s" is unknown, ' % shortname + if state == OK: + status = UNKNOWN + else: + message += 'Array %s is in state "%s" (%s), ' \ + % (shortname, state, raidlevel) + status = CRITICAL + + message = message.rstrip(", ") + + if status == OK: + message += "All arrays OK" + else: + if arrays_not_ok == 1: + message = "1 array not ok - " + message + else: + message = "%s arrays not ok - " % arrays_not_ok + message + + if number_arrays == 1: + message += " [1 array checked]" + else: + message += " [%s arrays checked]" % number_arrays + + return status, message + + +def main(): + """parses args and calls func to test MD arrays""" + + parser = OptionParser() + + parser.add_option( "-v", + "--verbose", + action="count", + dest="verbosity", + default=0, + help="Verbose mode. Good for testing plugin. By default\ + only one result line is printed as per Nagios standards") + + parser.add_option( "-V", + "--version", + action="store_true", + dest="version", + help="Print version number and exit") + + (options, args) = parser.parse_args() + + if args: + parser.print_help() + sys.exit(UNKNOWN) + + verbosity = options.verbosity + version = options.version + + if version: + print(__version__) + sys.exit(OK) + + result, message = test_raid(verbosity) + + end(result, message) + + +if __name__ == "__main__": + main() diff --git a/bin/monitoring/nagios/check_mem.sh b/bin/monitoring/nagios/check_mem.sh new file mode 100755 index 0000000..e893ec9 --- /dev/null +++ b/bin/monitoring/nagios/check_mem.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +if [ "$1" = "-w" ] && [ "$2" -gt "0" ] && [ "$3" = "-c" ] && [ "$4" -gt "0" ]; then + FreeM=`free -m |grep Mem` + memTotal_m=`echo "$FreeM" |awk '{print $2}'` + memUsed_m=`echo "$FreeM" |awk '{print $3}'` + memFree_m=`echo "$FreeM" |awk '{print $4}'` + if free -m | grep -q available + then + memBuffer_cache_m=`echo "$FreeM" |awk '{print $6}'` + memAvailable_m=`echo "$FreeM" |awk '{print $7}'` + else + memBuffer_cache_m=$(( `echo "$FreeM" |awk '{print $6}'` + `echo "$FreeM" |awk '{print $7}'` )) + memAvailable_m=$(($memFree_m+$memBuffer_cache_m)) + fi + + memUsed_m=$(($memTotal_m-$memAvailable_m)) + + memUsedPrc=`echo $((($memUsed_m*100)/$memTotal_m))||cut -d. -f1` + if [ "$memUsedPrc" -ge "$4" ]; then + echo "Memory: CRITICAL Total: $memTotal_m MB - Used: $memUsed_m MB - $memUsedPrc% used!|TOTAL=$memTotal_m;;;; USED=$memUsed_m;;;; BUFFER/CACHE=$memBuffer_cache_m;;;; AVAILABLE=$memAvailable_m;;;;" + exit 2 + elif [ "$memUsedPrc" -ge "$2" ]; then + echo "Memory: WARNING Total: $memTotal_m MB - Used: $memUsed_m MB - $memUsedPrc% used!|TOTAL=$memTotal_m;;;; USED=$memUsed_m;;;; BUFFER/CACHE=$memBuffer_cache_m;;;; AVAILABLE=$memAvailable_m;;;;" + exit 1 + else + echo "Memory: OK Total: $memTotal_m MB - Used: $memUsed_m MB - $memUsedPrc% used|TOTAL=$memTotal_m;;;; USED=$memUsed_m;;;; BUFFER/CACHE=$memBuffer_cache_m;;;; AVAILABLE=$memAvailable_m;;;;" + exit 0 + fi +else # If inputs are not as expected, print help. + sName="`echo $0|awk -F '/' '{print $NF}'`" + echo -e "\n\n\t\t### $sName Version 2.1###\n" + echo -e "# Usage:\t$sName -w -c " + echo -e "\t\t= warnlevel and critlevel is percentage value without %\n" + echo "# EXAMPLE:\t/usr/lib64/nagios/plugins/$sName -w 80 -c 90" + echo -e "\nCopyright (C) 2012 Lukasz Gogolin (lukasz.gogolin@gmail.com), improved by Nestor 2015\n\n" + exit +fi diff --git a/bin/monitoring/nagios/check_smartdisk b/bin/monitoring/nagios/check_smartdisk new file mode 100755 index 0000000..98f019c --- /dev/null +++ b/bin/monitoring/nagios/check_smartdisk @@ -0,0 +1,122 @@ +#!/bin/bash +# man smartctl for the return codes definitions +# By Gary GABRIEL. garyg@pilotsystems.net +# 2012-10-29 +#encoding: utf-8 + +STATUSOK="0" +WARNINGS="1" +CRITICAL="2" + +CRITFLAG="0" +WARNFLAG="0" + +SMARTCTL="/usr/sbin/smartctl" + +if [ ! -x "$SMARTCTL" ] +then + echo "$SMARTCTL not found or not executable. Please fix it." + exit $WARNINGS +fi + +# Maximum temperature in degrees celcius +HOSTNAME=$(hostname) +case $HOSTNAME in + *blue) + MAXDEG=60;; + *) + MAXDEG=40;; +esac +CURDEG=0 + +for DISK in `cat /proc/partitions |awk '{print $4}'|grep -E "sd[a-z]$"|sort -u` +do +# echo "Polling /dev/$DISK" + STATUS=`/usr/bin/sudo $SMARTCTL -a "/dev/$DISK" -s on` + RETVAL="$?" + + CMDLINE="Please run \"sudo $SMARTCTL -a /dev/$DISK\" on $HOSTNAME." + + # Parse output for SATA drives + CURDEG=`echo "$STATUS" | grep "194 Temperature_Celsius" | awk '{print $10}'` + if [ -z "$CURDEG" ] + then + # Parse output for SCSI drives + CURDEG=`echo "$STATUS" | grep "Current Drive Temperature" | awk '{print $4}'` + fi + + # Get sure the temperature is a figure + if ! [[ "$CURDEG" =~ ^[0-9]+$ ]] ; then + # Well, some disks aren't smart-capable, let's ignore them + continue + WARNLOGS="/dev/$DISK: Could not read current temperature; $WARNLOGS" + + WARNFLAG="1" + else + if [ "$CURDEG" -ge "$MAXDEG" ] + then + WARNLOGS="/dev/$DISK: Temperature is above $MAXDEG; $CRITLOGS" + WARNFLAG="1" + fi + fi + + # Parse return code with bit masking + for ((i=0;i<8;i++)) + do + let "BIT=$RETVAL & 2**$i" + case $BIT in + 1) WARNLOGS="/dev/$DISK: Command line did not parse. $CMDLINE; $WARNLOGS" + WARNFLAG="1" + ;; + + 2) WARNLOGS="/dev/$DISK: Device open failed, device did not return an IDENTIFY DEVICE structure, or device is in a low-power mode. $CMDLINE; $WARNLOGS" + WARNFLAG="1" + ;; + + # 4) WARNLOGS="/dev/$DISK: Some SMART or other ATA command to the disk failed, or there was a checksum error in a SMART data structure. $CMDLINE; $WARNLOGS" + # WARNFLAG="1" + # ;; + + 8) CRITLOGS="/dev/$DISK: SMART status check returned \"DISK FAILING\". $CMDLINE; $CRITLOGS" + CRITFLAG="1" + ;; + + 16) WARNLOGS="/dev/$DISK: We found prefail Attributes <= threshold. $CMDLINE; $WARNLOGS" + WARNFLAG="1" + ;; + + # 32) WARNLOGS="/dev/$DISK: SMART status check returned DISK OK but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past. $CMDLINE; $WARNLOGS" + # WARNFLAG="1" + # ;; + + # 64) WARNLOGS="/dev/$DISK: The device error log contains records of errors. $CMDLINE; $CRITLOGS" + # WARNFLAG="1" + # ;; + + 128) WARNLOGS="/dev/$DISK: The device self-test log contains records of errors. [ATA only] Failed self-tests outdated by a newer successful extended self-test are ignored. $CMDLINE; $CRITLOGS" + WARNFLAG="1" + ;; + *) + ;; + esac + done +done + +# Critical has precedence over warning +if [ "$CRITFLAG" -eq "1" ] +then + echo "$CRITLOGS" + exit $CRITICAL +fi + +# If no critical alerts, show warnings +if [ "$WARNFLAG" -eq "1" ] +then + echo "$WARNLOGS" + exit $WARNINGS +fi + +# else, everything is fine +echo "Everything is OK" +exit $STATUSOK + diff --git a/bin/monitoring/nagios/check_ssl b/bin/monitoring/nagios/check_ssl new file mode 100755 index 0000000..786a0d5 --- /dev/null +++ b/bin/monitoring/nagios/check_ssl @@ -0,0 +1,24 @@ +#!/bin/sh + +set -e + +HOST="$1" +PORT="$2" +IP="$3" + +if [ -z "$IP" ] +then + IP="$HOST" +fi + +/usr/lib/nagios/plugins/check_http -H "$HOST" -S -C 28 -p "$PORT" --sni -I "$IP" + +ISSUER="$(/usr/bin/openssl s_client -showcerts -servername "$HOST" -connect "$IP":"$PORT" /dev/null | grep issuer)" + +if echo "$ISSUER" | grep -q GeoTrust +then + echo "Certificate signed by $ISSUER, will expire on July 20th" + exit 1 +fi + +echo "Issuer : $ISSUER" diff --git a/bin/monitoring/nagios/check_telecaster.py b/bin/monitoring/nagios/check_telecaster.py new file mode 100755 index 0000000..8da6ede --- /dev/null +++ b/bin/monitoring/nagios/check_telecaster.py @@ -0,0 +1,104 @@ +#!/usr/bin/python3 + +import os, sys, psutil, time + + +class TelecasterCheck: + """Nagios compatible Telecaster server check""" + + record_paths = ['/home/telecaster/trash', '/home/telecaster/monitor'] + formats = ['mp3', 'webm'] + daemons = [ + {'proc': 'pipewire', 'args': ''}, + {'proc': 'Xtigervnc', 'args': ''}, + {'proc': 'gst-launch-1.0', 'args': 'lamemp3enc'}, + {'proc': 'gst-launch-1.0', 'args': 'vp8enc'}, + {'proc': 'deefuzzer', 'args': 'mp3'}, + {'proc': 'deefuzzer', 'args': 'webm'}, + ] + + log_path = '/var/log/telecaster/' + + OK_STATE = 0 + WARNING_STATE = 1 + CRITICAL_STATE = 2 + TIME_SLEEP = 1 + + def __init__(self): + self.message = "" + self.is_up = True + self.is_writing = True + + def get_pid(self, name, args=None): + """Get a process pid filtered by arguments and uid""" + for proc in psutil.process_iter(): + if proc.cmdline(): + if name == proc.name(): + if args: + #print(proc.cmdline()) + if args in proc.cmdline()[1:] or args in ' '.join(proc.cmdline()[1:]) : + return proc.pid + else: + return proc.pid + return None + + def get_dir_size(self, path='.'): + """https://note.nkmk.me/en/python-os-path-getsize/""" + total = 0 + with os.scandir(path) as it: + for entry in it: + if entry.is_file(): + total += entry.stat().st_size + elif entry.is_dir(): + total += self.get_dir_size(entry.path) + return total + + def check_daemons(self): + for daemon in self.daemons: + if not self.get_pid(daemon['proc'], args=daemon['args']): + self.is_up = False + self.message += daemon['proc'] + " " + daemon['args'] + " is OFF" + " - " + else: + self.message += daemon['proc'] + " " + daemon['args'] + " is ON" + " - " + + def check_writing(self): + for record_path in self.record_paths: + if os.path.exists(record_path): + for format in self.formats: + size = self.get_dir_size(record_path + os.sep + format) + log = self.log_path + os.sep + format + '.log' + if not os.path.exists(log): + f = open(log, 'w') + f.write(str(size)) + f.close() + else: + f = open(log) + previous_size = f.read() + f.close() + if previous_size: + previous_size = int(previous_size) + if size == previous_size: + if self.is_up: + time.sleep(self.TIME_SLEEP) + self.is_writing = False + self.message += format + " writing is OFF - " + else: + self.is_writing = True + self.message += format + " writing is ON - " + f = open(log, 'w') + f.write(str(size)) + f.close() + + def run(self): + self.check_daemons() + self.check_writing() + print(self.message) + if not self.is_up or not self.is_writing: + sys.exit(self.CRITICAL_STATE) + else: + sys.exit(self.OK_STATE) + + +if __name__ == "__main__": + check = TelecasterCheck() + check.run() -- 2.39.5