]> gitweb.michael.orlitzky.com - untangle-https-backup.git/commitdiff
Rename the executable, and implement a bunch of missing stuff.
authorMichael Orlitzky <michael@orlitzky.com>
Fri, 1 Apr 2016 14:23:49 +0000 (10:23 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Fri, 1 Apr 2016 14:23:49 +0000 (10:23 -0400)
This adds chmod of the backups, default options, SSL verification, and
cleans up some of the errors. It also supports command-line parsing
and a user-specified configuration file.

bin/untangle-https-backup [new file with mode: 0755]
src/untangle-https-backup.py [deleted file]

diff --git a/bin/untangle-https-backup b/bin/untangle-https-backup
new file mode 100755 (executable)
index 0000000..669c282
--- /dev/null
@@ -0,0 +1,146 @@
+#!/usr/bin/python3
+"""
+Back up Untangle configurations over HTTPS.
+"""
+
+from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
+import configparser
+import http.cookiejar
+from os import chmod
+import ssl
+from sys import stderr
+import urllib.parse
+import urllib.request
+
+
+# Define a few exit codes.
+EXIT_OK = 0
+EXIT_BACKUPS_FAILED = 1
+
+
+class Untangle:
+
+    def __init__(self, s):
+        """
+        Initialize this Untangle object with a ConfigParser section.
+        """
+        self.name = s.name
+        self.host = s['host']
+        self.username = s.get('username', 'admin')
+        self.password = s['password']
+        self.version = int(s.get('version', '11'))
+        self.base_url = 'https://' + self.host + '/' # This never changes
+
+        # Sanity check the numerical version.
+        if self.version not in [9, 11]:
+            msg =  'Invalid version "' + str(self.version) + '" '
+            msg += 'in section "' + s.name + '"'
+            raise configparser.ParsingError(msg)
+
+        # Sanity check the boolean verify_cert parameter.
+        vc = s.get('verify_cert', 'False')
+        if vc == 'True':
+            self.verify_cert = True
+        elif vc == 'False':
+            self.verify_cert = False
+        else:
+            msg =  'Invalid value "' + vc + '" for verify_cert '
+            msg += 'in section "' + s.name + '"'
+            raise configparser.ParsingError(msg)
+
+        #
+        # Finally, create a URL opener to make HTTPS requests.
+        #
+        # First, create a cookie jar that we'll attach to our URL
+        # opener thingy.
+        cj = http.cookiejar.CookieJar()
+        cookie_proc = urllib.request.HTTPCookieProcessor(cj)
+
+        # SSL mumbo jumbo to make it ignore the certificate's hostname
+        # when verify_cert = False.
+        if self.verify_cert:
+            ssl_ctx = ssl.create_default_context()
+        else:
+            ssl_ctx = ssl._create_unverified_context()
+
+        https_handler = urllib.request.HTTPSHandler(context=ssl_ctx)
+
+        # Now Create a URL opener, and tell it to use our cookie jar
+        # and SSL context. We keep this around for future requests.
+        self.opener = urllib.request.build_opener(https_handler, cookie_proc)
+
+
+    def login(self):
+        login_path = 'auth/login?url=/setup/welcome.do&realm=Administrator'
+        url = self.base_url + login_path
+        post_vars = {'username': self.username, 'password': self.password }
+        post_data = urllib.parse.urlencode(post_vars).encode('ascii')
+        self.opener.open(url, post_data)
+
+
+    def get_backup(self):
+        if self.version == 9:
+            return self.get_backup_v9()
+        elif self.version == 11:
+            return self.get_backup_v11()
+
+
+    def get_backup_v9(self):
+        url = self.base_url + '/webui/backup'
+        post_vars = {'action': 'requestBackup'}
+        post_data = urllib.parse.urlencode(post_vars).encode('ascii')
+        self.opener.open(url, post_data)
+
+        url = self.base_url + 'webui/backup?action=initiateDownload'
+        with self.opener.open(url) as response:
+            return response.read()
+
+
+    def get_backup_v11(self):
+        url = self.base_url + '/webui/download?type=backup'
+        post_vars = {'type': 'backup'}
+        post_data = urllib.parse.urlencode(post_vars).encode('ascii')
+        with self.opener.open(url, post_data) as response:
+            return response.read()
+
+
+
+# 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
+
+config = configparser.ConfigParser()
+config.read(args.config_file)
+
+for section in config.sections():
+    untangle = Untangle(config[section])
+    try:
+        untangle.login()
+        backup = untangle.get_backup()
+        filename = untangle.name + '.backup'
+        with open(filename, 'wb') as f:
+            f.write(backup)
+        chmod(filename, 0o600)
+
+    except urllib.error.URLError as e:
+        msg =  untangle.name + ': ' + str(e.reason)
+        msg += ' from ' + untangle.host
+        print(msg, file=stderr)
+        status = EXIT_BACKUPS_FAILED
+    except urllib.error.HTTPError as e:
+        msg =  untangle.name + ': ' + 'HTTP error ' + str(e.code)
+        msg += ' from ' + untangle.host
+        print(msg, file=stderr)
+        status = EXIT_BACKUPS_FAILED
+
+exit(status)
diff --git a/src/untangle-https-backup.py b/src/untangle-https-backup.py
deleted file mode 100755 (executable)
index 285c790..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/python3
-#
-# Back up customer Untangle boxes over HTTPS.
-#
-
-import configparser
-import http.cookiejar
-import ssl
-import sys
-import urllib.parse
-import urllib.request
-
-
-class Untangle:
-
-    def __init__(self, s):
-        """
-        Initialize this Untangle object with a ConfigParser section.
-        """
-        self.name = s.name
-        self.host = s['host']
-        self.username = s['username']
-        self.password = s['password']
-        self.version = int(s['version'])
-
-        # Create an opener object that we'll use to make HTTP requests.
-        cj = http.cookiejar.CookieJar()
-
-        # SSL mumbo jumbo to make it ignore the certificate's hostname.
-        ssl_ctx = ssl._create_unverified_context()
-        https_handler = urllib.request.HTTPSHandler(context=ssl_ctx)
-
-        # Tell it to use our cookie jar.
-        cookie_proc = urllib.request.HTTPCookieProcessor(cj)
-        self.opener = urllib.request.build_opener(https_handler, cookie_proc)
-
-        # Also set the base URL which will never change.
-        self.base_url = 'https://' + self.host + '/'
-
-
-    def login(self):
-        login_path = 'auth/login?url=/setup/welcome.do&realm=Administrator'
-        url = self.base_url + login_path
-        post_vars = {'username': self.username, 'password': self.password }
-        post_data = urllib.parse.urlencode(post_vars).encode('ascii')
-        self.opener.open(url, post_data)
-
-
-    def get_backup(self):
-        if self.version == 9:
-            return self.get_backup_v9()
-        elif self.version == 11:
-            return self.get_backup_v11()
-
-
-    def get_backup_v9(self):
-        url = self.base_url + '/webui/backup'
-        post_vars = {'action': 'requestBackup'}
-        post_data = urllib.parse.urlencode(post_vars).encode('ascii')
-        self.opener.open(url, post_data)
-
-        url = self.base_url + 'webui/backup?action=initiateDownload'
-        with self.opener.open(url) as response:
-            return response.read()
-
-
-    def get_backup_v11(self):
-        url = self.base_url + '/webui/download?type=backup'
-        post_vars = {'type': 'backup'}
-        post_data = urllib.parse.urlencode(post_vars).encode('ascii')
-        with self.opener.open(url, post_data) as response:
-            return response.read()
-
-
-
-config = configparser.ConfigParser()
-config.read('untangle-backup.ini')
-
-for section in config.sections():
-    untangle = Untangle(config[section])
-    try:
-        untangle.login()
-        backup = untangle.get_backup()
-        filename = untangle.name + '.backup'
-        with open(filename, 'wb') as f:
-            f.write(backup)
-    except urllib.error.URLError as e:
-        msg = 'Connection error (' + str(e.reason) + ')'
-        msg += ' from ' + untangle.host + '.'
-        print(msg, file=sys.stderr)
-    except urllib.error.HTTPError as e:
-        msg = 'HTTP error ' + str(e.code) + ' from ' + untangle.host + '.'
-        print(msg, file=sys.stderr)