#!/usr/bin/python3 """ Back up Untangle configurations via the web admin UI. """ from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser import configparser from http.client import HTTPException from os import chmod from urllib.error import HTTPError, URLError from socket import timeout from sys import stderr from untangle.untangle import Untangle # Define a few exit codes. EXIT_OK = 0 EXIT_BACKUPS_FAILED = 1 # Create an argument parser using our docsctring as its description. parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter) parser.add_argument('-c', '--config-file', default='/etc/untangle-https-backup.ini', help='path to configuration file') args = parser.parse_args() # Default to success, change it if anything fails. status = EXIT_OK # Parse the configuration file. In this contect "interpolation" is # something completely berserk, and it breaks passwords containing '%' # characters. So, we turn it off. config = configparser.ConfigParser(interpolation=None) config.read(args.config_file) # And loop through each section. for section in config.sections(): # For each section, we create an Untangle object based on that # section's configuration. u = Untangle(config[section]) try: # And then try to log in and retrieve a backup. u.login() backup = u.get_backup() # If that worked, we save the backup file and make it # accessible only to its owner. filename = u.name + '.backup' with open(filename, 'wb') as f: f.write(backup) chmod(filename, 0o600) # If it didn't work, but in a predictable way (some host is down), # then we report that error and keep going. except URLError as e: tpl = '{:s}: {:s} from {:s}' msg = tpl.format(u.name, str(e.reason), u.host) print(msg, file=stderr) status = EXIT_BACKUPS_FAILED except HTTPError as e: tpl = '{:s}: HTTP error {:s} from {:s}' msg = tpl.format(u.name, str(e.code), u.host) print(msg, file=stderr) status = EXIT_BACKUPS_FAILED except HTTPException as e: # At least one sort of HTTPException (BadStatusLine) is not # translated by urllib into an HTTPError, so we catch # HTTPExceptions too. tpl = '{:s}: HTTP exception {:s} from {:s}' msg = tpl.format(u.name, repr(e), u.host) print(msg, file=stderr) status = EXIT_BACKUPS_FAILED except timeout as e: # A socket.timeout exception occurs when something goes over # the configured "timeout" limit. tpl = '{:s}: socket timeout ({:s}) from {:s}' msg = tpl.format(u.name, str(e), u.host) print(msg, file=stderr) status = EXIT_BACKUPS_FAILED exit(status)