Ejemplo n.º 1
0
def test_get_wps_client_headers_preserved():
    """
    Validate that original request headers are not modified following WPS client sub-requests.
    """
    test_wps_url = "http://dont-care.com/wps"
    test_headers = {
        "Content-Type": CONTENT_TYPE_APP_XML,
        "Content-Length": "0",
        "Accept-Language": ACCEPT_LANGUAGE_FR_CA,
        "Accept": CONTENT_TYPE_APP_JSON,
        "Authorization": "Bearer: FAKE",  # nosec
    }
    test_copy_headers = copy.deepcopy(test_headers)
    # following are removed for sub-request
    test_wps_headers = {
        "Accept-Language": ACCEPT_LANGUAGE_FR_CA,
        "Authorization": "Bearer: FAKE",  # nosec
    }

    with contextlib.ExitStack() as stack:
        patches = mocked_remote_wps([], [ACCEPT_LANGUAGE_FR_CA])
        mocks = []
        for patch in patches:
            mocks.append(stack.enter_context(patch))

        wps = get_wps_client(test_wps_url, headers=test_headers)

    for mocked in mocks:
        assert mocked.called
    assert test_headers == test_copy_headers, "Input headers must be unmodified after WPS client call"
    assert wps.headers == test_wps_headers, "Only allowed headers should have been passed down to WPS client"
    assert wps.language == ACCEPT_LANGUAGE_FR_CA, "Language should have been passed down to WPS client from header"
    assert wps.url == test_wps_url
Ejemplo n.º 2
0
def describe_provider_process(request):
    # type: (Request) -> Process
    """
    Obtains a remote service process description in a compatible local process format.

    Note: this processes won't be stored to the local process storage.
    """
    provider_id = request.matchdict.get("provider_id")
    process_id = request.matchdict.get("process_id")
    store = get_db(request).get_store(StoreServices)
    service = store.fetch_by_name(provider_id)
    # FIXME: support other providers (https://github.com/crim-ca/weaver/issues/130)
    wps = get_wps_client(service.url, request)
    process = wps.describeprocess(process_id)
    return Process.convert(process, service, get_settings(request))
Ejemplo n.º 3
0
def fetch_wps_process(job, wps_url, headers, settings):
    """
    Retrieves the WPS process description from the local or remote WPS reference URL.
    """
    try:
        wps = get_wps_client(wps_url, settings, headers=headers, language=job.accept_language)
        raise_on_xml_exception(wps._capabilities)  # noqa
    except Exception as ex:
        job.save_log(errors=ex, message="Failed WPS client creation for process [{!s}]".format(job.process))
        raise OWSNoApplicableCode("Failed to retrieve WPS capabilities. Error: [{}].".format(str(ex)))
    try:
        wps_process = wps.describeprocess(job.process)
    except Exception as ex:
        raise OWSNoApplicableCode("Failed to retrieve WPS process description. Error: [{}].".format(str(ex)))
    return wps_process
Ejemplo n.º 4
0
 def prepare(self):
     LOGGER.debug("Execute WPS-1 provider: [%s]", self.provider)
     LOGGER.debug("Execute WPS-1 process: [%s]", self.process)
     try:
         self.wps_provider = get_wps_client(self.provider,
                                            headers=self.cookies)
         raise_on_xml_exception(
             self.wps_provider._capabilities)  # noqa: W0212
     except Exception as ex:
         raise OWSNoApplicableCode(
             "Failed to retrieve WPS capabilities. Error: [{}].".format(
                 str(ex)))
     try:
         self.wps_process = self.wps_provider.describeprocess(self.process)
     except Exception as ex:
         raise OWSNoApplicableCode(
             "Failed to retrieve WPS process description. Error: [{}].".
             format(str(ex)))
Ejemplo n.º 5
0
 def prepare(self):
     LOGGER.debug("Execute WPS-1 provider: [%s]", self.provider)
     LOGGER.debug("Execute WPS-1 process: [%s]", self.process)
     try:
         headers = {}
         headers.update(self.get_auth_cookies())
         headers.update(self.get_auth_headers())
         self.wps_provider = get_wps_client(self.provider, headers=headers)
         raise_on_xml_exception(
             self.wps_provider._capabilities)  # noqa: W0212
     except Exception as ex:
         raise OWSNoApplicableCode(
             f"Failed to retrieve WPS capabilities. Error: [{ex!s}].")
     try:
         self.wps_process = self.wps_provider.describeprocess(self.process)
     except Exception as ex:
         raise OWSNoApplicableCode(
             f"Failed to retrieve WPS process description. Error: [{ex!s}]."
         )
Ejemplo n.º 6
0
def fetch_wps_process(job, wps_url, headers, settings):
    # type: (Job, str, HeadersType, SettingsType) -> ProcessOWS
    """
    Retrieves the WPS process description from the local or remote WPS reference URL.
    """
    try:
        wps = get_wps_client(wps_url,
                             settings,
                             headers=headers,
                             language=job.accept_language)
        raise_on_xml_exception(wps._capabilities)  # noqa
    except Exception as ex:
        job.save_log(
            errors=ex,
            message=f"Failed WPS client creation for process [{job.process!s}]"
        )
        raise OWSNoApplicableCode(
            f"Failed to retrieve WPS capabilities. Error: [{ex!s}].")
    try:
        wps_process = wps.describeprocess(job.process)
    except Exception as ex:  # pragma: no cover
        raise OWSNoApplicableCode(
            f"Failed to retrieve WPS process description. Error: [{ex!s}].")
    return wps_process
Ejemplo n.º 7
0
def register_wps_processes_dynamic(service_name, service_url,
                                   service_visibility, container):
    # type: (str, str, bool, AnySettingsContainer) -> None
    """
    Register a WPS service ``provider`` such that ``processes`` under it are dynamically accessible on demand.

    The registered `WPS-1` provider generates a **dynamic** reference to processes under it. Only the :term:`Provider`
    reference itself is actually registered. No :term:`Process` are directly registered following this operation.

    When information about the offered processes, descriptions of those processes or their execution are requested,
    `Weaver` will query the referenced :term:`Provider` for details and convert the corresponding :term:`Process`
    dynamically. This means that latest metadata of the :term:`Process`, and any modification to it on the remote
    service will be immediately reflected on `Weaver` without any need to re-deploy processes.

    Each of the deployed processes using *dynamic* reference will be accessible under `Weaver` endpoints::

        /providers/<service-name>/processes/<process-id>

    The processes are **NOT** deployed locally since the processes are retrieved from the :term:`Provider` itself.

    .. seealso::
        - :func:`register_wps_processes_static`

    :param service_url: WPS-1 service location (where ``GetCapabilities`` and ``DescribeProcess`` requests can be made).
    :param service_name: Identifier to employ for registering the provider identifier.
    :param service_visibility: Visibility flag of the provider.
    :param container: settings to retrieve required configuration settings.
    """
    db = get_db(container)
    service_store = db.get_store(StoreServices)  # type: StoreServices

    LOGGER.info("Register WPS-1/2 provider: [%s]", service_url)
    try:
        get_wps_client(service_url,
                       container)  # only attempt fetch to validate it exists
    except Exception as ex:
        LOGGER.exception(
            "Exception during provider validation: [%s] [%r]. Skipping...",
            service_name, ex)
        return
    new_service = Service(name=service_name,
                          url=service_url,
                          public=service_visibility)
    try:
        old_service = service_store.fetch_by_name(service_name)
    except ServiceNotFound:
        LOGGER.info("Registering new provider: [%s]...", service_name)
    else:
        if new_service == old_service:
            LOGGER.warning("Provider already registered: [%s]. Skipping...",
                           service_name)
            return
        LOGGER.warning(
            "Provider matches registered service: [%s]. Updating details...",
            service_name)
    try:
        service_store.save_service(new_service, overwrite=True)
    except Exception as ex:
        LOGGER.exception(
            "Exception during provider registration: [%s] [%r]. Skipping...",
            service_name, ex)
Ejemplo n.º 8
0
def register_wps_processes_static(service_url, service_name,
                                  service_visibility, service_processes,
                                  container):
    # type: (str, str, bool, List[str], AnySettingsContainer) -> None
    """
    Register WPS-1 :term:`Process` under a service :term:`Provider` as static references.

    For a given WPS provider endpoint, either iterates over all available processes under it to register them one
    by one, or limit itself only to those of the reduced set specified by :paramref:`service_processes`.

    The registered `WPS-1` processes generate a **static** reference, meaning that metadata of each process as well
    as any other modifications to the real remote reference will not be tracked, including validation of even their
    actual existence, or modifications to inputs/outputs. The :term:`Application Package` will only point to it
    assuming it remains valid.

    Each of the deployed processes using *static* reference will be accessible directly under `Weaver` endpoints::

        /processes/<service-name>_<process-id>

    The service is **NOT** deployed as :term:`Provider` since the processes are registered directly.

    .. seealso::
        - :func:`register_wps_processes_dynamic`

    :param service_url: WPS-1 service location (where ``GetCapabilities`` and ``DescribeProcess`` requests can be made).
    :param service_name: Identifier to employ for generating the full process identifier.
    :param service_visibility: Visibility flag of the provider.
    :param service_processes: process IDs under the service to be registered, or all if empty.
    :param container: settings to retrieve required configuration settings.
    """
    db = get_db(container)
    process_store = db.get_store(StoreProcesses)  # type: StoreProcesses

    LOGGER.info("Fetching WPS-1: [%s]", service_url)
    wps = get_wps_client(service_url, container)
    if LooseVersion(wps.version) >= LooseVersion("2.0"):
        LOGGER.warning("Invalid WPS-1 provider, version was [%s]", wps.version)
        return
    wps_processes = [wps.describeprocess(p)
                     for p in service_processes] or wps.processes
    for wps_process in wps_processes:
        proc_id = "{}_{}".format(service_name,
                                 get_sane_name(wps_process.identifier))
        proc_url = "{}?service=WPS&request=DescribeProcess&identifier={}&version={}".format(
            service_url, wps_process.identifier, wps.version)
        svc_vis = VISIBILITY_PUBLIC if service_visibility else VISIBILITY_PRIVATE
        try:
            old_process = process_store.fetch_by_id(proc_id)
        except ProcessNotFound:
            pass
        else:
            if (old_process.id == proc_id
                    and old_process.processDescriptionURL == proc_url
                    and old_process.visibility == svc_vis):
                LOGGER.warning("Process already registered: [%s]. Skipping...",
                               proc_id)
                continue
            LOGGER.warning(
                "Process matches registered one: [%s]. Updating details...",
                proc_id)
        payload = {
            "processDescription": {
                "process": {
                    "id": proc_id,
                    "visibility": svc_vis
                }
            },
            "executionUnit": [{
                "href": proc_url
            }],
            "deploymentProfileName":
            "http://www.opengis.net/profiles/eoc/wpsApplication",
        }
        try:
            resp = deploy_process_from_payload(payload,
                                               container,
                                               overwrite=True)
            if resp.status_code == HTTPOk.code:
                LOGGER.info("Process registered: [%s]", proc_id)
            else:
                raise RuntimeError(
                    "Process registration failed: [{}]".format(proc_id))
        except Exception as ex:
            LOGGER.exception(
                "Exception during process registration: [%r]. Skipping...", ex)
            continue