src/untangle/untangle.py: use cleaner way of disabling verification.
[untangle-https-backup.git] / bin / untangle-https-backup
1 #!/usr/bin/python3
2 """
3 Back up Untangle configurations via the web admin UI.
4 """
5
6 from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
7 import configparser
8 from http.client import HTTPException
9 from os import chmod
10 from urllib.error import HTTPError, URLError
11 from socket import timeout
12 from sys import stderr
13
14 from untangle.untangle import Untangle
15
16 # Define a few exit codes.
17 EXIT_OK = 0
18 EXIT_BACKUPS_FAILED = 1
19
20 # Create an argument parser using our docsctring as its description.
21 parser = ArgumentParser(description = __doc__,
22 formatter_class = ArgumentDefaultsHelpFormatter)
23
24 parser.add_argument('-c',
25 '--config-file',
26 default='/etc/untangle-https-backup.ini',
27 help='path to configuration file')
28
29 args = parser.parse_args()
30
31 # Default to success, change it if anything fails.
32 status = EXIT_OK
33
34 # Parse the configuration file. In this contect "interpolation" is
35 # something completely berserk, and it breaks passwords containing '%'
36 # characters. So, we turn it off.
37 config = configparser.ConfigParser(interpolation=None)
38 config.read(args.config_file)
39
40 # And loop through each section.
41 for section in config.sections():
42 # For each section, we create an Untangle object based on that
43 # section's configuration.
44 u = Untangle(config[section])
45 try:
46 # And then try to log in and retrieve a backup.
47 u.login()
48 backup = u.get_backup()
49
50 # If that worked, we save the backup file and make it
51 # accessible only to its owner.
52 filename = u.name + '.backup'
53 with open(filename, 'wb') as f:
54 f.write(backup)
55 chmod(filename, 0o600)
56
57 # If it didn't work, but in a predictable way (some host is down),
58 # then we report that error and keep going.
59 except URLError as e:
60 tpl = '{:s}: {:s} from {:s}'
61 msg = tpl.format(u.name, str(e.reason), u.host)
62 print(msg, file=stderr)
63 status = EXIT_BACKUPS_FAILED
64 except HTTPError as e:
65 tpl = '{:s}: HTTP error {:s} from {:s}'
66 msg = tpl.format(u.name, str(e.code), u.host)
67 print(msg, file=stderr)
68 status = EXIT_BACKUPS_FAILED
69 except HTTPException as e:
70 # At least one sort of HTTPException (BadStatusLine) is not
71 # translated by urllib into an HTTPError, so we catch
72 # HTTPExceptions too.
73 tpl = '{:s}: HTTP exception {:s} from {:s}'
74 msg = tpl.format(u.name, repr(e), u.host)
75 print(msg, file=stderr)
76 status = EXIT_BACKUPS_FAILED
77 except timeout as e:
78 # A socket.timeout exception occurs when something goes over
79 # the configured "timeout" limit.
80 tpl = '{:s}: socket timeout ({:s}) from {:s}'
81 msg = tpl.format(u.name, str(e), u.host)
82 print(msg, file=stderr)
83 status = EXIT_BACKUPS_FAILED
84
85 exit(status)