initial commit
This commit is contained in:
commit
0dbf023957
2 files changed
+244
No files matched your search
@@ -0,0 +1,33 @@
|
||||
[smtp]
|
||||
host =
|
||||
; leave empty for default port
|
||||
port =
|
||||
; set to "true" to activate
|
||||
ssl = false
|
||||
user =
|
||||
password =
|
||||
|
||||
[email]
|
||||
; when to send an email, comma-separated list of [success, error]
|
||||
send = success,error
|
||||
subject = [SnapRAID] Status Report:
|
||||
from =
|
||||
to =
|
||||
|
||||
[snapraid]
|
||||
; path to the snapraid executable
|
||||
executable =
|
||||
; path to the snapraid config to be used
|
||||
config = snapraid.conf
|
||||
; abort operation if there are more deletes than this, leave empty to disable
|
||||
deletethreshold = 40
|
||||
|
||||
[logging]
|
||||
; logfile to write to, leave empty to disable
|
||||
file = snapraid.log
|
||||
; maximum logfile size in KiB, leave empty for infinite
|
||||
maxsize = 5000
|
||||
|
||||
|
||||
|
||||
; maybe some smartctrl options
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
# -*- coding: utf8 -*-
|
||||
import ConfigParser
|
||||
import argparse
|
||||
import logging
|
||||
import logging.handlers
|
||||
import sys
|
||||
import subprocess
|
||||
import threading
|
||||
import traceback
|
||||
from collections import Counter
|
||||
from cStringIO import StringIO
|
||||
|
||||
|
||||
# TODO: check config validity
|
||||
# TODO: alles in main und exceptions handlen
|
||||
# finish() darf keine exceptions werfen!
|
||||
|
||||
# Global variables
|
||||
config = None
|
||||
email_log = None
|
||||
|
||||
|
||||
def tee_log(infile, out_lines, log_level):
|
||||
def tee_thread():
|
||||
for line in iter(infile.readline, ''):
|
||||
logging.log(log_level, line.strip())
|
||||
out_lines.append(line)
|
||||
infile.close()
|
||||
t = threading.Thread(target=tee_thread)
|
||||
#t.daemon = True
|
||||
t.start()
|
||||
return t
|
||||
|
||||
|
||||
def snapraid_command(command):
|
||||
p = subprocess.Popen(
|
||||
[config.get("snapraid", "executable"), command,
|
||||
"--conf", config.get("snapraid", "config")],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
out = []
|
||||
threads = [
|
||||
tee_log(p.stdout, out, logging.OUTPUT),
|
||||
tee_log(p.stderr, [], logging.OUTERR)]
|
||||
for t in threads:
|
||||
t.join()
|
||||
ret = p.wait()
|
||||
if ret == 0:
|
||||
return out
|
||||
else:
|
||||
raise subprocess.CalledProcessError(ret, "snapraid " + command)
|
||||
|
||||
|
||||
def send_email(success):
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email import charset
|
||||
# use quoted-printable instead of the default base64
|
||||
charset.add_charset('utf-8', charset.SHORTEST, charset.QP)
|
||||
if success:
|
||||
body = "SnapRAID job completed successfully:\n\n\n"
|
||||
else:
|
||||
body = "Error during SnapRAID job:\n\n\n"
|
||||
body += email_log.getvalue()
|
||||
msg = MIMEText(body, "plain", "utf-8")
|
||||
msg['Subject'] = config.get("email", "subject") + \
|
||||
" SUCCESS" if success else " ERROR"
|
||||
msg['From'] = config.get("email", "from")
|
||||
msg['To'] = config.get("email", "to")
|
||||
smtp = {"host": config.get("smtp", "host")}
|
||||
if config.get("smtp", "port"):
|
||||
smtp["port"] = config.getint("smtp", "port")
|
||||
if config.get("smtp", "ssl").lower() == "true":
|
||||
server = smtplib.SMTP_SSL(**smtp)
|
||||
else:
|
||||
server = smtplib.SMTP(**smtp)
|
||||
if config.get("smtp", "user"):
|
||||
server.login(config.get("smtp", "user"),
|
||||
config.get("smtp", "password"))
|
||||
server.sendmail(
|
||||
config.get("email", "from"),
|
||||
[config.get("email", "to")],
|
||||
msg.as_string())
|
||||
server.quit
|
||||
|
||||
|
||||
def finish(is_success):
|
||||
if is_success:
|
||||
logging.info("Run finished successfully")
|
||||
else:
|
||||
logging.error("Run failed")
|
||||
if ((is_success and "success" in config.get("email", "send")) or
|
||||
(not is_success and "error" in config.get("email", "send"))):
|
||||
send_email(is_success)
|
||||
sys.exit(0 if is_success else 1)
|
||||
|
||||
|
||||
def load_config(file):
|
||||
global config
|
||||
config = ConfigParser.RawConfigParser(allow_no_value=True)
|
||||
config.add_section("smtp")
|
||||
config.add_section("email")
|
||||
config.add_section("snapraid")
|
||||
config.set("snapraid", "delethreshold", 0)
|
||||
config.add_section("logging")
|
||||
config.set("logging", "file", None)
|
||||
config.set("logging", "maxsize", 0)
|
||||
config.read(file)
|
||||
|
||||
|
||||
def setup_logger():
|
||||
log_format = logging.Formatter(
|
||||
"%(asctime)s [%(levelname)-6.6s] %(message)s")
|
||||
root_logger = logging.getLogger()
|
||||
logging.OUTPUT = 15
|
||||
logging.addLevelName(logging.OUTPUT, "OUTPUT")
|
||||
logging.OUTERR = 25
|
||||
logging.addLevelName(logging.OUTERR, "OUTERR")
|
||||
root_logger.setLevel(logging.OUTPUT)
|
||||
console_logger = logging.StreamHandler(sys.stdout)
|
||||
console_logger.setFormatter(log_format)
|
||||
root_logger.addHandler(console_logger)
|
||||
|
||||
if config.get("logging", "file"):
|
||||
max_log_size = min(config.getint("logging", "maxsize"), 0) * 1024
|
||||
file_logger = logging.handlers.RotatingFileHandler(
|
||||
config.get("logging", "file"),
|
||||
maxBytes=max_log_size,
|
||||
backupCount=9)
|
||||
file_logger.setFormatter(log_format)
|
||||
root_logger.addHandler(file_logger)
|
||||
|
||||
if config.get("email", "send"):
|
||||
global email_log
|
||||
email_log = StringIO()
|
||||
email_logger = logging.StreamHandler(email_log)
|
||||
email_logger.setFormatter(log_format)
|
||||
# Don't send programm stdout in email
|
||||
email_logger.setLevel(logging.INFO)
|
||||
root_logger.addHandler(email_logger)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-c', '--conf', nargs=1,
|
||||
default='snapraid-runner.conf',
|
||||
help='Configuration file (default %(default)s)')
|
||||
args = parser.parse_args()
|
||||
load_config(args.conf)
|
||||
setup_logger()
|
||||
|
||||
logging.info("=" * 60)
|
||||
logging.info("Run started")
|
||||
logging.info("=" * 60)
|
||||
|
||||
logging.info("Running diff...")
|
||||
try:
|
||||
diff_out = snapraid_command("diff")
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.error(e)
|
||||
finish(False)
|
||||
logging.info("*" * 60)
|
||||
|
||||
diff_results = Counter(line.split(" ")[0] for line in diff_out)
|
||||
logging.info(("Diff results: {add} added, {remove} removed, "
|
||||
+ "{move} moved, {update} modified").format(**diff_results))
|
||||
|
||||
if (config.getint("snapraid", "deletethreshold") > 0 and
|
||||
diff_results["remove"] >
|
||||
config.getint("snapraid", "deletethreshold")):
|
||||
logging.error(
|
||||
"Deleted files exceed delete threshold {}, aborting".format(
|
||||
config.getint("snapraid", "deletethreshold")))
|
||||
finish(False)
|
||||
|
||||
if (diff_results["remove"] + diff_results["add"] + diff_results["move"] +
|
||||
diff_results["update"] == 0):
|
||||
logging.info("No changes detected, no sync required")
|
||||
finish(True)
|
||||
|
||||
logging.info("Running sync...")
|
||||
try:
|
||||
snapraid_command("sync")
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.error(e)
|
||||
finish(False)
|
||||
logging.info("*" * 60)
|
||||
|
||||
logging.info("All done")
|
||||
finish(True)
|
||||
|
||||
|
||||
try:
|
||||
load_config()
|
||||
except:
|
||||
print("unexpected exception while loading config")
|
||||
print traceback.format_exc()
|
||||
sys.exit(2)
|
||||
|
||||
try:
|
||||
setup_logger()
|
||||
except:
|
||||
print("unexpected exception while setting up logging")
|
||||
print traceback.format_exc()
|
||||
sys.exit(2)
|
||||
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
logging.exception("Run failed due to unexpected exception:")
|
||||
finish(False)
|
||||
Reference in new issue
Block a user