Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add full support for service info fields #80

Merged
merged 2 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions bla

Large diffs are not rendered by default.

92 changes: 92 additions & 0 deletions pro_wes/api/additions.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,101 @@ paths:
$ref: "#/components/schemas/ErrorResponse"
components:
schemas:
# `Service` and `ServiceType` schemas copied over from Service Info API specs
# workaround for Connexion problem preventing the resolving of nested references
# in `ServiceInfoRegister` in `POST request
Service:
description: "GA4GH service"
type: object
required:
- id
- name
- type
- organization
- version
properties:
id:
type: string
description: "Unique ID of this service. Reverse domain name notation is recommended, though not required. The identifier should attempt to be globally unique so it can be used in downstream aggregator services e.g. Service Registry."
example: "org.ga4gh.myservice"
name:
type: string
description: "Name of this service. Should be human readable."
example: "My project"
type:
$ref: "#/components/schemas/ServiceType"
description:
type: string
description: "Description of the service. Should be human readable and provide information about the service."
example: "This service provides..."
organization:
type: object
description: "Organization providing the service"
required:
- name
- url
properties:
name:
type: string
description: "Name of the organization responsible for the service"
example: "My organization"
url:
type: string
format: uri
description: "URL of the website of the organization (RFC 3986 format)"
example: "https://example.com"
contactUrl:
type: string
format: uri
description: "URL of the contact for the provider of this service, e.g. a link to a contact form (RFC 3986 format), or an email (RFC 2368 format)."
example: "mailto:[email protected]"
documentationUrl:
type: string
format: uri
description: "URL of the documentation of this service (RFC 3986 format). This should help someone learn how to use your service, including any specifics required to access data, e.g. authentication."
example: "https://docs.myservice.example.com"
createdAt:
type: string
format: date-time
description: "Timestamp describing when the service was first deployed and available (RFC 3339 format)"
example: "2019-06-04T12:58:19Z"
updatedAt:
type: string
format: date-time
description: "Timestamp describing when the service was last updated (RFC 3339 format)"
example: "2019-06-04T12:58:19Z"
environment:
type: string
description: "Environment the service is running in. Use this to distinguish between production, development and testing/staging deployments. Suggested values are prod, test, dev, staging. However this is advised and not enforced."
example: "test"
version:
type: string
description: "Version of the service being described. Semantic versioning is recommended, but other identifiers, such as dates or commit hashes, are also allowed. The version should be changed whenever the service is updated."
example: "1.0.0"
ServiceType:
description: "Type of a GA4GH service"
type: object
required:
- group
- artifact
- version
properties:
group:
type: string
description: "Namespace in reverse domain name format. Use `org.ga4gh` for implementations compliant with official GA4GH specifications. For services with custom APIs not standardized by GA4GH, or implementations diverging from official GA4GH specifications, use a different namespace (e.g. your organization's reverse domain name)."
example: "org.ga4gh"
artifact:
type: string
description: "Name of the API or GA4GH specification implemented. Official GA4GH types should be assigned as part of standards approval process. Custom artifacts are supported."
example: "beacon"
version:
type: string
description: "Version of the API or specification. GA4GH specifications use semantic versioning."
example: "1.0.0"
ServiceInfoRegister:
title: ServiceInfoRegister
allOf:
# - $ref: "#/components/schemas/Service"
- type: object
properties:
workflow_type_versions:
Expand Down
29 changes: 24 additions & 5 deletions pro_wes/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,33 @@ custom:
list_runs:
default_page_size: 5
service_info:
auth_instructions_url: "https://www.elixir-europe.org/services/compute/aai"
auth_instructions_url: "https://example.org/auth_instructions"
default_workflow_engine_parameters: []
id: v1.wes.ga4gh.org.example
name: "proWES example deployment"
supported_filesystem_protocols:
- http
- https
supported_wes_versions:
- 1.0.0
- 1.0.1
tags:
key: "value"
type:
group: "org.ga4gh"
artifact: "wes"
version: "1.0.1"
workflow_engine_versions:
cwl-engine: "1.2.3"
workflow_type_versions:
CWL:
workflow_type_version:
- v1.0
tags:
service_repo: https://github.com/elixir-europe/proWES
description: "WES gateway service"
organization:
name: "Example organization"
url: "https://example.org"
contactUrl: "[email protected]"
documentationUrl: "https://example.org/docs"
createdAt: "2020-01-01T00:00:00Z"
updatedAt: "2022-12-31T00:00:00Z"
environment: "test"
version: "0.18.0"
61 changes: 4 additions & 57 deletions pro_wes/config_models.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
"""Custom app config models."""

from typing import Dict, List, Optional
from typing import Optional
from pathlib import Path

from pydantic import AnyUrl, BaseModel # pylint: disable=no-name-in-module
from pydantic import BaseModel # pylint: disable=no-name-in-module

from pro_wes.ga4gh.wes.models import (
DefaultWorkflowEngineParameter,
ServiceInfoBase,
WorkflowTypeVersion,
)
from pro_wes.ga4gh.wes.models import ServiceInfoBase as ServiceInfo

# pragma pylint: disable=too-few-public-methods

Expand Down Expand Up @@ -72,55 +68,6 @@ class ListRuns(BaseModel):
default_page_size: int = 5


class ServiceInfo(ServiceInfoBase):
"""Model for initial service info configuration.

Args:
workflow_type_versions: Workflow types and versions supported by this
service.
supported_wes_versions: The version(s) of the WES schema supported by
this service.
supported_filesystem_protocols: The filesystem protocols supported by
this service.
workflow_engine_versions: Workflow engine versions supported by this
service.
default_workflow_engine_parameters: Default workflow engine parameters
set by this service.
auth_instructions_url: URL to web page with human-readable instructions
on how to get an authorization token for use with this service.
tags: Additional information about this service as key-value pairs.

Attributes:
workflow_type_versions: Workflow types and versions supported by this
service.
supported_wes_versions: The version(s) of the WES schema supported by
this service.
supported_filesystem_protocols: The filesystem protocols supported by
this service.
workflow_engine_versions: Workflow engine versions supported by this
service.
default_workflow_engine_parameters: Default workflow engine parameters
set by this service.
auth_instructions_url: URL to web page with human-readable instructions
on how to get an authorization token for use with this service.
tags: Additional information about this service as key-value pairs.
"""

workflow_type_versions: Dict[str, WorkflowTypeVersion] = {
"CWL": WorkflowTypeVersion(workflow_type_version=["v1.0"]),
}
supported_wes_versions: List[str] = [
"1.0.0",
]
supported_filesystem_protocols: List[str] = [
"http",
]
workflow_engine_versions: Dict[str, str] = {}
default_workflow_engine_parameters: List[DefaultWorkflowEngineParameter] = []
auth_instructions_url: AnyUrl = "https://lifescience-ri.eu/ls-login/"
tags: Dict[str, str] = {"service_repo": "https://github.com/elixir-europe/proWES"}


class CustomConfig(BaseModel):
"""Custom app configuration.

Expand All @@ -142,4 +89,4 @@ class CustomConfig(BaseModel):
defaults: Defaults = Defaults()
post_runs: PostRuns = PostRuns()
list_runs: ListRuns = ListRuns()
service_info: ServiceInfo = ServiceInfo()
service_info: ServiceInfo
1 change: 1 addition & 0 deletions pro_wes/ga4gh/service_info/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""GA4GH Service Info API subpackage."""
86 changes: 86 additions & 0 deletions pro_wes/ga4gh/service_info/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""proWES schema models."""

from datetime import datetime
from typing import Optional, Union

from pydantic import AnyUrl, BaseModel, EmailStr # pylint: disable=no-name-in-module


# pragma pylint: disable=too-few-public-methods


class Organization(BaseModel):
"""Model for organization implementing GA4GH services.

Attributes:
name: Name of the organization responsible for the service.
url: URL of the website of the organization (RFC 3986 format).
"""

name: str
url: AnyUrl


class ServiceType(BaseModel):
"""Model for GA4GH service type.

Attributes:
group: Namespace in reverse domain name format. Use `org.ga4gh` for
implementations compliant with official GA4GH specifications. For services
with custom APIs not standardized by GA4GH, or implementations diverging
from official GA4GH specifications, use a different namespace (e.g. your
organization's reverse domain name).
artifact: Name of the API or GA4GH specification implemented. Official GA4GH
types should be assigned as part of standards approval process. Custom
artifacts are supported.
version: Version of the API or specification. GA4GH specifications use
semantic versioning.
"""

group: str
artifact: str
version: str


class Service(BaseModel):
"""Model for GA4GH service.

Attributes:
id: Unique ID of this service. Reverse domain name notation is recommended,
though not required. The identifier should attempt to be globally unique so
it can be used in downstream aggregator services e.g. Service Registry.
name: Name of this service. Should be human readable.
type: Type of this service.
description: Description of the service. Should be human readable and provide
information about the service.
organization: Organization providing the service.
contactUrl: URL of the contact for the provider of this service, e.g. a link
to a contact form (RFC 3986 format), or an email (RFC 2368 format).
documentationUrl: URL of the documentation of this service (RFC 3986 format).
This should help someone learn how to use your service, including any
specifics required to access data, e.g. authentication.
createdAt: Timestamp describing when the service was first deployed and
available (RFC 3339 format).
updatedAt: Timestamp describing when the service was last updated (RFC 3339
format).
environment: Environment the service is running in. Use this to distinguish
between production, development and testing/staging deployments. Suggested
values are prod, test, dev, staging. However this is advised and not
enforced.
version: Version of the service being described. Semantic versioning is
recommended, but other identifiers, such as dates or commit hashes, are
also allowed. The version should be changed whenever the service is
updated.
"""

id: str
name: str
type: ServiceType
description: Optional[str]
organization: Organization
contactUrl: Optional[Union[AnyUrl, EmailStr]]
documentationUrl: Optional[AnyUrl]
createdAt: Optional[datetime]
updatedAt: Optional[datetime]
environment: Optional[str]
version: str
1 change: 1 addition & 0 deletions pro_wes/ga4gh/wes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""GA4GH WES API subpackage."""
7 changes: 4 additions & 3 deletions pro_wes/ga4gh/wes/controllers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Controller for GA4GH WES API endpoints."""

import logging
from typing import Dict, Literal, Tuple
from typing import Dict, Literal, Optional, Tuple

from connexion import request
from foca.utils.logging import log_traffic
Expand Down Expand Up @@ -29,7 +29,7 @@ def GetServiceInfo() -> Dict:


@log_traffic
def PostServiceInfo(**kwargs) -> Tuple[None, Literal["201"]]:
def PostServiceInfo(**kwargs) -> Tuple[None, Literal["201"], Optional[dict[str, str]]]:
"""Set information about this service.

Controller for `POST /service-info`.
Expand All @@ -42,7 +42,8 @@ def PostServiceInfo(**kwargs) -> Tuple[None, Literal["201"]]:
"""
service_info = ServiceInfo()
service_info.set_service_info(data=request.json)
return (None, "201")
headers = None
return (None, "201", headers)


@log_traffic
Expand Down
9 changes: 7 additions & 2 deletions pro_wes/ga4gh/wes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
)

from pro_wes.exceptions import NoSuitableEngine
from pro_wes.ga4gh.service_info.models import Service
from pro_wes.ga4gh.wes.service_info import ServiceInfo as ServiceInfoController

# pragma pylint: disable=too-few-public-methods
Expand Down Expand Up @@ -455,8 +456,8 @@ class DefaultWorkflowEngineParameter(BaseModel):
default_value: Optional[str]


class ServiceInfoBase(BaseModel):
"""Base model for service info.
class ServiceInfoWesBase(BaseModel):
"""Base model for WES-specific service info fields.

Args:
workflow_type_versions: Workflow types and versions supported by this
Expand Down Expand Up @@ -498,6 +499,10 @@ class ServiceInfoBase(BaseModel):
tags: Dict[str, str]


class ServiceInfoBase(ServiceInfoWesBase, Service):
"""Based model for service info."""


class ServiceInfo(ServiceInfoBase):
"""Full model for service info.

Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
connexion<3
email-validator>=2.1.0,<3
foca>=0.12.1
gunicorn>=20.1.0,<21