diff options
Diffstat (limited to 'jobs')
-rwxr-xr-x | jobs/EmailChecker.py | 46 | ||||
-rwxr-xr-x | jobs/HTTPServerChecker.py | 36 | ||||
-rwxr-xr-x | jobs/JobBase.py | 53 | ||||
-rwxr-xr-x | jobs/JobSpawner.py | 5 | ||||
-rwxr-xr-x | jobs/PeerChecker.py | 39 | ||||
-rwxr-xr-x | jobs/TCPServerChecker.py | 41 | ||||
-rwxr-xr-x | jobs/__init__.py | 86 |
7 files changed, 306 insertions, 0 deletions
diff --git a/jobs/EmailChecker.py b/jobs/EmailChecker.py new file mode 100755 index 0000000..51992bf --- /dev/null +++ b/jobs/EmailChecker.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +import os +import base64 +import datetime + +import imaplib + +import JobBase + +class EmailChecker(JobBase.JobBase): + def executeEvery(self): + return JobBase.JobFrequency.HOUR + def execute(self): + USER = self.config.get('email', 'user') + PASS = self.config.get('email', 'pass') + + #Generate a random subject + subj = base64.b64encode(os.urandom(20)) + + if not self.sendEmail(subj, "", USER): + return False + + M = imaplib.IMAP4_SSL(self.config.get('email', 'imapserver')) + M.login(USER, PASS) + + #If we have set up a filter to auto-delete messages from ourself + if self.config.get('email', 'ideletesentmessagesautomatically'): + M.select("[Gmail]/Trash") + + criteria = '(FROM "'+USER+'" SINCE "'+datetime.date.today().strftime("%d-%b-%Y")+'")' + typ, data = M.search(None, criteria) + + foundSubject = False + for num in data[0].split(): + typ, data = M.fetch(num, '(BODY.PEEK[HEADER.FIELDS (Subject)])') + if subj in data[0][1]: + foundSubject = True + M.close() + M.logout() + if not foundSubject: + #This may not work, but try anyway + self.sendEmail("Email Fetch Failure", "Body") + return False + else: + return True
\ No newline at end of file diff --git a/jobs/HTTPServerChecker.py b/jobs/HTTPServerChecker.py new file mode 100755 index 0000000..ec8eda1 --- /dev/null +++ b/jobs/HTTPServerChecker.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python
+
+import logging
+import requests
+
+import JobBase
+import JobSpawner
+
+class HTTPServerChecker(JobSpawner.JobSpawner):
+ servers = [
+ #("http://example.com", JobBase.JobFrequency.MINUTE),
+ #("https://exampletwo.com", JobBase.JobFrequency.MINUTE)
+ ]
+
+ class ServerChecker(JobBase.JobBase):
+ def __init__(self, url, frequency):
+ self.url = url
+ self.frequency = frequency
+
+ def getName(self):
+ return str(self.__class__) + " for " + self.url
+ def executeEvery(self):
+ return self.frequency
+ def execute(self):
+ try:
+ requests.get(self.url)
+ return True
+ except:
+ msg = "Could not hit server " + self.url
+ logging.warn(msg)
+ return self.sendEmail(msg, "")
+
+ def get_sub_jobs(self):
+ for s in self.servers:
+ yield self.ServerChecker(s[0], s[1])
+
diff --git a/jobs/JobBase.py b/jobs/JobBase.py new file mode 100755 index 0000000..330b6a9 --- /dev/null +++ b/jobs/JobBase.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import random +import logging + +import smtplib + +class JobFrequency: + MINUTE = "minute" + HOUR = "hour" + +class JobBase: + def __init__(self): + self.config = None + def getName(self): + return str(self.__class__) + def shouldExecute(self, cronmode): + frequency = self.executeEvery() + if cronmode == frequency: + return True + return False + def setConfig(self, config): + self.config = config + + def sendEmail(self, subject, body, to=""): + return sendEmail(self.config, subject, body, to) + + def executeEvery(self): + pass + def execute(self): + pass + +def sendEmail(config, subject, body, to=""): + FROM = config.get('email', 'user') + PASS = config.get('email', 'pass') + if not to: + to = config.get('alertcontact', 'default') + + # Prepare actual message + # Avoid gmail threading + subject = subject + " " + str(random.random()) + message = """\From: %s\nTo: %s\nSubject: %s\n\n%s""" \ + % (FROM, ", ".join(to), subject, body) + try: + server = smtplib.SMTP(config.get('email', 'smtpserver'), config.get('email', 'smtpport')) + server.ehlo() + server.starttls() + server.login(FROM, PASS) + server.sendmail(FROM, to, message) + server.close() + return True + except: + return False
\ No newline at end of file diff --git a/jobs/JobSpawner.py b/jobs/JobSpawner.py new file mode 100755 index 0000000..3d09693 --- /dev/null +++ b/jobs/JobSpawner.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python
+
+class JobSpawner:
+ def get_sub_jobs(self):
+ pass
diff --git a/jobs/PeerChecker.py b/jobs/PeerChecker.py new file mode 100755 index 0000000..c8cca38 --- /dev/null +++ b/jobs/PeerChecker.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python
+
+import os
+import base64
+import datetime
+
+import imaplib
+
+import JobBase
+
+class PeerChecker(JobBase.JobBase):
+ def executeEvery(self):
+ return JobBase.JobFrequency.HOUR
+ def execute(self):
+ testSuccess = True
+ peers = self.config.items('peers')
+ for p in peers:
+ peer = p[1].split(',')
+ peerOK = False
+
+ try:
+ response = requests.get(peer[0])
+ if response.status_code != 200:
+ peerOK = False
+ subject = peer[0] + " returned a non-standard status code."
+ else:
+ if "True" in response.content:
+ peerOK = True
+ elif "False" in response.content:
+ peerOK = False
+ subject = peer[0] + " reports it cannot send email."
+ except:
+ peerOK = False
+ subject = peer[0] + " is not responding."
+
+ if not peerOK:
+ if not self.sendEmail(subject, "", peer[1]):
+ testSuccess = False
+ return testSuccess
\ No newline at end of file diff --git a/jobs/TCPServerChecker.py b/jobs/TCPServerChecker.py new file mode 100755 index 0000000..711047b --- /dev/null +++ b/jobs/TCPServerChecker.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python
+
+import os
+import socket
+import logging
+
+import JobBase
+import JobSpawner
+
+class TCPServerChecker(JobSpawner.JobSpawner):
+ servers = [
+ #("example.com", 53, "example.com:tcpdns", JobBase.JobFrequency.MINUTE),
+ ]
+
+ class ServerChecker(JobBase.JobBase):
+ def __init__(self, ip, port, friendlyName, frequency):
+ self.ip = ip
+ self.port = port
+ self.friendlyName = friendlyName + "(" + self.ip + ":" + str(self.port) + ")"
+ self.frequency = frequency
+
+ def getName(self):
+ return str(self.__class__) + " for " + self.friendlyName
+ def executeEvery(self):
+ return self.frequency
+ def execute(self):
+ try:
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((self.ip, self.port))
+ s.close()
+ return True
+ except:
+ msg = "Could not hit server " + self.friendlyName
+ logging.warn(msg)
+ return self.sendEmail(msg, "")
+
+ def get_sub_jobs(self):
+ for s in self.servers:
+ yield self.ServerChecker(s[0], s[1], s[2], s[3])
+
+
diff --git a/jobs/__init__.py b/jobs/__init__.py new file mode 100755 index 0000000..9955164 --- /dev/null +++ b/jobs/__init__.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python + +import os +import sys +import inspect +import logging +from imp import load_module, find_module +import importlib + +import jobs +import jobs.JobBase +import jobs.JobSpawner + +class JobFinder: + def __init__(self, config): + """ + Opens the jobs folder and looks at every .py module in that directory. + Finds available jobs by looking at any class defined in those modules + that implements the JobBase abstract class. + Returns a list of job classes. + """ + self._jobs = set([]) + self.config = config + + job_modules = self.get_job_modules_dynamic() + + for module in job_modules: + # Check every declaration in that module + for name in dir(module): + obj = getattr(module, name) + if name not in module.__name__: + # Jobs have to have the same class name as their module name + # This prevents Job B from being detected twice when there is a Job A that imports Job B + continue + + if inspect.isclass(obj): + # A class declaration was found in that module + # Checking if it's a subclass of JobBase + # Discarding JobBase as a subclass of JobBase + if obj != jobs.JobBase.JobBase and obj != jobs.JobSpawner.JobSpawner: + logging.info("Found " + str(obj)) + for base in obj.__bases__: + # H4ck because issubclass() doesn't seem to work as expected on Linux + # It has to do with JobBase being imported multiple times (within jobs) or something + if base.__name__ == 'JobBase': + # A job was found, keep it + self._jobs.add(obj()) + elif base.__name__ == 'JobSpawner': + spawner = obj() + for j in spawner.get_sub_jobs(): + self._jobs.add(j) + + + def get_job_modules_dynamic(self): + job_modules = [] + + job_dir = jobs.__path__[0] + full_job_dir = os.path.join(sys.path[0], job_dir) + if os.path.exists(full_job_dir): + for (root, dirs, files) in os.walk(full_job_dir): + del dirs[:] # Do not walk into subfolders of the job directory + # Checking every .py module in the job directory + jobs_loaded = [] + for source in (s for s in files if s.endswith((".py"))): + module_name = os.path.splitext(os.path.basename(source))[0] + if module_name in jobs_loaded: + continue + jobs_loaded.append(module_name) + full_name = os.path.splitext(source)[0].replace(os.path.sep,'.') + + try: # Try to import the job package + # The job package HAS to be imported as a submodule + # of module 'jobs' or it will break windows compatibility + (file, pathname, description) = \ + find_module(full_name, jobs.__path__) + module = load_module('jobs.' + full_name, file, + pathname, description) + except Exception as e: + logging.critical('Import Error on ' + module_name + ': ' + str(e)) + jobs.JobBase.sendEmail(self.config, 'Import Error on ' + module_name, str(e)) + continue + job_modules.append(module) + return job_modules + + def get_jobs(self): + return self._jobs
\ No newline at end of file |