-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'issue668-federation-extension'
- Loading branch information
Showing
24 changed files
with
1,124 additions
and
294 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
|
||
.. _federation-extension: | ||
|
||
=========================== | ||
openEO Federation Extension | ||
=========================== | ||
|
||
|
||
The `openEO Federation extension <https://github.com/Open-EO/openeo-api/tree/master/extensions/federation>`_ | ||
is a set of additional specifications, | ||
on top of the standard openEO API specification, | ||
to address the need for extra metadata in the context | ||
of federated openEO processing, | ||
where multiple (separately operated) openEO services are bundled together | ||
behind a single API endpoint. | ||
|
||
|
||
Accessing federation extension metadata | ||
======================================== | ||
|
||
The openEO Python client library provides access to this additional metadata | ||
in a couple of resources. | ||
|
||
.. versionadded:: 0.38.0 | ||
initial support to access federation extension related metadata. | ||
|
||
.. warning:: this API is experimental and subject to change. | ||
|
||
|
||
Backend details | ||
--------------- | ||
|
||
Participating backends in a federation are listed under the ``federation`` field | ||
of the capabilities document (``GET /``) and can be inspected | ||
using :py:meth:`OpenEoCapabilities.ext_federation_backend_details() <openeo.rest.capabilities.OpenEoCapabilities.ext_federation_backend_details>`: | ||
|
||
.. code-block:: python | ||
import openeo | ||
connection = openeo.connect(url=...) | ||
capabilities = connection.capabilities() | ||
print("Federated backends:", capabilities.ext_federation_backend_details()) | ||
Unavailable backends (``federation:missing``) | ||
---------------------------------------------- | ||
|
||
When listing resources like | ||
collections (with :py:meth:`Connection.list_collections() <openeo.rest.connection.Connection.list_collections>`), | ||
processes (with :py:meth:`Connection.list_processes() <openeo.rest.connection.Connection.list_processes>`), | ||
jobs (with :py:meth:`Connection.list_jobs() <openeo.rest.connection.Connection.list_jobs>`), | ||
etc., | ||
there might be items missing due to federation participants being temporarily unavailable. | ||
These missing federation components are listed in the response under the ``federation:missing`` field | ||
and can be inspected as follows: | ||
|
||
.. code-block:: python | ||
import openeo | ||
connection = openeo.connect(url=...) | ||
collections = connection.list_collections() | ||
print("Number of collections:", len(collections)) | ||
print("Missing federation components:", collections.ext_federation_missing()) | ||
Note that the ``collections`` object in this example, returned by | ||
:py:meth:`Connection.list_collections() <openeo.rest.connection.Connection.list_collections>`, | ||
acts at the surface as a simple list of dictionaries with collection metadata, | ||
but also provides additional properties/methods like | ||
:py:attr:`ext_federation_missing() <openeo.rest.models.general.CollectionListingResponse.ext_federation_missing>`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,13 @@ | ||
import logging | ||
from typing import Optional, Union | ||
import warnings | ||
|
||
from openeo.internal.warnings import UserDeprecationWarning | ||
from openeo.rest.models.logs import LogEntry, log_level_name, normalize_log_level | ||
|
||
class LogEntry(dict): | ||
""" | ||
Log message and info for jobs and services | ||
warnings.warn( | ||
message="Submodule `openeo.api.logs` is deprecated in favor of `openeo.rest.models.logs`.", | ||
category=UserDeprecationWarning, | ||
stacklevel=2, | ||
) | ||
|
||
Fields: | ||
- ``id``: Unique ID for the log, string, REQUIRED | ||
- ``code``: Error code, string, optional | ||
- ``level``: Severity level, string (error, warning, info or debug), REQUIRED | ||
- ``message``: Error message, string, REQUIRED | ||
- ``time``: Date and time of the error event as RFC3339 date-time, string, available since API 1.1.0 | ||
- ``path``: A "stack trace" for the process, array of dicts | ||
- ``links``: Related links, array of dicts | ||
- ``usage``: Usage metrics available as property 'usage', dict, available since API 1.1.0 | ||
May contain the following metrics: cpu, memory, duration, network, disk, storage and other custom ones | ||
Each of the metrics is also a dict with the following parts: value (numeric) and unit (string) | ||
- ``data``: Arbitrary data the user wants to "log" for debugging purposes. | ||
Please note that this property may not exist as there's a difference | ||
between None and non-existing. None for example refers to no-data in | ||
many cases while the absence of the property means that the user did | ||
not provide any data for debugging. | ||
""" | ||
|
||
_required = {"id", "level", "message"} | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
|
||
# Check required fields | ||
missing = self._required.difference(self.keys()) | ||
if missing: | ||
raise ValueError("Missing required fields: {m}".format(m=sorted(missing))) | ||
|
||
@property | ||
def id(self): | ||
return self["id"] | ||
|
||
# Legacy alias | ||
log_id = id | ||
|
||
@property | ||
def message(self): | ||
return self["message"] | ||
|
||
@property | ||
def level(self): | ||
return self["level"] | ||
|
||
# TODO: add properties for "code", "time", "path", "links" and "data" with sensible defaults? | ||
|
||
|
||
def normalize_log_level( | ||
log_level: Union[int, str, None], default: int = logging.DEBUG | ||
) -> int: | ||
""" | ||
Helper function to convert a openEO API log level (e.g. string "error") | ||
to the integer constants defined in Python's standard library ``logging`` module (e.g. ``logging.ERROR``). | ||
:param log_level: log level to normalize: a log level string in the style of | ||
the openEO API ("error", "warning", "info", or "debug"), | ||
an integer value (e.g. a ``logging`` constant), or ``None``. | ||
:param default: fallback log level to return on unknown log level strings or ``None`` input. | ||
:raises TypeError: when log_level is any other type than str, an int or None. | ||
:return: One of the following log level constants from the standard module ``logging``: | ||
``logging.ERROR``, ``logging.WARNING``, ``logging.INFO``, or ``logging.DEBUG`` . | ||
""" | ||
if isinstance(log_level, str): | ||
log_level = log_level.upper() | ||
if log_level in ["CRITICAL", "ERROR", "FATAL"]: | ||
return logging.ERROR | ||
elif log_level in ["WARNING", "WARN"]: | ||
return logging.WARNING | ||
elif log_level == "INFO": | ||
return logging.INFO | ||
elif log_level == "DEBUG": | ||
return logging.DEBUG | ||
else: | ||
return default | ||
elif isinstance(log_level, int): | ||
return log_level | ||
elif log_level is None: | ||
return default | ||
else: | ||
raise TypeError( | ||
f"Value for log_level is not an int or str: type={type(log_level)}, value={log_level!r}" | ||
) | ||
|
||
|
||
def log_level_name(log_level: Union[int, str, None]) -> str: | ||
""" | ||
Get the name of a normalized log level. | ||
This value conforms to log level names used in the openEO API. | ||
""" | ||
return logging.getLevelName(normalize_log_level(log_level)).lower() | ||
__all__ = ["LogEntry", "normalize_log_level", "log_level_name"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.