def get_exception_from_xml_status(xml): # type: (Union[xml_util.XML, str]) -> Optional[owsexceptions.OWSException] """ Retrieves the :term:`OWS` exception that corresponds to the :term:`XML` status. Expects the following :term:`XML` status response structure (``ows:Exception`` block can be at any level): .. code-block:: xml <ows:Exception exceptionCode="NoApplicableCode" locator="None"> <ows:ExceptionText>Error message about the cause of the exception.</ows:ExceptionText> </ows:Exception> :param xml: XML tree object with exception details. :return: Matched :class:`owsexceptions.OWSException`. If no matching exception code is found within available exception classes, defaults to generic ``OWSException``. If any parsing error occurs, returns nothing. """ try: if isinstance(xml, (str, bytes)): xml = xml_util.fromstring(bytes2str(xml)) if not isinstance(xml, xml_util.XML): return None # Exception blocks can be with or without 'ows' prefix depending on which default namespace was defined ows_exc_xml = xml.find( "Exception", namespaces=xml.nsmap) # type: Optional[xml_util.XML] if ows_exc_xml is None: ows_exc_xml = xml.xpath( "//ows:Exception", namespaces=xml.nsmap)[0] # type: Optional[xml_util.XML] ows_exc_txt = ows_exc_xml.find( "ExceptionText", namespaces=xml.nsmap) # type: Optional[xml_util.XML] if ows_exc_txt is None: ows_exc_txt = ows_exc_xml.xpath("//ows:ExceptionText", namespaces=xml.nsmap)[0] ows_exc_msg = ows_exc_txt.text ows_exc_loc = ows_exc_xml.attrib.get( "locator") or ows_exc_xml.attrib.get( "locater") # some WPS have typo ows_exc_code = ows_exc_xml.attrib["exceptionCode"] for ows_exc_name in dir(owsexceptions): ows_exc_cls = getattr(owsexceptions, ows_exc_name) if (inspect.isclass(ows_exc_cls) and issubclass(ows_exc_cls, owsexceptions.OWSException) and ows_exc_cls is not owsexceptions.OWSException and ows_exc_code == ows_exc_cls.code): return ows_exc_cls(ows_exc_msg, code=ows_exc_code, locator=ows_exc_loc) return owsexceptions.OWSException(ows_exc_msg, code=ows_exc_code, locator=ows_exc_loc) except Exception as exc: LOGGER.error("Failed mapping of OWS Exception from error codes.", exc_info=exc) return None
def encrypt_email(email, settings): if not email or not isinstance(email, str): raise TypeError(f"Invalid email: {email!s}") LOGGER.debug("Job email setup.") try: salt = str2bytes(settings.get("weaver.wps_email_encrypt_salt")) email = str2bytes(email) rounds = int(settings.get("weaver.wps_email_encrypt_rounds", 100000)) derived_key = hashlib.pbkdf2_hmac("sha256", email, salt, rounds) return bytes2str(binascii.hexlify(derived_key)) except Exception as ex: LOGGER.debug("Job email setup failed [%r].", ex) raise ValueError( "Cannot register job, server not properly configured for notification email." )
def test_bytes2str(): assert utils.bytes2str(b"test-bytes") == u"test-bytes" assert utils.bytes2str(u"test-unicode") == u"test-unicode"
def monitor(self, monitor_reference): # type: (JobExecution) -> bool execution = monitor_reference["execution"] max_retries = 20 # using 'wait_secs' incremental delays, this is ~3min of retry attempts num_retries = 0 run_step = 0 job_id = "<undefined>" log_progress = Wps1RemoteJobProgress.MONITOR while execution.isNotComplete() or run_step == 0: if num_retries >= max_retries: raise Exception( f"Could not read status document after {max_retries} retries. Giving up." ) try: execution = check_wps_status(location=execution.statusLocation, sleep_secs=wait_secs(run_step), settings=self.settings) monitor_reference[ "execution"] = execution # update reference for later stages job_id = execution.statusLocation.split("/")[-1].replace( ".xml", "") exec_status = map_status(execution.getStatus()) LOGGER.debug( get_log_monitor_msg(job_id, exec_status, execution.percentCompleted, execution.statusMessage, execution.statusLocation)) log_msg = get_job_log_msg(status=exec_status, message=execution.statusMessage, progress=execution.percentCompleted, duration=None) # get if available log_progress = map_progress(execution.percentCompleted, Wps1RemoteJobProgress.MONITOR, Wps1RemoteJobProgress.RESULTS) self.update_status(log_msg, log_progress, Status.RUNNING) except Exception as exc: num_retries += 1 LOGGER.debug("Exception raised: %r", exc) sleep(1) else: num_retries = 0 run_step += 1 if not execution.isSucceded(): exec_msg = execution.statusMessage or "Job failed." exec_status = map_status(execution.getStatus()) exec_status_url = execution.statusLocation LOGGER.debug( get_log_monitor_msg(job_id, exec_status, execution.percentCompleted, exec_msg, exec_status_url)) # provide more details in logs of parent job process about the cause of the failing remote execution xml_err = bytes2str(xml_util.tostring(execution.response)) xml_exc = get_exception_from_xml_status(execution.response) self.update_status( f"Retrieved error status response from WPS remote provider on [{exec_status_url}]:\n{xml_err}\n", log_progress, Status.FAILED, error=xml_exc) return False return True