Commit bce8206f authored by Colomban Wendling's avatar Colomban Wendling

Make config set options inside the lib module

Instead of depending on config.py defining several magic variables,
move the default configuration in the config instance at the root of
the lib module, and make config.py override them as needed.
parent 9e384f72
from lib.checks import *
from lib import config
# This is the base granularity (in seconds) for polling
# Each check may then individually be configured to run every N * tick
base_tick = 60
config.base_tick = 60
# Email addresses to send to when an alert is triggered
emails = ['john@localhost']
config.emails.to.append('john@localhost')
# Subject template for state change email notifications
# available substitutions:
# - state ("Problem" or "OK")
# - check (check's name, like "CheckDNSRec6")
# - dest (the target of the check ie. an IP or a Host's 'name' parameter)
subject_tpl = "[ARN] {state}: {check} on {dest}"
config.emails.subject_tpl = "[ARN] {state}: {check} on {dest}"
mail = Host(ipv4='127.0.0.1', ipv6='::1', name='LXC mail')
......@@ -21,11 +22,10 @@ web = Host(ipv4='127.0.0.0', ipv6='::42', name='Bad IPs')
alsace = Host(ipv4='127.0.0.1', ipv6='::1')
recursif = Host(ipv4='89.234.141.66', ipv6='2a00:5881:8100:1000::31', name='DNS récursif')
checks = Checks()
checks.add(CheckDNSZone, ["arn-fai.net", "netlib.re"], ip_version=4)
checks.add(CheckPing4, [mail, web], retry=2)
checks.add(CheckPing6, [mail, web], retry=2)
checks.add(CheckDNSRec4, [recursif])
checks.add(CheckDNSRec6, [recursif])
# checks.add(CheckSMTP4, [mail, alsace])
# checks.add(CheckSMTP6, [mail, alsace])
config.checks.add(CheckDNSZone, ["arn-fai.net", "netlib.re"], ip_version=4)
config.checks.add(CheckPing4, [mail, web], retry=2)
config.checks.add(CheckPing6, [mail, web], retry=2)
config.checks.add(CheckDNSRec4, [recursif])
config.checks.add(CheckDNSRec6, [recursif])
# config.checks.add(CheckSMTP4, [mail, alsace])
# config.checks.add(CheckSMTP6, [mail, alsace])
from .attrtree import AttrTree
from .checks import Checks
config = AttrTree()
# the list of checks
config.install_attr('checks', Checks())
# This is the base granularity (in seconds) for polling
# Each check may then individually be configured to run every N * tick
config.install_attr('base_tick', 60)
# Email addresses to send to when an alert is triggered
config.install_attr('emails.to', [])
# Subject template for state change email notifications
# available substitutions:
# - state ("Problem" or "OK")
# - check (check's name, like "CheckDNSRec6")
# - dest (the target of the check ie. an IP or a Host's 'name' parameter)
config.install_attr('emails.subject_tpl', '[DOMAIN] {state}: {check} on {dest}')
class AttrTree(object):
""" A class holding attributes/items, but not allowing to create
new ones implicitely. Use .install_attr() instead. """
def __init__(self):
object.__setattr__(self, '_attrs', {})
def install_attr(self, key, default):
if key in self._attrs:
raise KeyError('Key "%s" already exists' % key)
stems = key.split('.', 2)
if len(stems) < 2:
self._attrs[key] = default
elif stems[0] in self._attrs:
self._attrs[stems[0]].install_attr(stems[1], default)
else:
sub = AttrTree()
sub.install_attr(stems[1], default)
self._attrs[stems[0]] = sub
def __getitem__(self, key):
return self._attrs[key]
def __setitem__(self, key, value):
if not key in self._attrs:
raise KeyError('Key "%s" does not exist' % key)
elif isinstance(self._attrs[key], AttrTree):
raise KeyError('Key "%s" is not settable' % key)
self._attrs[key] = value
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
......@@ -10,11 +10,11 @@ import email.charset
email.charset.add_charset('utf-8', email.charset.QP, email.charset.QP, 'utf-8')
def send_email_for_check(check):
from config import emails, subject_tpl
from . import config
addr_from = "Picomon <picomon@%s>" % socket.getfqdn()
# ensure we do not traceback with unknown substitutions
subject = subject_tpl.format_map(
subject = config.emails.subject_tpl.format_map(
defaultdict(lambda: "<no substitution>",
state='OK' if check.ok else 'Problem',
check=check.__class__.__name__,
......@@ -30,12 +30,12 @@ def send_email_for_check(check):
msg = MIMEText(msg_text.encode('utf-8').decode('latin1'), 'plain', 'utf-8')
msg['Subject'] = subject
msg['From'] = addr_from
msg['To'] = ", ".join(emails)
msg['To'] = ", ".join(config.emails.to)
try:
server = smtplib.SMTP('localhost')
# server.set_debuglevel(1)
server.sendmail(addr_from, emails, msg.as_string())
server.sendmail(addr_from, config.emails.to, msg.as_string())
server.quit()
except Exception as e:
print("Couldn't send email: %s" % str(e), file=stderr)
import concurrent.futures
from config import *
import signal
import argparse
from time import sleep
import config as user_config
from lib import config
def usr1_handler(signum, frame):
print ("""Signal SIGUSR1 caught, printing state of checks.
Checks in error:""")
for check in checks:
for check in config.checks:
if not check.ok:
print ('-+' * 40)
print ("Check %s is in error state:\n\t%s" % (check,
......@@ -17,7 +18,7 @@ def usr1_handler(signum, frame):
print ('-+' * 40, """
Other checks (usually OK but may be in retry mode):""")
for check in checks:
for check in config.checks:
if check.ok:
print ("Check %s is %s" % (check,
"OK" if check.retry_count == 0 else "retrying"))
......@@ -41,7 +42,7 @@ if __name__ == '__main__':
if args.one:
futures = []
for check in checks:
for check in config.checks:
futures.append(executor.submit(runner, check))
for future in concurrent.futures.as_completed(futures):
......@@ -54,6 +55,6 @@ if __name__ == '__main__':
else:
# This will drift slowly as it takes (base_tick + espilon) seconds
while True:
for check in checks:
for check in config.checks:
executor.submit(check.run())
sleep(base_tick)
sleep(config.base_tick)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment