self.host = s['host']
self.username = s.get('username', 'admin')
self.password = s['password']
- self.version = int(s.get('version', '12'))
+ self.timeout = s.get('timeout', 300)
self.base_url = 'https://' + self.host + '/' # This never changes
# Sanity check the numerical version.
- if self.version not in [9, 10, 11, 12]:
- msg = 'Invalid version "' + str(self.version) + '" '
+ self.version = s.get('version', '14')
+ if self.version not in ['9', '10', '11', '12', '13', '13.1', '14']:
+ msg = 'Invalid version "' + self.version + '" '
msg += 'in section "' + s.name + '"'
raise configparser.ParsingError(msg)
msg += 'in section "' + s.name + '"'
raise configparser.ParsingError(msg)
+ # Sanity check the integer "timeout" parameter. We want to
+ # bail if either the given parameter is not an integer, or if
+ # it's negative. To handle both at the same time, we try to
+ # parse an integer...
+ timeout = s.get('timeout', 300)
+ try:
+ self.timeout = int(timeout)
+ except:
+ # ...and set self.timeout to a negative value if we can't...
+ self.timeout = -1
+
+ # Now we check to see if the timeout value is negative. That
+ # will happen if it was either negative to begin with, or
+ # non-integer (and we set it negative).
+ if self.timeout < 0:
+ msg = 'Invalid value "' + timeout + '" for timeout '
+ 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
self.opener = urllib.request.build_opener(https_handler, cookie_proc)
+ def open(self, url, data=None):
+ """
+ A wrapper around ``self.opener.open()`` that uses our
+ configurable socket "timeout" value. Without the timeout
+ parameter, it seems we can wait forever in some corner cases.
+ """
+ return self.opener.open(url, data, self.timeout)
+
+
def login(self):
"""
Perform the HTTPS request to log in to the Untangle web admin
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)
+ self.open(url, post_data)
def get_backup(self):
Version-agnostic get-me-a-backup method. Dispatches to the
actual implementation based on ``self.version``.
"""
- if self.version == 9:
+ if self.version == '9':
return self.get_backup_v9()
- elif self.version in [10, 11, 12]:
- # The procedure for v11 or v12 is the same as for v10.
+ elif self.version in ['10', '11', '12', '13']:
+ # The procedure for v11, v12, or v13 is the same as for v10.
return self.get_backup_v10()
+ elif self.version in ['13.1', '14']:
+ # But the minor update v13.1 moved the backup URL.
+ return self.get_backup_v13_1()
+ else
+ raise ValueError('unknown version %s' % self.version)
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)
+ self.open(url, post_data)
url = self.base_url + 'webui/backup?action=initiateDownload'
- with self.opener.open(url) as response:
+ with self.open(url) as response:
return response.read()
url = self.base_url + '/webui/download'
post_vars = {'type': 'backup'}
post_data = urllib.parse.urlencode(post_vars).encode('ascii')
- with self.opener.open(url, post_data) as response:
+ with self.open(url, post_data) as response:
+ return response.read()
+
+
+ def get_backup_v13_1(self):
+ """
+ Retrieve a backup from Untangle version 13.1. This
+ differs from v13 (and v12, and v11,...) by only one word
+ in the URL: "webui" becomes "admin".
+
+ Returns the binary HTTPS response (i.e. the file).
+ """
+ url = self.base_url + '/admin/download'
+ post_vars = {'type': 'backup'}
+ post_data = urllib.parse.urlencode(post_vars).encode('ascii')
+ with self.open(url, post_data) as response:
return response.read()