aboutsummaryrefslogtreecommitdiff
path: root/jobs
diff options
context:
space:
mode:
Diffstat (limited to 'jobs')
-rwxr-xr-xjobs/EmailChecker.py46
-rwxr-xr-xjobs/HTTPServerChecker.py36
-rwxr-xr-xjobs/JobBase.py53
-rwxr-xr-xjobs/JobSpawner.py5
-rwxr-xr-xjobs/PeerChecker.py39
-rwxr-xr-xjobs/TCPServerChecker.py41
-rwxr-xr-xjobs/__init__.py86
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