summaryrefslogtreecommitdiffstats
path: root/testing/mozharness/mozharness/mozilla/bouncer/submitter.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/mozharness/mozharness/mozilla/bouncer/submitter.py')
-rw-r--r--testing/mozharness/mozharness/mozilla/bouncer/submitter.py134
1 files changed, 134 insertions, 0 deletions
diff --git a/testing/mozharness/mozharness/mozilla/bouncer/submitter.py b/testing/mozharness/mozharness/mozilla/bouncer/submitter.py
new file mode 100644
index 0000000000..e9289d2be6
--- /dev/null
+++ b/testing/mozharness/mozharness/mozilla/bouncer/submitter.py
@@ -0,0 +1,134 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import base64
+import socket
+import sys
+import traceback
+from xml.dom.minidom import parseString
+
+from mozharness.base.log import FATAL
+
+try:
+ import httplib
+except ImportError:
+ import http.client as httplib
+try:
+ from urllib import quote, urlencode
+except ImportError:
+ from urllib.parse import quote, urlencode
+try:
+ from urllib2 import HTTPError, Request, URLError, urlopen
+except ImportError:
+ from urllib.request import HTTPError, Request, URLError, urlopen
+
+
+class BouncerSubmitterMixin(object):
+ def query_credentials(self):
+ if self.credentials:
+ return self.credentials
+ global_dict = {}
+ local_dict = {}
+ exec(
+ compile(
+ open(self.config["credentials_file"], "rb").read(),
+ self.config["credentials_file"],
+ "exec",
+ ),
+ global_dict,
+ local_dict,
+ )
+ self.credentials = (local_dict["tuxedoUsername"], local_dict["tuxedoPassword"])
+ return self.credentials
+
+ def api_call(self, route, data, error_level=FATAL, retry_config=None):
+ retry_args = dict(
+ failure_status=None,
+ retry_exceptions=(
+ HTTPError,
+ URLError,
+ httplib.BadStatusLine,
+ socket.timeout,
+ socket.error,
+ ),
+ error_message="call to %s failed" % (route),
+ error_level=error_level,
+ )
+
+ if retry_config:
+ retry_args.update(retry_config)
+
+ return self.retry(self._api_call, args=(route, data), **retry_args)
+
+ def _api_call(self, route, data):
+ api_prefix = self.config["bouncer-api-prefix"]
+ api_url = "%s/%s" % (api_prefix, route)
+ request = Request(api_url)
+ if data:
+ post_data = urlencode(data, doseq=True)
+ request.add_data(post_data)
+ self.info("POST data: %s" % post_data)
+ credentials = self.query_credentials()
+ if credentials:
+ auth = base64.encodestring("%s:%s" % credentials)
+ request.add_header("Authorization", "Basic %s" % auth.strip())
+ try:
+ self.info("Submitting to %s" % api_url)
+ res = urlopen(request, timeout=60).read()
+ self.info("Server response")
+ self.info(res)
+ return res
+ except HTTPError as e:
+ self.warning("Cannot access %s" % api_url)
+ traceback.print_exc(file=sys.stdout)
+ self.warning("Returned page source:")
+ self.warning(e.read())
+ raise
+ except URLError:
+ traceback.print_exc(file=sys.stdout)
+ self.warning("Cannot access %s" % api_url)
+ raise
+ except socket.timeout as e:
+ self.warning("Timed out accessing %s: %s" % (api_url, e))
+ raise
+ except socket.error as e:
+ self.warning("Socket error when accessing %s: %s" % (api_url, e))
+ raise
+ except httplib.BadStatusLine as e:
+ self.warning("BadStatusLine accessing %s: %s" % (api_url, e))
+ raise
+
+ def product_exists(self, product_name):
+ self.info("Checking if %s already exists" % product_name)
+ res = self.api_call("product_show?product=%s" % quote(product_name), data=None)
+ try:
+ xml = parseString(res)
+ # API returns <products/> if the product doesn't exist
+ products_found = len(xml.getElementsByTagName("product"))
+ self.info("Products found: %s" % products_found)
+ return bool(products_found)
+ except Exception as e:
+ self.warning("Error parsing XML: %s" % e)
+ self.warning("Assuming %s does not exist" % product_name)
+ # ignore XML parsing errors
+ return False
+
+ def api_add_product(self, product_name, add_locales, ssl_only=False):
+ data = {
+ "product": product_name,
+ }
+ if self.locales and add_locales:
+ data["languages"] = self.locales
+ if ssl_only:
+ # Send "true" as a string
+ data["ssl_only"] = "true"
+ self.api_call("product_add/", data)
+
+ def api_add_location(self, product_name, bouncer_platform, path):
+ data = {
+ "product": product_name,
+ "os": bouncer_platform,
+ "path": path,
+ }
+ self.api_call("location_add/", data)