many things
This commit is contained in:
1 parent
0dbf023957
commit
bd55a215f3
2 files changed
+106
-92
No files matched your search
+21
-21
@@ -1,3 +1,24 @@
|
|||||||
|
[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, set to -1 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
|
||||||
|
|
||||||
|
[email]
|
||||||
|
; when to send an email, comma-separated list of [success, error]
|
||||||
|
sendon = success,error
|
||||||
|
subject = [SnapRAID] Status Report:
|
||||||
|
from =
|
||||||
|
to =
|
||||||
|
|
||||||
[smtp]
|
[smtp]
|
||||||
host =
|
host =
|
||||||
; leave empty for default port
|
; leave empty for default port
|
||||||
@@ -7,27 +28,6 @@ ssl = false
|
|||||||
user =
|
user =
|
||||||
password =
|
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
|
; maybe some smartctrl options
|
||||||
@@ -1,20 +1,16 @@
|
|||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf8 -*-
|
||||||
import ConfigParser
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import ConfigParser
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import sys
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
from collections import Counter
|
from collections import Counter, defaultdict
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
|
||||||
# TODO: check config validity
|
|
||||||
# TODO: alles in main und exceptions handlen
|
|
||||||
# finish() darf keine exceptions werfen!
|
|
||||||
|
|
||||||
# Global variables
|
# Global variables
|
||||||
config = None
|
config = None
|
||||||
email_log = None
|
email_log = None
|
||||||
@@ -22,20 +18,20 @@ email_log = None
|
|||||||
|
|
||||||
def tee_log(infile, out_lines, log_level):
|
def tee_log(infile, out_lines, log_level):
|
||||||
def tee_thread():
|
def tee_thread():
|
||||||
for line in iter(infile.readline, ''):
|
for line in iter(infile.readline, ""):
|
||||||
logging.log(log_level, line.strip())
|
logging.log(log_level, line.strip())
|
||||||
out_lines.append(line)
|
out_lines.append(line)
|
||||||
infile.close()
|
infile.close()
|
||||||
t = threading.Thread(target=tee_thread)
|
t = threading.Thread(target=tee_thread)
|
||||||
#t.daemon = True
|
t.daemon = True
|
||||||
t.start()
|
t.start()
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
|
||||||
def snapraid_command(command):
|
def snapraid_command(command):
|
||||||
p = subprocess.Popen(
|
p = subprocess.Popen(
|
||||||
[config.get("snapraid", "executable"), command,
|
[config["snapraid"]["executable"], command,
|
||||||
"--conf", config.get("snapraid", "config")],
|
"--conf", config["snapraid"]["config"]],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
out = []
|
out = []
|
||||||
@@ -56,56 +52,64 @@ def send_email(success):
|
|||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email import charset
|
from email import charset
|
||||||
# use quoted-printable instead of the default base64
|
# use quoted-printable instead of the default base64
|
||||||
charset.add_charset('utf-8', charset.SHORTEST, charset.QP)
|
charset.add_charset("utf-8", charset.SHORTEST, charset.QP)
|
||||||
if success:
|
if success:
|
||||||
body = "SnapRAID job completed successfully:\n\n\n"
|
body = "SnapRAID job completed successfully:\n\n\n"
|
||||||
else:
|
else:
|
||||||
body = "Error during SnapRAID job:\n\n\n"
|
body = "Error during SnapRAID job:\n\n\n"
|
||||||
body += email_log.getvalue()
|
body += email_log.getvalue()
|
||||||
msg = MIMEText(body, "plain", "utf-8")
|
msg = MIMEText(body, "plain", "utf-8")
|
||||||
msg['Subject'] = config.get("email", "subject") + \
|
msg["Subject"] = config["email"]["subject"] + \
|
||||||
" SUCCESS" if success else " ERROR"
|
(" SUCCESS" if success else " ERROR")
|
||||||
msg['From'] = config.get("email", "from")
|
msg["From"] = config["email"]["from"]
|
||||||
msg['To'] = config.get("email", "to")
|
msg["To"] = config["email"]["to"]
|
||||||
smtp = {"host": config.get("smtp", "host")}
|
smtp = {"host": config["smtp"]["host"]}
|
||||||
if config.get("smtp", "port"):
|
if config["smtp"]["port"]:
|
||||||
smtp["port"] = config.getint("smtp", "port")
|
smtp["port"] = config["smtp"]["port"]
|
||||||
if config.get("smtp", "ssl").lower() == "true":
|
if config["smtp"]["ssl"]:
|
||||||
server = smtplib.SMTP_SSL(**smtp)
|
server = smtplib.SMTP_SSL(**smtp)
|
||||||
else:
|
else:
|
||||||
server = smtplib.SMTP(**smtp)
|
server = smtplib.SMTP(**smtp)
|
||||||
if config.get("smtp", "user"):
|
if config["smtp"]["user"]:
|
||||||
server.login(config.get("smtp", "user"),
|
server.login(config["smtp"]["user"], config["smtp"]["password"])
|
||||||
config.get("smtp", "password"))
|
|
||||||
server.sendmail(
|
server.sendmail(
|
||||||
config.get("email", "from"),
|
config["email"]["from"],
|
||||||
[config.get("email", "to")],
|
[config["email"]["to"]],
|
||||||
msg.as_string())
|
msg.as_string())
|
||||||
server.quit
|
server.quit()
|
||||||
|
|
||||||
|
|
||||||
def finish(is_success):
|
def finish(is_success):
|
||||||
|
if ("error", "success")[is_success] in config["email"]["sendon"]:
|
||||||
|
try:
|
||||||
|
send_email(is_success)
|
||||||
|
except:
|
||||||
|
logging.exception("Failed to send email")
|
||||||
if is_success:
|
if is_success:
|
||||||
logging.info("Run finished successfully")
|
logging.info("Run finished successfully")
|
||||||
else:
|
else:
|
||||||
logging.error("Run failed")
|
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)
|
sys.exit(0 if is_success else 1)
|
||||||
|
|
||||||
|
|
||||||
def load_config(file):
|
def load_config(file):
|
||||||
global config
|
global config
|
||||||
config = ConfigParser.RawConfigParser(allow_no_value=True)
|
parser = ConfigParser.RawConfigParser()
|
||||||
config.add_section("smtp")
|
parser.read(file)
|
||||||
config.add_section("email")
|
sections = ["snapraid", "logging", "email", "smtp"]
|
||||||
config.add_section("snapraid")
|
config = dict((x, defaultdict(lambda: "")) for x in sections)
|
||||||
config.set("snapraid", "delethreshold", 0)
|
for section in parser.sections():
|
||||||
config.add_section("logging")
|
for (k, v) in parser.items(section):
|
||||||
config.set("logging", "file", None)
|
config[section][k] = v.strip()
|
||||||
config.set("logging", "maxsize", 0)
|
|
||||||
config.read(file)
|
intvals = [("snapraid", "deletethreshold"), ("logging", "maxsize")]
|
||||||
|
for section, option in intvals:
|
||||||
|
try:
|
||||||
|
config[section][option] = int(config[section][option])
|
||||||
|
except ValueError:
|
||||||
|
config[section][option] = 0
|
||||||
|
|
||||||
|
config["smtp"]["ssl"] = (config["smtp"]["ssl"].lower() == "true")
|
||||||
|
|
||||||
|
|
||||||
def setup_logger():
|
def setup_logger():
|
||||||
@@ -121,16 +125,16 @@ def setup_logger():
|
|||||||
console_logger.setFormatter(log_format)
|
console_logger.setFormatter(log_format)
|
||||||
root_logger.addHandler(console_logger)
|
root_logger.addHandler(console_logger)
|
||||||
|
|
||||||
if config.get("logging", "file"):
|
if config["logging"]["file"]:
|
||||||
max_log_size = min(config.getint("logging", "maxsize"), 0) * 1024
|
max_log_size = min(config["logging"]["maxsize"], 0) * 1024
|
||||||
file_logger = logging.handlers.RotatingFileHandler(
|
file_logger = logging.handlers.RotatingFileHandler(
|
||||||
config.get("logging", "file"),
|
config["logging"]["file"],
|
||||||
maxBytes=max_log_size,
|
maxBytes=max_log_size,
|
||||||
backupCount=9)
|
backupCount=9)
|
||||||
file_logger.setFormatter(log_format)
|
file_logger.setFormatter(log_format)
|
||||||
root_logger.addHandler(file_logger)
|
root_logger.addHandler(file_logger)
|
||||||
|
|
||||||
if config.get("email", "send"):
|
if config["email"]["sendon"]:
|
||||||
global email_log
|
global email_log
|
||||||
email_log = StringIO()
|
email_log = StringIO()
|
||||||
email_logger = logging.StreamHandler(email_log)
|
email_logger = logging.StreamHandler(email_log)
|
||||||
@@ -142,17 +146,46 @@ def setup_logger():
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('-c', '--conf', nargs=1,
|
parser.add_argument("-c", "--conf", nargs=1,
|
||||||
default='snapraid-runner.conf',
|
default="snapraid-runner.conf",
|
||||||
help='Configuration file (default %(default)s)')
|
help="Configuration file (default %(default)s)")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
load_config(args.conf)
|
|
||||||
setup_logger()
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
load_config(args.conf)
|
||||||
|
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:
|
||||||
|
run()
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Run failed due to unexpected exception:")
|
||||||
|
finish(False)
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
logging.info("=" * 60)
|
logging.info("=" * 60)
|
||||||
logging.info("Run started")
|
logging.info("Run started")
|
||||||
logging.info("=" * 60)
|
logging.info("=" * 60)
|
||||||
|
|
||||||
|
if not os.path.exists(config["snapraid"]["executable"]):
|
||||||
|
logging.error("Snapraid executable does not exist at " +
|
||||||
|
config["snapraid"]["executable"])
|
||||||
|
finish(False)
|
||||||
|
if not os.path.exists(config["snapraid"]["config"]):
|
||||||
|
logging.error("Snapraid config does not exist at " +
|
||||||
|
config["snapraid"]["config"])
|
||||||
|
finish(False)
|
||||||
|
|
||||||
logging.info("Running diff...")
|
logging.info("Running diff...")
|
||||||
try:
|
try:
|
||||||
diff_out = snapraid_command("diff")
|
diff_out = snapraid_command("diff")
|
||||||
@@ -165,12 +198,11 @@ def main():
|
|||||||
logging.info(("Diff results: {add} added, {remove} removed, "
|
logging.info(("Diff results: {add} added, {remove} removed, "
|
||||||
+ "{move} moved, {update} modified").format(**diff_results))
|
+ "{move} moved, {update} modified").format(**diff_results))
|
||||||
|
|
||||||
if (config.getint("snapraid", "deletethreshold") > 0 and
|
if (config["snapraid"]["deletethreshold"] >= 0 and
|
||||||
diff_results["remove"] >
|
diff_results["remove"] > config["snapraid"]["deletethreshold"]):
|
||||||
config.getint("snapraid", "deletethreshold")):
|
|
||||||
logging.error(
|
logging.error(
|
||||||
"Deleted files exceed delete threshold {}, aborting".format(
|
"Deleted files exceed delete threshold of {}, aborting".format(
|
||||||
config.getint("snapraid", "deletethreshold")))
|
config["snapraid"]["deletethreshold"]))
|
||||||
finish(False)
|
finish(False)
|
||||||
|
|
||||||
if (diff_results["remove"] + diff_results["add"] + diff_results["move"] +
|
if (diff_results["remove"] + diff_results["add"] + diff_results["move"] +
|
||||||
@@ -190,22 +222,4 @@ def main():
|
|||||||
finish(True)
|
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()
|
main()
|
||||||
except Exception as e:
|
|
||||||
logging.exception("Run failed due to unexpected exception:")
|
|
||||||
finish(False)
|
|
||||||
Reference in new issue
Block a user