From 1b1c90e6e02fd33027aa5813625ac66d2d0123c1 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 13:24:54 +0100 Subject: [PATCH 01/36] Remove trailing '/' but preserve the leading ones --- lifemonitor/auth/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifemonitor/auth/models.py b/lifemonitor/auth/models.py index ffb65cbd7..8d28e8d80 100644 --- a/lifemonitor/auth/models.py +++ b/lifemonitor/auth/models.py @@ -222,7 +222,7 @@ class Resource(db.Model, ModelMixin): def __init__(self, uri, uuid=None, name=None, version=None) -> None: assert uri, "URI cannot be empty" - self.uri = uri.strip('/') + self.uri = uri.rstrip('/') self.name = name self.version = version self.uuid = uuid From bc8e562a513406d1fa2aa69197dfbf5360103f9f Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 21:54:47 +0100 Subject: [PATCH 02/36] Detect temp files through 'tmp' prefix --- lifemonitor/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifemonitor/utils.py b/lifemonitor/utils.py index cba1b2723..78f124375 100644 --- a/lifemonitor/utils.py +++ b/lifemonitor/utils.py @@ -196,7 +196,7 @@ def download_url(url: str, target_path: str = None, authorization: str = None) - target_path = tempfile.mktemp() try: parsed_url = urllib.parse.urlparse(url) - if parsed_url.scheme == '' or parsed_url.scheme == 'file': + if parsed_url.scheme == '' or parsed_url.scheme in ['file', 'tmp']: logger.debug("Copying %s to local path %s", url, target_path) shutil.copyfile(parsed_url.path, target_path) else: From 8bca46aef3e8dc541214a84fbca30a246f039062 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 21:57:24 +0100 Subject: [PATCH 03/36] Update specs: support encoded rocrate on post methods --- specs/api.yaml | 84 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/specs/api.yaml b/specs/api.yaml index 6bcec386b..79f21a624 100644 --- a/specs/api.yaml +++ b/specs/api.yaml @@ -217,7 +217,8 @@ paths: application/json: schema: oneOf: - - $ref: "#/components/schemas/GenericWorkflowVersion" + - $ref: "#/components/schemas/RoCrateWorkflowVersion" + - $ref: "#/components/schemas/RoCrateLinkWorkflowVersion" - $ref: "#/components/schemas/RegistryWorkflowVersion" responses: "201": @@ -335,7 +336,8 @@ paths: application/json: schema: oneOf: - - $ref: "#/components/schemas/GenericWorkflowVersion" + - $ref: "#/components/schemas/RoCrateWorkflowVersion" + - $ref: "#/components/schemas/RoCrateLinkWorkflowVersion" - $ref: "#/components/schemas/RegistryWorkflowVersion" responses: "201": @@ -391,7 +393,9 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/GenericWorkflowVersion" + oneOf: + - $ref: "#/components/schemas/RoCrateLinkWorkflowVersion" + - $ref: "#/components/schemas/RoCrateWorkflowVersion" responses: "201": $ref: "#/components/responses/WorkflowRegistered" @@ -1530,18 +1534,18 @@ components: description: | A name for the workflow. If not provided, the RO-Crate dataset name is used as default. example: "COVID-19 Workflow" - authorization: - type: string - nullable: true - writeOnly: true - description: | - An optional authorization header. - - The `authorization` parameter might be required to download - the RO-Crate containing the workflow if it is not directly - accessible to the user for download - (e.g., `authorization: "ApiKey 1234567890"`). - example: "Bearer xxx__ZRBhqf9eeRasjqMw90pgEeMpTZ7__" + # authorization: + # type: string + # nullable: true + # writeOnly: true + # description: | + # An optional authorization header. + + # The `authorization` parameter might be required to download + # the RO-Crate containing the workflow if it is not directly + # accessible to the user for download + # (e.g., `authorization: "ApiKey 1234567890"`). + # example: "Bearer xxx__ZRBhqf9eeRasjqMw90pgEeMpTZ7__" WorkflowVersionBase: allOf: @@ -1600,6 +1604,56 @@ components: - roc_link - $ref: "#/components/schemas/WorkflowVersionBase" + RoCrateLinkWorkflowVersion: + description: A generic workflow version + allOf: + - type: object + properties: + roc_link: + type: string + description: | + Link to the workflow RO-Crate + example: http://webserver:5000/download?file=ro-crate-galaxy-sortchangecase.crate.zip + uuid: + type: string + description: | + Universal unique identifier of the workflow. + example: 123e4567-e89b-12d3-a456-426614174000 + authorization: + type: string + nullable: true + writeOnly: true + description: | + An optional authorization header. + + The `authorization` parameter might be required to download + the RO-Crate containing the workflow if it is not directly + accessible to the user for download + (e.g., `authorization: "ApiKey 1234567890"`). + example: "Bearer xxx__ZRBhqf9eeRasjqMw90pgEeMpTZ7__" + required: + - roc_link + - $ref: "#/components/schemas/WorkflowVersionBase" + + RoCrateWorkflowVersion: + description: A generic workflow version + allOf: + - type: object + properties: + rocrate: + type: string + format: base64 + description: | + Base64 encoding of the RO-Crate archive + uuid: + type: string + description: | + Universal unique identifier of the workflow. + example: 123e4567-e89b-12d3-a456-426614174000 + required: + - rocrate + - $ref: "#/components/schemas/WorkflowVersionBase" + RegistryWorkflowVersion: description: A (version of a) workflow indexed by a registry. allOf: From 54f9b84a390263777e8f9b9bc1d77fc09ee820ae Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 21:58:10 +0100 Subject: [PATCH 04/36] Update API controller to support encoded rocrate --- lifemonitor/api/controllers.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lifemonitor/api/controllers.py b/lifemonitor/api/controllers.py index 75e3dfcb2..5bcbbc7f0 100644 --- a/lifemonitor/api/controllers.py +++ b/lifemonitor/api/controllers.py @@ -18,6 +18,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import os +import base64 import logging import tempfile @@ -306,10 +308,23 @@ def workflows_post(body, _registry=None, _submitter_id=None): detail=messages.input_data_missing) roc_link = body.get('roc_link', None) - if not registry and not roc_link: - return lm_exceptions.report_problem(400, "Bad Request", extra_info={"missing input": "roc_link"}, + encoded_rocrate = body.get('rocrate', None) + if not registry and not roc_link and not encoded_rocrate: + return lm_exceptions.report_problem(400, "Bad Request", extra_info={"missing input": "roc_link OR rocrate"}, detail=messages.input_data_missing) + temp_rocrate_file = None + if encoded_rocrate: + try: + rocrate = base64.b64decode(encoded_rocrate) + temp_rocrate_file = tempfile.NamedTemporaryFile(delete=False, prefix="/tmp/") + temp_rocrate_file.write(rocrate) + roc_link = f"tmp://{temp_rocrate_file.name}" + logger.debug("ROCrate written to %r", temp_rocrate_file.name) + except Exception as e: + return lm_exceptions.report_problem(400, "Bad Request", extra_info={"exception": str(e)}, + detail=messages.decode_ro_crate_error) + submitter = current_user if current_user and not current_user.is_anonymous else None if not submitter: try: @@ -366,6 +381,12 @@ def workflows_post(body, _registry=None, _submitter_id=None): except Exception as e: logger.exception(e) raise lm_exceptions.LifeMonitorException(title="Internal Error", detail=str(e)) + finally: + if roc_link and roc_link.startswith("tmp://"): + try: + os.remove(roc_link.replace('tmp://', '')) + except Exception as e: + logger.error("Error deleting temp rocrate: %r", str(e)) @authorized From 9a7b6f4237815d37d8b08c3c48545f29f4f83f7b Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 22:02:18 +0100 Subject: [PATCH 05/36] Store workflow RO-Crate locally --- lifemonitor/api/models/rocrate.py | 28 +++++++++++++++++++++++----- lifemonitor/config.py | 2 ++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lifemonitor/api/models/rocrate.py b/lifemonitor/api/models/rocrate.py index e166a6b81..868358508 100644 --- a/lifemonitor/api/models/rocrate.py +++ b/lifemonitor/api/models/rocrate.py @@ -20,11 +20,13 @@ from __future__ import annotations +import os import json import logging import tempfile from pathlib import Path - +import uuid as _uuid +from flask import current_app import lifemonitor.exceptions as lm_exceptions from lifemonitor.api.models import db from lifemonitor.auth.models import HostingService, Resource @@ -47,7 +49,7 @@ class ROCrate(Resource): backref=db.backref("ro_crates", cascade="all, delete-orphan"), foreign_keys=[hosting_service_id]) _metadata = db.Column("metadata", JSON, nullable=True) - _local_path = None + _local_path = db.Column("local_path", db.String, nullable=True) _metadata_loaded = False __roc_helper = None @@ -62,6 +64,19 @@ def __init__(self, uri, uuid=None, name=None, self.hosting_service = hosting_service self.__roc_helper = None + @property + def local_path(self): + if not self._local_path: + root_path = current_app.config.get('DATA_WORKFLOWS', '/data_workflows') + if not self.workflow.uuid: + self.workflow.uuid = _uuid.uuid4() + if not self.uuid: + self.uuid = _uuid.uuid4() + base_path = os.path.join(root_path, str(self.workflow.uuid)) + os.makedirs(base_path, exist_ok=True) + self._local_path = os.path.join(base_path, f"{self.uuid}.zip") + return self._local_path + @hybrid_property def crate_metadata(self): if not self._metadata_loaded and not self._metadata: @@ -103,13 +118,15 @@ def _get_authorizations(self): def load_metadata(self) -> dict: errors = [] + local_target_path = self.local_path + # try either with authorization header and without authorization for authorization in self._get_authorizations(): try: auth_header = authorization.as_http_header() if authorization else None logger.debug(auth_header) self.__roc_helper, self._metadata = \ - self.load_metadata_files(self.uri, authorization_header=auth_header) + self.load_metadata_files(self.uri, local_target_path, authorization_header=auth_header) self._metadata_loaded = True return self._metadata except lm_exceptions.NotAuthorizedException as e: @@ -140,11 +157,12 @@ def download(self, target_path: str) -> str: raise lm_exceptions.NotAuthorizedException(detail=f"Not authorized to download {self.uri}", original_errors=errors) @classmethod - def load_metadata_files(cls, roc_link, authorization_header=None): + def load_metadata_files(cls, roc_link, target_local_path, authorization_header=None): + with tempfile.TemporaryDirectory() as tmpdir: tmpdir_path = Path(tmpdir) local_zip = download_url(roc_link, - target_path=(tmpdir_path / 'rocrate.zip').as_posix(), + target_path=target_local_path, authorization=authorization_header) logger.debug("ZIP Archive: %s", local_zip) diff --git a/lifemonitor/config.py b/lifemonitor/config.py index 59546b948..7100f4715 100644 --- a/lifemonitor/config.py +++ b/lifemonitor/config.py @@ -77,6 +77,8 @@ class BaseConfig: # Default Cache Settings CACHE_TYPE = "flask_caching.backends.simplecache.SimpleCache" CACHE_DEFAULT_TIMEOUT = 60 + # Workflow Data Folder + DATA_WORKFLOWS = "./data" class DevelopmentConfig(BaseConfig): From f57f8c52cfc9fa9e0f40ac8980f44bf694d05911 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 22:03:26 +0100 Subject: [PATCH 06/36] Fix serialization of RO-Crate original link --- lifemonitor/api/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifemonitor/api/serializers.py b/lifemonitor/api/serializers.py index 0daea9132..32f7cb945 100644 --- a/lifemonitor/api/serializers.py +++ b/lifemonitor/api/serializers.py @@ -97,7 +97,7 @@ def get_links(self, obj: models.WorkflowVersion): def get_rocrate(self, obj): rocrate = { 'links': { - 'origin': obj.uri, + 'origin': obj.external_link, 'metadata': urljoin(lm_utils.get_external_server_url(), f"workflows/{obj.workflow.uuid}/rocrate/{obj.version}/metadata"), 'download': urljoin(lm_utils.get_external_server_url(), From fd88716ab8eabda30c72694aa42c75dc7ae77365 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 22:04:53 +0100 Subject: [PATCH 07/36] Fix missing error message --- lifemonitor/lang/messages.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lifemonitor/lang/messages.py b/lifemonitor/lang/messages.py index 3d53ca304..36246be48 100644 --- a/lifemonitor/lang/messages.py +++ b/lifemonitor/lang/messages.py @@ -31,6 +31,7 @@ not_authorized_registry_access = "User not authorized to access the registry '{}'" not_authorized_workflow_access = "User not authorized to get workflow data" input_data_missing = "One or more input data are missing" +decode_ro_crate_error = "Unable to decode the RO Crate: it should be encoded using base64" invalid_ro_crate = "RO Crate processing exception" workflow_not_found = "Workflow '{}' (ver.{}) not found" workflow_version_conflict = "Workflow '{}' (ver.{}) already exists" From 3caf113d41d1fd306a9b9d51af517c9643c2e6d9 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 22:09:35 +0100 Subject: [PATCH 08/36] Return empty external link for directly uploaded workflows --- lifemonitor/api/models/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifemonitor/api/models/workflows.py b/lifemonitor/api/models/workflows.py index 3bece861a..5a7d51412 100644 --- a/lifemonitor/api/models/workflows.py +++ b/lifemonitor/api/models/workflows.py @@ -227,7 +227,7 @@ def external_link(self) -> str: @cached(Timeout.WORKFLOW, client_scope=False) def get_external_link(self) -> str: if self.hosting_service is None: - return self.uri + return self.uri if 'tmp://' not in self.uri else '' return self.hosting_service.get_external_link(self.workflow.external_id, self.version) @hybrid_property From cdf07b7c652e7d3eb9d6fa8db781399d3887b2c1 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 22:11:20 +0100 Subject: [PATCH 09/36] Fix workflow filter --- lifemonitor/api/models/workflows.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lifemonitor/api/models/workflows.py b/lifemonitor/api/models/workflows.py index 5a7d51412..a85c8d146 100644 --- a/lifemonitor/api/models/workflows.py +++ b/lifemonitor/api/models/workflows.py @@ -148,11 +148,12 @@ def get_user_workflows(cls, owner: User, include_subscriptions=False) -> List[Wo result: List[Workflow] = cls.query.join(Permission)\ .filter(Permission.user_id == owner.id).all() if include_subscriptions: - result.extend(cls.query - .join(Subscription).filter(Subscription.user_id == owner.id and Subscription.resource_id == cls.id) - .filter(cls.public == true()) - .all()) - return list({x.name: x for x in result}.values()) + subscribed_workflows = cls.query\ + .join(Subscription).filter(Subscription.user_id == owner.id and Subscription.resource_id == cls.id) \ + .filter(cls.public == true()).all() + user_wf_ids = [w.uuid for w in result] + result.extend([w for w in subscribed_workflows if w.uuid not in user_wf_ids]) + return result @classmethod def get_public_workflows(cls) -> List[Workflow]: From 97bd83d10bf8d59babedc95ebbc7d17881dd6df7 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 22:14:00 +0100 Subject: [PATCH 10/36] Add tests --- tests/conftest.py | 14 ++++++++++ .../integration/api/controllers/test_users.py | 26 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 027a02985..4fa418224 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -300,6 +300,20 @@ def generic_workflow(app_client): } +@pytest.fixture +def encoded_rocrate_workflow(app_client): + with open('tests/config/data/rocrateBase64.txt') as f: + data = f.read() + return { + 'uuid': str(uuid.uuid4()), + 'version': '1', + 'rocrate': data, + 'name': 'sort-and-change-case', + 'testing_service_type': 'jenkins', + 'authorization': app_client.application.config['WEB_SERVER_AUTH_TOKEN'] + } + + @pytest.fixture def workflow_no_name(app_client): return { diff --git a/tests/integration/api/controllers/test_users.py b/tests/integration/api/controllers/test_users.py index ee0357283..58648018c 100644 --- a/tests/integration/api/controllers/test_users.py +++ b/tests/integration/api/controllers/test_users.py @@ -129,6 +129,32 @@ def test_generic_workflow_registration(app_client, client_auth_method, "Response should be equal to the workflow UUID" +@pytest.mark.parametrize("client_auth_method", [ + ClientAuthenticationMethod.API_KEY, +], indirect=True) +def test_generic_workflow_registration_with_encoded_rocrate( + app_client, client_auth_method, user1, user1_auth, + client_credentials_registry, encoded_rocrate_workflow): + logger.debug("User: %r", user1) + logger.debug("headers: %r", user1_auth) + workflow = encoded_rocrate_workflow + logger.debug("Selected workflow: %r", workflow) + logger.debug("Using oauth2 user: %r", user1) + # prepare body + body = {'rocrate': workflow['rocrate'], + 'version': workflow['version'], + 'uuid': workflow['uuid'], + 'authorization': workflow['authorization']} + logger.debug("The BODY: %r", body) + response = app_client.post('/users/current/workflows', json=body, headers=user1_auth) + logger.debug("The actual response: %r", response.data) + utils.assert_status_code(201, response.status_code) + data = json.loads(response.data) + logger.debug("Response data: %r", data) + assert data['uuid'] == workflow['uuid'] and data['wf_version'] == workflow['version'], \ + "Response should be equal to the workflow UUID" + + @pytest.mark.parametrize("client_auth_method", [ ClientAuthenticationMethod.API_KEY, ClientAuthenticationMethod.AUTHORIZATION_CODE, From e9846d917cb5d6fdf14710a5e08bf0ae703091ff Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 2 Dec 2021 22:15:33 +0100 Subject: [PATCH 11/36] Mount 'data_workflows' volume on compose deployment --- docker-compose.base.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.base.yml b/docker-compose.base.yml index 52ab430ff..1d272872e 100644 --- a/docker-compose.base.yml +++ b/docker-compose.base.yml @@ -40,6 +40,7 @@ services: - "./certs:/certs:ro" - "./instance:/lm/instance:ro" - "./settings.conf:/lm/settings.conf:ro" # default settings + - "data_workflows:/lm/data" networks: - life_monitor @@ -63,6 +64,7 @@ services: - "./certs:/certs:ro" - "./instance:/lm/instance:ro" - "./settings.conf:/lm/settings.conf:ro" # default settings + - "data_workflows:/lm/data" - type: volume source: data_static_files target: /lm/lifemonitor/static @@ -85,6 +87,7 @@ services: - "./certs:/certs:ro" - "./instance:/lm/instance:ro" - "./settings.conf:/lm/settings.conf:ro" # default settings + - "data_workflows:/lm/data" networks: - life_monitor @@ -106,6 +109,7 @@ volumes: data_static_files: data_specs: data_redis: + data_workflows: networks: life_monitor: From ba51bb37dde2ca9215a6a8a5b3cfc97c579f900c Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 10:39:24 +0100 Subject: [PATCH 12/36] Use tmp for data on testing environment --- lifemonitor/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lifemonitor/config.py b/lifemonitor/config.py index 7100f4715..c5318d842 100644 --- a/lifemonitor/config.py +++ b/lifemonitor/config.py @@ -108,6 +108,7 @@ class TestingConfig(BaseConfig): # SQLALCHEMY_DATABASE_URI = "sqlite:///{0}/app-test.db".format(basedir) # CACHE_TYPE = "flask_caching.backends.nullcache.NullCache" CACHE_TYPE = "flask_caching.backends.rediscache.RedisCache" + DATA_WORKFLOWS = "/tmp/lm_tests_data" class TestingSupportConfig(TestingConfig): @@ -115,6 +116,7 @@ class TestingSupportConfig(TestingConfig): DEBUG = True TESTING = False LOG_LEVEL = "DEBUG" + DATA_WORKFLOWS = "/tmp/lm_tests_data" _EXPORT_CONFIGS: List[Type[BaseConfig]] = [ From 6f48dd41342504c0745b5b0ebbff6f9c9d513818 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 11:32:13 +0100 Subject: [PATCH 13/36] Fix missing data required for testing --- tests/config/data/rocrate.base64 | 1 + tests/conftest.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 tests/config/data/rocrate.base64 diff --git a/tests/config/data/rocrate.base64 b/tests/config/data/rocrate.base64 new file mode 100644 index 000000000..f7040b4ad --- /dev/null +++ b/tests/config/data/rocrate.base64 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 4fa418224..a39a57f9e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -302,7 +302,7 @@ def generic_workflow(app_client): @pytest.fixture def encoded_rocrate_workflow(app_client): - with open('tests/config/data/rocrateBase64.txt') as f: + with open('tests/config/data/rocrate.base64') as f: data = f.read() return { 'uuid': str(uuid.uuid4()), From c5cc6c0e83c8ea9721822c6548f178a41c875c02 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 15:17:01 +0100 Subject: [PATCH 14/36] Ignore data folder when building Docker image --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 841d17722..8ce907d8e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,6 +8,7 @@ **/__pycache__ **/.npm *.pyc +data docker/Dockerfile package-lock.json **/node_modules From 4153be382cda3564594b72f599f13b590691e09d Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 15:17:19 +0100 Subject: [PATCH 15/36] Ignore data folder from git repo --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4dd7f30cf..034bc54b5 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ instance *.pyc ./certs **/node_modules +data lifemonitor/static/dist docker-compose.yml utils/certs/data From 55dee8fccbc94c145be2c81d5da94c42ea93f74b Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 15:18:12 +0100 Subject: [PATCH 16/36] Update mount point of data folder --- docker-compose.base.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.base.yml b/docker-compose.base.yml index 1d272872e..0965a24a8 100644 --- a/docker-compose.base.yml +++ b/docker-compose.base.yml @@ -40,7 +40,7 @@ services: - "./certs:/certs:ro" - "./instance:/lm/instance:ro" - "./settings.conf:/lm/settings.conf:ro" # default settings - - "data_workflows:/lm/data" + - "data_workflows:/var/data/lm" networks: - life_monitor @@ -64,7 +64,7 @@ services: - "./certs:/certs:ro" - "./instance:/lm/instance:ro" - "./settings.conf:/lm/settings.conf:ro" # default settings - - "data_workflows:/lm/data" + - "data_workflows:/var/data/lm" - type: volume source: data_static_files target: /lm/lifemonitor/static @@ -87,7 +87,7 @@ services: - "./certs:/certs:ro" - "./instance:/lm/instance:ro" - "./settings.conf:/lm/settings.conf:ro" # default settings - - "data_workflows:/lm/data" + - "data_workflows:/var/data/lm" networks: - life_monitor From 7ea12572c0df0905dcecda82c7f81b31bb52e2fe Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 15:22:24 +0100 Subject: [PATCH 17/36] Update Docker image to prepare data folder --- docker/lifemonitor.Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docker/lifemonitor.Dockerfile b/docker/lifemonitor.Dockerfile index 588997e35..61f6a4040 100644 --- a/docker/lifemonitor.Dockerfile +++ b/docker/lifemonitor.Dockerfile @@ -46,6 +46,12 @@ RUN chmod 755 \ # Set the container entrypoint ENTRYPOINT /usr/local/bin/lm_entrypoint.sh +# Prepare data folder +RUN mkdir -p /var/data/lm \ + && chown -R lm:lm /var/data/lm \ + && ln -s /var/data/lm /lm/data \ + && chown -R lm:lm /lm/data + # Set the default user USER lm From 3bf4f4c4f062306148dc18478595de15e7ef8659 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 15:31:04 +0100 Subject: [PATCH 18/36] Update download method to use local storage --- lifemonitor/api/models/rocrate.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lifemonitor/api/models/rocrate.py b/lifemonitor/api/models/rocrate.py index 868358508..c00f18433 100644 --- a/lifemonitor/api/models/rocrate.py +++ b/lifemonitor/api/models/rocrate.py @@ -135,6 +135,21 @@ def load_metadata(self) -> dict: raise lm_exceptions.NotAuthorizedException(detail=f"Not authorized to download {self.uri}", original_errors=errors) def download(self, target_path: str) -> str: + # load ro-crate if not locally stored + if not self._local_path: + self.load_metadata() + + # report an error if the workflow is not locally available + if self._metadata and not self._local_path: + raise lm_exceptions.DownloadException(detail=f"Unable to find the RO-Crate", status=410) + + tmpdir_path = Path(target_path) + local_zip = download_url(self.local_path, + target_path=(tmpdir_path / 'rocrate.zip').as_posix()) + logger.debug("ZIP Archive: %s", local_zip) + return (tmpdir_path / 'rocrate.zip').as_posix() + + def download_from_source(self, target_path: str) -> str: # report if the workflow is not longer available on the origin server if self._metadata and not check_resource_exists(self.uri, self._get_authorizations()): raise lm_exceptions.DownloadException(detail=f"Not found: {self.uri}", status=410) From 91e5afbbdeaec495a28a3b55bdc63f4fcedefcfe Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Fri, 3 Dec 2021 15:36:42 +0100 Subject: [PATCH 19/36] Fix flake8 issue --- lifemonitor/api/models/rocrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifemonitor/api/models/rocrate.py b/lifemonitor/api/models/rocrate.py index c00f18433..6f512208c 100644 --- a/lifemonitor/api/models/rocrate.py +++ b/lifemonitor/api/models/rocrate.py @@ -141,7 +141,7 @@ def download(self, target_path: str) -> str: # report an error if the workflow is not locally available if self._metadata and not self._local_path: - raise lm_exceptions.DownloadException(detail=f"Unable to find the RO-Crate", status=410) + raise lm_exceptions.DownloadException(detail="RO-Crate unavailable", status=410) tmpdir_path = Path(target_path) local_zip = download_url(self.local_path, From 4712e55e94cd011c6c9ac566903d88a2788f4d66 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Sat, 4 Dec 2021 00:33:20 +0100 Subject: [PATCH 20/36] Fix missing migration to support 'local_path' property --- .../f4cbfe20075f_ro_crate_local_path.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 migrations/versions/f4cbfe20075f_ro_crate_local_path.py diff --git a/migrations/versions/f4cbfe20075f_ro_crate_local_path.py b/migrations/versions/f4cbfe20075f_ro_crate_local_path.py new file mode 100644 index 000000000..30e06e1f4 --- /dev/null +++ b/migrations/versions/f4cbfe20075f_ro_crate_local_path.py @@ -0,0 +1,24 @@ +"""RO-Crate local path + +Revision ID: f4cbfe20075f +Revises: 861eca55901d +Create Date: 2021-12-02 18:09:13.207425 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f4cbfe20075f' +down_revision = '861eca55901d' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('ro_crate', sa.Column('local_path', sa.String(), nullable=True)) + + +def downgrade(): + op.drop_column('ro_crate', 'local_path') From a21e19cb1480b77083c67036bec023d585653aa1 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Sat, 4 Dec 2021 01:35:21 +0100 Subject: [PATCH 21/36] Bump version number to 0.5.0 --- k8s/Chart.yaml | 2 +- lifemonitor/static/src/package.json | 2 +- specs/api.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/k8s/Chart.yaml b/k8s/Chart.yaml index 39c3f761b..cc7dd8615 100644 --- a/k8s/Chart.yaml +++ b/k8s/Chart.yaml @@ -12,7 +12,7 @@ version: 0.4.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. -appVersion: 0.4.3 +appVersion: 0.5.0 # Chart dependencies dependencies: diff --git a/lifemonitor/static/src/package.json b/lifemonitor/static/src/package.json index 78672568c..5d8ae18df 100644 --- a/lifemonitor/static/src/package.json +++ b/lifemonitor/static/src/package.json @@ -1,7 +1,7 @@ { "name": "lifemonitor", "description": "Workflow Testing Service", - "version": "0.4.3", + "version": "0.5.0", "license": "MIT", "author": "CRS4", "main": "../dist/js/lifemonitor.min.js", diff --git a/specs/api.yaml b/specs/api.yaml index 79f21a624..3fce2761d 100644 --- a/specs/api.yaml +++ b/specs/api.yaml @@ -3,7 +3,7 @@ openapi: "3.0.0" info: - version: "0.4.3" + version: "0.5.0" title: "Life Monitor API" description: | *Workflow sustainability service* @@ -18,7 +18,7 @@ info: servers: - url: / description: > - Version 0.4.3 of API. + Version 0.5.0 of API. tags: - name: Registries From ab3dc29a611e7dd8c8ac67fd5d29425d81ed94f5 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 04:33:21 +0100 Subject: [PATCH 22/36] Add RegistryWorkflow model --- lifemonitor/api/models/registries/registry.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lifemonitor/api/models/registries/registry.py b/lifemonitor/api/models/registries/registry.py index af6389ccb..553353517 100644 --- a/lifemonitor/api/models/registries/registry.py +++ b/lifemonitor/api/models/registries/registry.py @@ -41,6 +41,51 @@ logger = logging.getLogger(__name__) +class RegistryWorkflow(object): + _registry: WorkflowRegistry + _identifier: str + _name: str + _latest_version: str + _versions: List[str] = None + + def __init__(self, + registry: WorkflowRegistry, + identifier: str, + name: str, + latest_version: str = None, + versions: List[str] = None) -> None: + self._registry = registry + self._identifier = identifier + self._name = name + self._latest_version = latest_version + if versions: + self._versions = versions.copy() + + @property + def registry(self) -> WorkflowRegistry: + return self._registry + + @property + def identifier(self) -> str: + return self._identifier + + @property + def name(self) -> str: + return self._name + + @property + def latest_version(self) -> str: + return self._latest_version + + @property + def versions(self) -> List[str]: + return self._versions.copy() + + @property + def external_link(self) -> str: + return self._registry.get_external_link(self._identifier, self._latest_version) + + class WorkflowRegistryClient(ABC): client_types = ClassManager('lifemonitor.api.models.registries', class_suffix="WorkflowRegistryClient", skip=["registry"]) From b3ff8d6c662074bfd1ca6c1111df3ef36339e858 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:03:17 +0100 Subject: [PATCH 23/36] Extend RegistryClient interface to expose index of workflows --- lifemonitor/api/models/registries/registry.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lifemonitor/api/models/registries/registry.py b/lifemonitor/api/models/registries/registry.py index 553353517..4aa26238b 100644 --- a/lifemonitor/api/models/registries/registry.py +++ b/lifemonitor/api/models/registries/registry.py @@ -123,6 +123,12 @@ def _get(self, user, *args, **kwargs): response.raise_for_status() return response + def get_index(self, user: auth_models.User) -> List[RegistryWorkflow]: + pass + + def get_index_workflow(self, user: auth_models.User, workflow_identifier: str) -> RegistryWorkflow: + pass + def download_url(self, url, user, target_path=None): return download_url(url, target_path, authorization=f'Bearer {self._get_access_token(user.id)["access_token"]}') From 293a777aac0375a428e31e607f7178b678ac6187 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:04:32 +0100 Subject: [PATCH 24/36] Add implementation of registry index for Seek --- lifemonitor/api/models/registries/seek.py | 26 ++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lifemonitor/api/models/registries/seek.py b/lifemonitor/api/models/registries/seek.py index 723ac30f7..8ab0067ba 100644 --- a/lifemonitor/api/models/registries/seek.py +++ b/lifemonitor/api/models/registries/seek.py @@ -21,13 +21,16 @@ from __future__ import annotations import logging -from typing import Union +from typing import List, Union +import requests from lifemonitor.api import models from lifemonitor.auth.models import User -from lifemonitor.exceptions import EntityNotFoundException +from lifemonitor.exceptions import (EntityNotFoundException, + LifeMonitorException) -from .registry import WorkflowRegistry, WorkflowRegistryClient +from .registry import (RegistryWorkflow, WorkflowRegistry, + WorkflowRegistryClient) # set module level logger logger = logging.getLogger(__name__) @@ -63,6 +66,23 @@ def get_workflow_metadata(self, user, w: Union[models.WorkflowVersion, str]): raise RuntimeError(f"ERROR: unable to get workflow (status code: {r.status_code})") return r.json()['data'] + def get_index(self, user: User) -> List[RegistryWorkflow]: + result = [] + for w in self.get_workflows_metadata(user): + result.append(RegistryWorkflow(self.registry, w['id'], w['attributes']['title'])) + return result + + def get_index_workflow(self, user: User, workflow_identifier: str) -> RegistryWorkflow: + try: + w = self.get_workflow_metadata(user, workflow_identifier) + return RegistryWorkflow(self.registry, w['id'], w['attributes']['title'], + latest_version=w['attributes']['version'], + versions=[_['version'] for _ in w['attributes']['versions']]) if w else None + except requests.exceptions.HTTPError as e: + if e.response.status_code == 404: + raise EntityNotFoundException(WorkflowRegistry, entity_id=workflow_identifier) + raise LifeMonitorException(original_error=e) + def get_external_link(self, external_id: str, version: str) -> str: return f"{self.registry.uri}/workflows/{external_id}?version={version}" From dda895f81791325e377783d70a7722a09419dd3b Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:05:25 +0100 Subject: [PATCH 25/36] Fix external link of seek workflows without version --- lifemonitor/api/models/registries/seek.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lifemonitor/api/models/registries/seek.py b/lifemonitor/api/models/registries/seek.py index 8ab0067ba..73be66249 100644 --- a/lifemonitor/api/models/registries/seek.py +++ b/lifemonitor/api/models/registries/seek.py @@ -84,7 +84,8 @@ def get_index_workflow(self, user: User, workflow_identifier: str) -> RegistryWo raise LifeMonitorException(original_error=e) def get_external_link(self, external_id: str, version: str) -> str: - return f"{self.registry.uri}/workflows/{external_id}?version={version}" + version_param = '' if not version or version == 'latest' else f"?version={version}" + return f"{self.registry.uri}/workflows/{external_id}{version_param}" def get_rocrate_external_link(self, external_id: str, version: str) -> str: return f'{self.registry.uri}/workflows/{external_id}/ro_crate?version={version}' From 57fbd60789f0bff5518f0281fa4fe1207065b9ea Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:08:01 +0100 Subject: [PATCH 26/36] Expose index through the WorkflowRegistry model --- lifemonitor/api/models/registries/registry.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lifemonitor/api/models/registries/registry.py b/lifemonitor/api/models/registries/registry.py index 4aa26238b..9c8b40369 100644 --- a/lifemonitor/api/models/registries/registry.py +++ b/lifemonitor/api/models/registries/registry.py @@ -291,6 +291,12 @@ def get_user_workflows(self, user: auth_models.User) -> List[models.Workflow]: def get_user_workflow_versions(self, user: auth_models.User) -> List[models.WorkflowVersion]: return self.client.filter_by_user(self.registered_workflow_versions, user) + def get_index(self, user: auth_models.User) -> List[RegistryWorkflow]: + return self.client.get_index(user) + + def get_index_workflow(self, user: auth_models.User, workflow_identifier: str) -> RegistryWorkflow: + return self.client.get_index_workflow(user, workflow_identifier) + @classmethod def all(cls) -> List[WorkflowRegistry]: return cls.query.all() From 31c69e55962b84ea210e285fab18f16ebaa8176e Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:11:32 +0100 Subject: [PATCH 27/36] Update specs to introduce support for registry index --- specs/api.yaml | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/specs/api.yaml b/specs/api.yaml index 3fce2761d..f6a058d00 100644 --- a/specs/api.yaml +++ b/specs/api.yaml @@ -83,6 +83,65 @@ paths: "404": $ref: "#/components/responses/NotFound" + /registries/{registry_uuid}/index: + get: + tags: ["Registries"] + x-openapi-router-controller: lifemonitor.api.controllers + operationId: "registry_index" + summary: "Get registry index" + description: "Get the index of workflows available on the registry" + security: + - apiKey: ["user.workflow.read"] + - RegistryCodeFlow: ["user.workflow.read"] + - AuthorizationCodeFlow: ["user.workflow.read"] + parameters: + - $ref: "#/components/parameters/registry_uuid" + responses: + "200": + description: List of workflows on the registry + content: + application/json: + schema: + $ref: "#/components/schemas/ListOfRegistryWorkflows" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthorized" + "403": + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" + + /registries/{registry_uuid}/index/{registry_workflow_identifier}: + get: + tags: ["Registries"] + x-openapi-router-controller: lifemonitor.api.controllers + operationId: "registry_index_workflow" + summary: "Get registry index workflow" + description: "Get information about the specified workflow of the registry index" + security: + - apiKey: ["user.workflow.read"] + - RegistryCodeFlow: ["user.workflow.read"] + - AuthorizationCodeFlow: ["user.workflow.read"] + parameters: + - $ref: "#/components/parameters/registry_uuid" + - $ref: "#/components/parameters/registry_workflow_identifier" + responses: + "200": + description: List of workflows on the registry + content: + application/json: + schema: + $ref: "#/components/schemas/RegistryWorkflow" + "400": + $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthorized" + "403": + $ref: "#/components/responses/Forbidden" + "404": + $ref: "#/components/responses/NotFound" + /users/current: get: tags: ["Users"] @@ -1118,6 +1177,14 @@ components: type: string required: true example: aa16c6a9-571f-4a62-976f-60ea514ad2c1 + registry_workflow_identifier: + name: "registry_workflow_identifier" + description: "Identifier of the workflow on the registry" + in: path + schema: + type: string + required: true + example: 123e4567-e89b-12d3-a456-426614174000 user_id: name: "user_id" description: "Registry user's identifier" @@ -1547,6 +1614,48 @@ components: # (e.g., `authorization: "ApiKey 1234567890"`). # example: "Bearer xxx__ZRBhqf9eeRasjqMw90pgEeMpTZ7__" + RegistryWorkflowBase: + allOf: + - $ref: "#/components/schemas/WorkflowBase" + - type: object + description: Registry workflow + properties: + identifier: + type: string + description: | + The identifier of the workflow on the registry + example: 148 + registry: + description: + $ref: "#/components/schemas/Registry" + + RegistryWorkflow: + allOf: + - $ref: "#/components/schemas/RegistryWorkflowBase" + - type: object + description: Registry workflow + properties: + latest_version: + type: string + description: The workflow identifier on the registry + example: '1.0' + versions: + description: The list of workflow versions + type: array + items: + type: string + example: ['1.0', "1.0-dev"] + + ListOfRegistryWorkflows: + type: object + properties: + items: + type: array + items: + $ref: "#/components/schemas/RegistryWorkflowBase" + required: + - items + WorkflowVersionBase: allOf: - $ref: "#/components/schemas/WorkflowBase" From c2ca4aba7ef97f41c9221e121c17e8552e619d16 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:12:50 +0100 Subject: [PATCH 28/36] Extend controller with methods to support registry index --- lifemonitor/api/controllers.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lifemonitor/api/controllers.py b/lifemonitor/api/controllers.py index 5bcbbc7f0..097e66c29 100644 --- a/lifemonitor/api/controllers.py +++ b/lifemonitor/api/controllers.py @@ -64,6 +64,35 @@ def workflow_registries_get_by_uuid(registry_uuid): return serializers.WorkflowRegistrySchema().dump(registry) +@authorized +@cached(timeout=Timeout.REQUEST) +def registry_index(registry_uuid): + if not current_user: + return lm_exceptions.report_problem(401, "Unauthorized") + registry = lm.get_workflow_registry_by_uuid(registry_uuid) + if not registry: + return lm_exceptions.report_problem(404, "Not Found", + detail=messages.no_registry_found.format(registry_uuid)) + workflows = registry.get_index(current_user) + return serializers.ListOfRegistryIndexItemsSchema().dump(workflows) + + +@authorized +@cached(timeout=Timeout.REQUEST) +def registry_index_workflow(registry_uuid, registry_workflow_identifier): + if not current_user: + return lm_exceptions.report_problem(401, "Unauthorized") + registry = lm.get_workflow_registry_by_uuid(registry_uuid) + if not registry: + return lm_exceptions.report_problem(404, "Not Found", + detail=messages.no_registry_found.format(registry_uuid)) + workflow = registry.get_index_workflow(current_user, registry_workflow_identifier) + if not workflow: + return lm_exceptions.report_problem(404, "Not Found", + detail=messages.workflow_not_found.format(registry_workflow_identifier, 'latest')) + return serializers.RegistryIndexItemSchema().dump(workflow) + + @authorized @cached(timeout=Timeout.REQUEST) def workflow_registries_get_current(): From d8d1aa4c0dbb2e3d39b9d5948a30e4e9b15820a1 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:13:42 +0100 Subject: [PATCH 29/36] Expose RegistryWorkflow model --- lifemonitor/api/models/__init__.py | 3 ++- lifemonitor/api/models/registries/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lifemonitor/api/models/__init__.py b/lifemonitor/api/models/__init__.py index db4af2084..a3a299ac3 100644 --- a/lifemonitor/api/models/__init__.py +++ b/lifemonitor/api/models/__init__.py @@ -30,7 +30,7 @@ from .status import Status, AggregateTestStatus, WorkflowStatus, SuiteStatus # 'registries' package -from .registries import WorkflowRegistry, WorkflowRegistryClient +from .registries import RegistryWorkflow, WorkflowRegistry, WorkflowRegistryClient # 'workflows' package from .workflows import Workflow, WorkflowVersion @@ -72,6 +72,7 @@ "WorkflowRegistryClient", "WorkflowStatus", "WorkflowVersion", + "RegistryWorkflow" ] # set module level logger diff --git a/lifemonitor/api/models/registries/__init__.py b/lifemonitor/api/models/registries/__init__.py index 686583215..b2400778c 100644 --- a/lifemonitor/api/models/registries/__init__.py +++ b/lifemonitor/api/models/registries/__init__.py @@ -21,9 +21,9 @@ from __future__ import annotations from lifemonitor.utils import ClassManager -from .registry import WorkflowRegistry, WorkflowRegistryClient +from .registry import RegistryWorkflow, WorkflowRegistry, WorkflowRegistryClient -__all__ = [WorkflowRegistry, WorkflowRegistryClient] + \ +__all__ = [RegistryWorkflow, WorkflowRegistry, WorkflowRegistryClient] + \ ClassManager('lifemonitor.api.models.registries', class_suffix="WorkflowRegistry", skip=["registry"], lazy=False).get_classes() From b6bf9ca1246d0844c521722e91a2e0e44d361538 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Thu, 16 Dec 2021 05:37:04 +0100 Subject: [PATCH 30/36] Add schemas to serialise the RegistryWorkflow model --- lifemonitor/api/serializers.py | 37 +++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/lifemonitor/api/serializers.py b/lifemonitor/api/serializers.py index 32f7cb945..0162ec5da 100644 --- a/lifemonitor/api/serializers.py +++ b/lifemonitor/api/serializers.py @@ -59,6 +59,41 @@ class ListOfWorkflowRegistriesSchema(ListOfItems): __item_scheme__ = WorkflowRegistrySchema +class RegistryIndexItemSchema(ResourceMetadataSchema): + __envelope__ = {"single": None, "many": "items"} + __model__ = models.RegistryWorkflow + + class Meta: + model = models.RegistryWorkflow + + identifier = fields.String(attribute="identifier") + name = fields.String(attribute="name") + latest_version = fields.String(attribute="latest_version") + versions = fields.List(fields.String, attribute="versions") + registry = ma.Nested(WorkflowRegistrySchema(exclude=('meta', 'links')), attribute="registry") + links = fields.Method('get_links') + + def get_links(self, obj): + links = ResourceMetadataSchema.get_links(self, obj) + if links is not None: + links['origin'] = obj.external_link + return links + return { + 'origin': obj.external_link + } + + @post_dump + def remove_skip_values(self, data, **kwargs): + return { + key: value for key, value in data.items() + if value is not None + } + + +class ListOfRegistryIndexItemsSchema(ListOfItems): + __item_scheme__ = RegistryIndexItemSchema + + class WorkflowSchema(ResourceMetadataSchema): __envelope__ = {"single": None, "many": "items"} __model__ = models.WorkflowVersion @@ -273,7 +308,7 @@ def format_availability_issues(status: models.WorkflowStatus): issues = status.availability_issues logger.info(issues) if 'not_available' == status.aggregated_status and len(issues) > 0: - return ', '.join([f"{i['issue']}: Unable to get resource '{i['resource']}' from service '{i['service']}'" if 'service' in i else i['issue'] for i in issues]) + return ', '.join([f"{i['issue']}: Unable to get resource '{i['resource']}' from service '{i['service']}'" if 'service' in i and 'resource' in i else i['issue'] for i in issues]) return None From 36053d2e2c8acbdad9ac773835eb56af3266593a Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Wed, 22 Dec 2021 16:08:57 +0100 Subject: [PATCH 31/36] Add definition of PVC to store workflows --- k8s/pvc-backend-data.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 k8s/pvc-backend-data.yaml diff --git a/k8s/pvc-backend-data.yaml b/k8s/pvc-backend-data.yaml new file mode 100644 index 000000000..17db9368c --- /dev/null +++ b/k8s/pvc-backend-data.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: data-api-workflows +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi From a20bb0bff0e2679dfc81a3277f9033e71b3321db Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Wed, 22 Dec 2021 16:09:30 +0100 Subject: [PATCH 32/36] Connect PVC to pods --- k8s/templates/_helpers.tpl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/k8s/templates/_helpers.tpl b/k8s/templates/_helpers.tpl index 40f949c38..3a178f222 100644 --- a/k8s/templates/_helpers.tpl +++ b/k8s/templates/_helpers.tpl @@ -110,6 +110,9 @@ Define volumes shared by some pods. - name: lifemonitor-settings secret: secretName: {{ include "chart.fullname" . }}-settings +- name: lifemonitor-data + persistentVolumeClaim: + claimName: data-{{- .Release.Name -}}-workflows {{- end -}} {{/* @@ -122,4 +125,6 @@ Define mount points shared by some pods. - name: lifemonitor-settings mountPath: "/lm/settings.conf" subPath: settings.conf +- name: lifemonitor-data + mountPath: "/var/data/lm" {{- end -}} From b72801b66a02da9e45213f1ee9c8fd43e273d18e Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Wed, 22 Dec 2021 16:11:09 +0100 Subject: [PATCH 33/36] Update labels of init job --- k8s/templates/job-init.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/k8s/templates/job-init.yaml b/k8s/templates/job-init.yaml index a20595777..cb554301e 100644 --- a/k8s/templates/job-init.yaml +++ b/k8s/templates/job-init.yaml @@ -3,7 +3,9 @@ kind: Job metadata: name: {{ include "chart.fullname" . }}-init labels: - {{- include "chart.labels" . | nindent 4 }} + app.kubernetes.io/name: {{ include "chart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} spec: template: spec: From af14ac18f8f9bfa5358e1b15d5d514734336a2e5 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Wed, 22 Dec 2021 16:11:38 +0100 Subject: [PATCH 34/36] Update default values --- k8s/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/k8s/values.yaml b/k8s/values.yaml index 07683f742..151902555 100644 --- a/k8s/values.yaml +++ b/k8s/values.yaml @@ -107,6 +107,7 @@ lifemonitor: persistence: storageClass: *storageClass + storageSize: 8Gi # Enable/Disable the pod to test connection to the LifeMonitor back-end enableTestConnection: false From 249a9613679570a2b831d5bf073518e7d5a22776 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Wed, 22 Dec 2021 16:12:47 +0100 Subject: [PATCH 35/36] Update Chart.lock --- k8s/Chart.lock | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/k8s/Chart.lock b/k8s/Chart.lock index 169adc771..cfad0e39f 100644 --- a/k8s/Chart.lock +++ b/k8s/Chart.lock @@ -5,5 +5,8 @@ dependencies: - name: postgresql repository: https://charts.bitnami.com/bitnami version: 10.1.1 -digest: sha256:386060b432509d7925e2d620559d44d0efbe869184049da1fc12cfd86b0b5550 -generated: "2021-04-25T15:26:03.079993489Z" +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 15.3.2 +digest: sha256:e69b28d1eb2d1b5e7fef36eb02b99cf305f52af14e4d2bda033eaf7544ef498b +generated: "2021-10-21T16:46:24.046062+02:00" From 16ed3d219f04b2d1a3001632a853a55d1fddcf15 Mon Sep 17 00:00:00 2001 From: Marco Enrico Piras Date: Wed, 22 Dec 2021 16:13:25 +0100 Subject: [PATCH 36/36] Bump chart version --- k8s/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/Chart.yaml b/k8s/Chart.yaml index cc7dd8615..49776cf43 100644 --- a/k8s/Chart.yaml +++ b/k8s/Chart.yaml @@ -7,7 +7,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.0 +version: 0.5.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to