def fetch_data_sources(): # type: () -> DataSourceConfig global DATA_SOURCES # pylint: disable=W0603,global-statement if DATA_SOURCES: return DATA_SOURCES settings = get_settings() data_source_config = settings.get("weaver.data_sources", "") if data_source_config: data_source_config = get_weaver_config_file( str(data_source_config), WEAVER_DEFAULT_DATA_SOURCES_CONFIG) if not os.path.isabs(data_source_config): data_source_config = os.path.normpath( os.path.join(WEAVER_ROOT_DIR, data_source_config)) try: with open(data_source_config, mode="r", encoding="utf-8") as f: DATA_SOURCES = yaml.safe_load(f) # both JSON/YAML except Exception as exc: raise ValueError( f"Data sources file [{data_source_config}] cannot be loaded due to error: [{exc!r}]." ) if not DATA_SOURCES: raise ValueError( "No data sources found in setting 'weaver.data_sources'. Data source required for EMS." ) return DATA_SOURCES
def get_wps_output_context(request): # type: (AnyRequestType) -> Optional[str] """ Obtains and validates allowed values for sub-directory context of WPS outputs in header ``X-WPS-Output-Context``. :raises HTTPUnprocessableEntity: if the header was provided an contains invalid or illegal value. :returns: validated context or None if not specified. """ headers = getattr(request, "headers", {}) ctx = get_header(sd.WpsOutputContextHeader.name, headers) if not ctx: settings = get_settings(request) ctx_default = settings.get("weaver.wps_output_context", None) if not ctx_default: return None LOGGER.debug("Using default 'wps.wps_output_context': %s", ctx_default) ctx = ctx_default cxt_found = re.match(r"^(?=[\w-]+)([\w-]+/?)+$", ctx) if cxt_found and cxt_found[0] == ctx: ctx_matched = ctx[:-1] if ctx.endswith("/") else ctx LOGGER.debug("Using request 'X-WPS-Output-Context': %s", ctx_matched) return ctx_matched raise HTTPUnprocessableEntity( json={ "code": "InvalidHeaderValue", "name": sd.WpsOutputContextHeader.name, "description": "Provided value for 'X-WPS-Output-Context' request header is invalid.", "cause": "Value must be an alphanumeric context directory or tree hierarchy of sub-directory names.", "value": str(ctx) })
def includeme(config): from weaver.wps.app import pywps_view settings = get_settings(config) logger = logging.getLogger(__name__) if not asbool(settings.get("weaver.wps", True)): logger.debug( "Weaver WPS disable. WPS KVP/XML endpoint will not be available.") else: logger.debug("Weaver WPS enabled.") wps_path = get_wps_path(settings) wps_service = Service(name="wps", path=wps_path) logger.debug("Adding WPS KVP/XML schemas.") wps_tags = [ sd.TAG_GETCAPABILITIES, sd.TAG_DESCRIBEPROCESS, sd.TAG_EXECUTE, sd.TAG_WPS ] wps_service.add_view("GET", pywps_view, tags=wps_tags, renderer=OUTPUT_FORMAT_XML, schema=sd.WPSEndpoint(), response_schemas=sd.wps_responses) wps_service.add_view("POST", pywps_view, tags=wps_tags, renderer=OUTPUT_FORMAT_XML, schema=sd.WPSEndpoint(), response_schemas=sd.wps_responses) logger.debug("Adding WPS KVP/XML view.") config.add_route(**sd.service_api_route_info(wps_service, settings)) config.add_view(pywps_view, route_name=wps_service.name)
def get_schema_ref(schema, container=None, ref_type="$schema", ref_name=True): # type: (colander.SchemaNode, Optional[AnySettingsContainer], str, True) -> Dict[str, str] """ Generates the JSON OpenAPI schema reference relative to the current `Weaver` instance. The provided schema should be one of the items listed in ``#/definitions`` of the ``/json`` endpoint. No validation is accomplished to avoid long processing of all references. If setting ``weaver.schema_url`` is set, this value will be used direct as fully-defined base URL. This could be used to refer to a static endpoint where schemas are hosted. Otherwise, the current Web Application resolved location is employed with JSON OpenAPI path. :param schema: schema-node instance or type for which to generate the OpenAPI reference. :param container: application settings to retrieve the base URL of the schema location. :param ref_type: key employed to form the reference (e.g.: "$schema", "$ref", "@schema", etc.) :param ref_name: indicate if the plain name should also be included under field ``"schema"``. :return: OpenAPI schema reference """ is_instance = isinstance(schema, colander.SchemaNode) assert is_instance or (inspect.isclass(schema) and issubclass(schema, colander.SchemaNode)) if is_instance: schema = type(schema) schema_name = schema.__name__ settings = get_settings(container) weaver_schema_url = settings.get("weaver.schema_url") if not weaver_schema_url: restapi_path = get_wps_restapi_base_url(container) weaver_schema_url = f"{restapi_path}{sd.openapi_json_service.path}#/definitions" weaver_schema_url = weaver_schema_url.rstrip("/").strip() schema_ref = {ref_type: f"{weaver_schema_url}/{schema_name}"} if ref_name: schema_ref.update({"schema": schema_name}) return schema_ref
def get_pywps_service(environ=None, is_worker=False): """ Generates the PyWPS Service that provides *older* WPS-1/2 XML endpoint. """ environ = environ or {} try: # get config file settings = get_settings(app) pywps_cfg = environ.get("PYWPS_CFG") or settings.get( "PYWPS_CFG") or os.getenv("PYWPS_CFG") if not isinstance( pywps_cfg, ConfigParser) or not settings.get("weaver.wps_configured"): load_pywps_config(app, config=pywps_cfg) # call pywps application with processes filtered according to the adapter's definition process_store = get_db(app).get_store(StoreProcesses) processes_wps = [ process.wps() for process in process_store.list_processes( visibility=VISIBILITY_PUBLIC) ] service = WorkerService(processes_wps, is_worker=is_worker, settings=settings) except Exception as ex: LOGGER.exception( "Error occurred during PyWPS Service and/or Processes setup.") raise OWSNoApplicableCode( "Failed setup of PyWPS Service and/or Processes. Error [{!r}]". format(ex)) return service
def get_mongodb_connection(container): # type: (AnySettingsContainer) -> Database """ Obtains the basic database connection from settings. """ settings = get_settings(container) settings_default = [("mongodb.host", "localhost"), ("mongodb.port", 27017), ("mongodb.db_name", "weaver")] for setting, default in settings_default: if settings.get(setting, None) is None: warnings.warn( f"Setting '{setting}' not defined in registry, using default [{default}]." ) settings[setting] = default client = pymongo.MongoClient( settings["mongodb.host"], int(settings["mongodb.port"]), connect=False, # Must specify representation since PyMongo 4.0 and also to avoid Python 3.6 error # https://pymongo.readthedocs.io/en/stable/examples/uuid.html#unspecified uuidRepresentation="pythonLegacy", # Require that datetime objects be returned with timezone awareness. # This ensures that missing 'tzinfo' does not get misinterpreted as locale time when # loading objects from DB, since by default 'datetime.datetime' employs 'tzinfo=None' # for locale naive datetime objects, while MongoDB stores Date in ISO-8601 format. tz_aware=True) return client[settings["mongodb.db_name"]]
def map_wps_output_location(reference, container, url=False, exists=True, file_scheme=False): # type: (str, AnySettingsContainer, bool, bool, bool) -> Optional[str] """ Obtains the mapped WPS output location of a file where applicable. :param reference: Local file path or file URL to be mapped. :param container: Retrieve application settings. :param url: Perform URL mapping (local path -> URL endpoint), or map to local path (URL -> local path). :param exists: Ensure that the mapped file exists, otherwise don't map it (otherwise ``None``). :param file_scheme: Ensure that the 'file://' scheme is applied to resulting local file location when mapped from WPS output URL. When in 'reverse' mode, 'file://' is always removed if present to form a potential local file path. :returns: Mapped reference that corresponds to the local/URL WPS output location. """ settings = get_settings(container) wps_out_dir = get_wps_output_dir(settings) wps_out_url = get_wps_output_url(settings) if url and reference.startswith("file://"): reference = reference[7:] if url and reference.startswith(wps_out_dir): wps_out_ref = reference.replace(wps_out_dir, wps_out_url, 1) if not exists or os.path.isfile(reference): return wps_out_ref elif not url and reference.startswith(wps_out_url): wps_out_ref = reference.replace(wps_out_url, wps_out_dir, 1) if not exists or os.path.isfile(wps_out_ref): if file_scheme: return "file://" + wps_out_ref return wps_out_ref return None
def get_pywps_service(environ=None, is_worker=False): # type: (SettingsType, bool) -> WorkerService """ Generates the PyWPS Service that provides WPS-1/2 XML endpoint. """ environ = environ or {} try: # get config file registry = get_registry() settings = get_settings(registry) pywps_cfg = environ.get("PYWPS_CFG") or settings.get( "PYWPS_CFG") or os.getenv("PYWPS_CFG") if not isinstance( pywps_cfg, ConfigParser) or not settings.get("weaver.wps_configured"): load_pywps_config(settings, config=pywps_cfg) # call pywps application with processes filtered according to the adapter's definition process_store = get_db(registry).get_store( StoreProcesses) # type: StoreProcesses processes_wps = [ process.wps() for process in process_store.list_processes( visibility=Visibility.PUBLIC) ] service = WorkerService(processes_wps, is_worker=is_worker, settings=settings) except Exception as ex: LOGGER.exception( "Error occurred during PyWPS Service and/or Processes setup.") raise OWSNoApplicableCode( f"Failed setup of PyWPS Service and/or Processes. Error [{ex!r}]") return service
def raise_job_dismissed(job, container=None): # type: (Job, Optional[AnySettingsContainer]) -> None """ Raise the appropriate messages for dismissed :term:`Job` status. """ if job.status == Status.DISMISSED: # provide the job status links since it is still available for reference settings = get_settings(container) job_links = job.links(settings) job_links = [ link for link in job_links if link["rel"] in ["status", "alternate", "collection", "up"] ] raise JobGone( json={ "title": "JobDismissed", "type": "JobDismissed", "status": JobGone.code, "detail": "Job was dismissed and artifacts have been removed.", "cause": { "status": job.status }, "value": str(job.id), "links": job_links })
def get_providers(request): """ Lists registered providers. """ store = get_db(request).get_store(StoreServices) providers = [] for service in store.list_services(): try: if service.type.lower() != "wps": continue wps = WebProcessingService(url=service.url, headers=get_cookie_headers( request.headers)) providers.append( dict(id=service.name, title=getattr(wps.identification, "title", ""), abstract=getattr(wps.identification, "abstract", ""), url="{base_url}/providers/{provider_id}".format( base_url=get_wps_restapi_base_url( get_settings(request)), provider_id=service.name), public=service.public)) except Exception as exc: warnings.warn( "Exception occurred while fetching wps {0} : {1!r}".format( service.url, exc), NonBreakingExceptionWarning) return HTTPOk(json={"providers": providers})
def json(self, container=None): # pylint: disable=W0221,arguments-differ # type: (Optional[AnySettingsContainer]) -> JSON """Obtain the JSON data representation for response body. .. note:: Settings are required to update API shortcut URLs to job additional information. Without them, paths will not include the API host, which will not resolve to full URI. """ settings = get_settings(container) if container else {} job_json = { "jobID": self.id, "status": self.status, "message": self.status_message, "duration": self.duration_str, "percentCompleted": self.progress, } job_url = self._job_url(settings) # TODO: use links (https://github.com/crim-ca/weaver/issues/58) if self.status in JOB_STATUS_CATEGORIES[STATUS_CATEGORY_FINISHED]: job_status = map_status(self.status) if job_status == STATUS_SUCCEEDED: resource_type = "result" else: resource_type = "exceptions" job_json[resource_type] = "{job_url}/{res}".format(job_url=job_url, res=resource_type.lower()) job_json["logs"] = "{job_url}/logs".format(job_url=job_url) return sd.JobStatusInfo().deserialize(job_json)
def _get_settings_or_wps_config( container, # type: AnySettingsContainer weaver_setting_name, # type: str config_setting_section, # type: str config_setting_name, # type: str default_not_found, # type: str message_not_found, # type: str load=False, # type: bool ): # type: (...) -> str settings = get_settings(container) found = settings.get(weaver_setting_name) if not found: if not settings.get("weaver.wps_configured") and load: load_pywps_config(container) # not yet defined on first load permitted if settings retrieved early on if pywps_config.CONFIG: found = pywps_config.CONFIG.get(config_setting_section, config_setting_name) if not isinstance(found, str): LOGGER.warning( "%s not set in settings or WPS configuration, using default value.", message_not_found) found = default_not_found return found.strip()
def main(global_config, **settings): """ Creates a Pyramid WSGI application for Weaver. """ setup_loggers(settings) LOGGER.info("Initiating weaver application") # validate and fix configuration weaver_config = get_weaver_configuration(settings) settings.update({"weaver.configuration": weaver_config}) # Parse extra_options and add each of them in the settings dict LOGGER.info("Parsing extra options...") settings.update( parse_extra_options(settings.get("weaver.extra_options", ""))) # load requests options if found, otherwise skip LOGGER.info("Checking for request options file...") req_file = get_weaver_config_file(settings.get("weaver.request_options", ""), WEAVER_DEFAULT_REQUEST_OPTIONS_CONFIG, generate_default_from_example=False) if req_file: LOGGER.info("Loading request options...") with open(req_file, "r") as f: settings.update({"weaver.request_options": yaml.safe_load(f)}) else: LOGGER.warning("No request options found.") # add default caching regions if they were omitted in config file if settings.get("weaver.celery", False): LOGGER.info("Celery runner detected. Skipping cache options setup.") else: LOGGER.info("Adding default caching options...") setup_cache(settings) LOGGER.info("Setup celery configuration...") local_config = Configurator(settings=settings) if global_config.get("__file__") is not None: local_config.include("pyramid_celery") local_config.configure_celery(global_config["__file__"]) local_config.include("weaver") LOGGER.info("Running database migration...") db = get_db(settings) db.run_migration() if settings.get("weaver.celery", False): LOGGER.info("Celery runner detected. Skipping process registration.") else: LOGGER.info("Registering builtin processes...") register_builtin_processes(local_config) LOGGER.info("Registering WPS-1 processes from configuration file...") wps_processes_file = get_settings(local_config).get( "weaver.wps_processes_file") register_wps_processes_from_config(wps_processes_file, local_config) return local_config.make_wsgi_app()
def __init__(self, container): # type: (AnySettingsContainer) -> None super(MongoDatabase, self).__init__(container) self._database = get_mongodb_engine(container) self._settings = get_settings(container) self._stores = dict() LOGGER.debug("Database [%s] using versions: {MongoDB: %s, pymongo: %s}", self._database.name, self._database.client.server_info()["version"], pymongo.__version__)
def get_wps_output_path(container): # type: (AnySettingsContainer) -> str """ Retrieves the WPS output path (without hostname) for staging XML status, logs and process outputs. Searches directly in settings, then `weaver.wps_cfg` file, or finally, uses the default values if not found. """ return get_settings(container).get("weaver.wps_output_path") or urlparse( get_wps_output_url(container)).path
def get_wps_url(container, load=True): # type: (AnySettingsContainer, bool) -> str """ Retrieves the full WPS URL (hostname + WPS path). Searches directly in settings, then `weaver.wps_cfg` file, or finally, uses the default values if not found. """ return get_settings(container).get("weaver.wps_url") or get_weaver_url( container) + get_wps_path(container, load)
def get_wps_restapi_base_url(container): # type: (AnySettingsContainer) -> str settings = get_settings(container) weaver_rest_url = settings.get("weaver.wps_restapi_url") if not weaver_rest_url: weaver_url = get_weaver_url(settings) restapi_path = wps_restapi_base_path(settings) weaver_rest_url = weaver_url + restapi_path return weaver_rest_url.rstrip("/").strip()
def submit_job(request, reference, tags=None): # type: (Request, Union[Service, Process], Optional[List[str]]) -> JSON """ Generates the job submission from details retrieved in the request. .. seealso:: :func:`submit_job_handler` to provide elements pre-extracted from requests or from other parsing. """ # validate body with expected JSON content and schema if CONTENT_TYPE_APP_JSON not in request.content_type: raise HTTPBadRequest( "Request 'Content-Type' header other than '{}' not supported.". format(CONTENT_TYPE_APP_JSON)) try: json_body = request.json_body except Exception as ex: raise HTTPBadRequest( "Invalid JSON body cannot be decoded for job submission. [{}]". format(ex)) provider_id = None # None OK if local process_id = None # None OK if remote, but can be found as well if available from WPS-REST path tags = tags or [] if isinstance(reference, Process): service_url = reference.processEndpointWPS1 process_id = reference.id visibility = reference.visibility is_workflow = reference.type == PROCESS_WORKFLOW is_local = True tags += "local" elif isinstance(reference, Service): service_url = reference.url provider_id = reference.id process_id = request.matchdict.get("process_id") visibility = VISIBILITY_PUBLIC is_workflow = False is_local = False tags += "remote" else: LOGGER.error("Expected process/service, got: %s", type(reference)) raise TypeError("Invalid process or service reference to execute job.") tags = request.params.get("tags", "").split(",") + tags user = request.authenticated_userid lang = request.accept_language.header_value headers = dict(request.headers) settings = get_settings(request) return submit_job_handler(json_body, settings, service_url, provider_id, process_id, is_workflow, is_local, visibility, language=lang, auth=headers, tags=tags, user=user)
def includeme(config): # type: (Configurator) -> None settings = get_settings(config) if asbool(settings.get("weaver.vault", True)): LOGGER.info("Adding file vault...") config.add_route(**sd.service_api_route_info(sd.vault_service, settings)) config.add_route(**sd.service_api_route_info(sd.vault_file_service, settings)) config.add_view(v.upload_file, route_name=sd.vault_service.name, request_method="POST") config.add_view(v.describe_file, route_name=sd.vault_file_service.name, request_method="HEAD") config.add_view(v.download_file, route_name=sd.vault_file_service.name, request_method="GET")
def api_frontpage(request): """Frontpage of weaver.""" # import here to avoid circular import errors from weaver.config import get_weaver_configuration settings = get_settings(request) weaver_url = get_weaver_url(settings) weaver_config = get_weaver_configuration(settings) weaver_api = asbool(settings.get("weaver.wps_restapi")) weaver_api_url = get_wps_restapi_base_url(settings) if weaver_api else None weaver_api_def = weaver_api_url + sd.api_swagger_ui_uri if weaver_api else None weaver_api_doc = settings.get("weaver.wps_restapi_doc", None) if weaver_api else None weaver_api_ref = settings.get("weaver.wps_restapi_ref", None) if weaver_api else None weaver_wps = asbool(settings.get("weaver.wps")) weaver_wps_url = get_wps_url(settings) if weaver_wps else None weaver_conform_url = weaver_url + sd.api_conformance_uri weaver_process_url = weaver_url + sd.processes_uri weaver_links = [ {"href": weaver_url, "rel": "self", "type": CONTENT_TYPE_APP_JSON, "title": "This document"}, {"href": weaver_conform_url, "rel": "conformance", "type": CONTENT_TYPE_APP_JSON, "title": "WPS 2.0/3.0 REST-JSON Binding Extension conformance classes implemented by this service."}, ] if weaver_api_def: weaver_links.append({"href": weaver_api_def, "rel": "service", "type": CONTENT_TYPE_APP_JSON, "title": "API definition of this service."}) if isinstance(weaver_api_doc, str): if "." in weaver_api_doc: # pylint: disable=E1135,unsupported-membership-test ext_type = weaver_api_doc.split(".")[-1] doc_type = "application/{}".format(ext_type) else: doc_type = CONTENT_TYPE_TEXT_PLAIN # default most basic type weaver_links.append({"href": weaver_api_doc, "rel": "documentation", "type": doc_type, "title": "API documentation about this service."}) if weaver_api_ref: weaver_links.append({"href": weaver_api_ref, "rel": "reference", "type": CONTENT_TYPE_APP_JSON, "title": "API reference specification of this service."}) weaver_links.append({"href": weaver_process_url, "rel": "processes", "type": CONTENT_TYPE_APP_JSON, "title": "Processes offered by this service."}) return { "message": "Weaver Information", "configuration": weaver_config, "parameters": [ {"name": "api", "enabled": weaver_api, "url": weaver_api_url, "doc": weaver_api_doc, "api": weaver_api_def, "ref": weaver_api_ref}, {"name": "wps", "enabled": weaver_wps, "url": weaver_wps_url}, ], "links": weaver_links, }
def submit_job(request, reference, tags=None): # type: (Request, Union[Service, Process], Optional[List[str]]) -> JSON """ Generates the job submission from details retrieved in the request. .. seealso:: :func:`submit_job_handler` to provide elements pre-extracted from requests or from other parsing. """ # validate body with expected JSON content and schema if CONTENT_TYPE_APP_JSON not in request.content_type: raise HTTPBadRequest(json={ "code": "InvalidHeaderValue", "name": "Content-Type", "description": "Request 'Content-Type' header other than '{}' not supported.".format(CONTENT_TYPE_APP_JSON), "value": str(request.content_type) }) try: json_body = request.json_body except Exception as ex: raise HTTPBadRequest("Invalid JSON body cannot be decoded for job submission. [{}]".format(ex)) # validate context if needed later on by the job for early failure context = get_wps_output_context(request) provider_id = None # None OK if local process_id = None # None OK if remote, but can be found as well if available from WPS-REST path tags = tags or [] lang = request.accept_language.header_value # can only preemptively check if local process if isinstance(reference, Process): service_url = reference.processEndpointWPS1 process_id = reference.id visibility = reference.visibility is_workflow = reference.type == PROCESS_WORKFLOW is_local = True tags += "local" if lang and request.accept_language.best_match(ACCEPT_LANGUAGES) is None: raise HTTPNotAcceptable("Requested language [{}] is not in supported languages [{}].".format( lang, ", ".join(ACCEPT_LANGUAGES) )) elif isinstance(reference, Service): service_url = reference.url provider_id = reference.id process_id = request.matchdict.get("process_id") visibility = VISIBILITY_PUBLIC is_workflow = False is_local = False tags += "remote" else: LOGGER.error("Expected process/service, got: %s", type(reference)) raise TypeError("Invalid process or service reference to execute job.") tags = request.params.get("tags", "").split(",") + tags user = request.authenticated_userid headers = dict(request.headers) settings = get_settings(request) return submit_job_handler(json_body, settings, service_url, provider_id, process_id, is_workflow, is_local, visibility, language=lang, auth=headers, tags=tags, user=user, context=context)
def __init__(self, request): # type: (WPSRequest) -> None self.request = request self.cookies = get_cookie_headers(self.request.http_request.headers) self.headers = { "Accept": CONTENT_TYPE_APP_JSON, "Content-Type": CONTENT_TYPE_APP_JSON } self.settings = get_settings(app) self.verify = asbool( self.settings.get("weaver.ows_proxy_ssl_verify", True))
def __init__(self, request, update_status): # type: (WorkerRequest, UpdateStatusPartialFunction) -> None self.request = request self.headers = { "Accept": ContentType.APP_JSON, "Content-Type": ContentType.APP_JSON } self.settings = get_settings() self.update_status = update_status # type: UpdateStatusPartialFunction self.temp_staging = set() self.stage_output_id_nested = False
def host_file(file_name): settings = get_settings(app) weaver_output_url = get_wps_output_url(settings) weaver_output_dir = get_wps_output_dir(settings) file_name = file_name.replace("file://", "") if not file_name.startswith(weaver_output_dir): raise Exception( "Cannot host files outside of the output path : {0}".format( file_name)) return file_name.replace(weaver_output_dir, weaver_output_url)
def retrieve_data_source_url(data_source): # type: (Optional[Text]) -> str """ Finds the data source URL using the provided data source identifier. :returns: found URL, 'default' data source if not found, or current weaver WPS Rest API base URL if `None`. """ if data_source is None: # get local data source return get_wps_restapi_base_url(get_settings()) data_sources = fetch_data_sources() return data_sources[data_source if data_source in data_sources else get_default_data_source(data_sources)]["ades"]
def redoc_ui_cached(request): settings = get_settings(request) weaver_server_url = get_weaver_url(settings) spec = openapi_json_cached(base_url=weaver_server_url, settings=settings, use_docstring_summary=True, use_refs=False) data_mako = {"openapi_spec": json.dumps(spec, ensure_ascii=False)} resp = render_to_response("templates/redoc_ui.mako", data_mako, request=request) return resp
def includeme(config): settings = get_settings(config) if asbool(settings.get("weaver.build_docs", False)): LOGGER.info("Skipping database when building docs...") return LOGGER.info("Adding database...") def _add_db(request): return MongoDatabase(request.registry) config.add_request_method(_add_db, "db", reify=True)
def get_processes(request): """ List registered processes (GetCapabilities). Optionally list both local and provider processes. """ detail = asbool(request.params.get("detail", True)) try: # get local processes and filter according to schema validity # (previously deployed process schemas can become invalid because of modified schema definitions processes, invalid_processes = get_processes_filtered_by_valid_schemas( request) if invalid_processes: raise HTTPServiceUnavailable( "Previously deployed processes are causing invalid schema integrity errors. " "Manual cleanup of following processes is required: {}".format( invalid_processes)) response_body = { "processes": processes if detail else [get_any_id(p) for p in processes] } # if 'EMS' and '?providers=True', also fetch each provider's processes settings = get_settings(request) if get_weaver_configuration(settings) == WEAVER_CONFIGURATION_EMS: queries = parse_request_query(request) if "providers" in queries and asbool( queries["providers"][0]) is True: prov_url = "{host}/providers".format(host=request.host_url) providers_response = request_extra("GET", prov_url, settings=settings, headers=request.headers, cookies=request.cookies) providers = providers_response.json() response_body.update({"providers": providers}) for i, provider in enumerate(providers): provider_id = get_any_id(provider) proc_url = "{host}/providers/{prov}/processes".format( host=request.host_url, prov=provider_id) response = request_extra("GET", proc_url, settings=settings, headers=request.headers, cookies=request.cookies) processes = response.json().get("processes", []) response_body["providers"][i].update({ "processes": processes if detail else [get_any_id(p) for p in processes] }) return HTTPOk(json=response_body) except colander.Invalid as ex: raise HTTPBadRequest("Invalid schema: [{!s}]".format(ex))
def get_vault_url(file, container=None): # type: (Union[VaultFile, uuid.UUID, str], Optional[AnySettingsContainer]) -> str """ Obtain the vault link corresponding to the file. """ if isinstance(file, uuid.UUID) or is_uuid(file): file_id = str(file) else: file_id = file.id settings = get_settings(container) base_url = get_weaver_url(settings) vault_url = base_url + sd.vault_file_service.path.format(file_id=file_id) return vault_url
def openapi_json(request): # noqa: F811 # type: (Request) -> dict """ Weaver OpenAPI schema definitions. """ # obtain 'server' host and api-base-path, which doesn't correspond necessarily to the app's host and path # ex: 'server' adds '/weaver' with proxy redirect before API routes settings = get_settings(request) weaver_server_url = get_weaver_url(settings) LOGGER.debug("Request app URL: [%s]", request.url) LOGGER.debug("Weaver config URL: [%s]", weaver_server_url) return openapi_json_cached(base_url=weaver_server_url, use_docstring_summary=True, settings=settings)