Example #1
0
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
Example #2
0
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."
        )
Example #3
0
def test_bytes2str():
    assert utils.bytes2str(b"test-bytes") == u"test-bytes"
    assert utils.bytes2str(u"test-unicode") == u"test-unicode"
Example #4
0
    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