Skip to content

Commit 84dfc46

Browse files
committed
merge
2 parents 009ca53 + 1de3bc2 commit 84dfc46

9 files changed

Lines changed: 155 additions & 25 deletions

File tree

.safety-policy.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ security:
2525
70624:
2626
reason: 'No fix available.'
2727
expires: '2025-5-27'
28+
71595:
29+
reason: 'Foca needs to update werkzeug to >=2.3.8.'
30+
expires: '2025-7-21'
31+
71594:
32+
reason: 'Foca needs to update werkzeug to >=3.0.3.'
33+
expires: '2025-7-21'
34+
71636:
35+
reason: 'Foca needs to update authlib to >=1.3.0.'
36+
expires: '2025-7-21'
2837

2938
report:
3039
dependency-vulnerabilities:

deployment/config.yaml

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Server configuration
77
# Cf. https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.ServerConfig
88
server:
9-
host: "0.0.0.0"
9+
host: '0.0.0.0'
1010
port: 8080
1111
debug: True
1212
environment: development
@@ -48,7 +48,31 @@ api:
4848
swagger_ui: True
4949
serve_spec: True
5050

51+
# Custom configuration
52+
# Cf. https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.CustomConfig
5153
custom:
54+
# ServiceInfo configuration based on ServiceInfo model
55+
service_info:
56+
id: org.ga4gh.myservice
57+
name: TESK
58+
type:
59+
group: org.ga4gh
60+
artifact: tes
61+
version: 1.1.0
62+
description: TES on Kubernetes
63+
organization:
64+
name: My organization
65+
url: https://example.com
66+
contactUrl: mailto:support@example.com
67+
documentationUrl: https://docs.myservice.example.com
68+
createdAt: '2019-06-04T12:58:19Z'
69+
updatedAt: '2019-06-04T12:58:19Z'
70+
environment: test
71+
version: 1.0.0
72+
tesResources_backend_parameters:
73+
- VmSize
74+
- ParamToRecogniseDataComingFromConfig
75+
# Taskmaster configuration
5276
taskmaster_template:
5377
apiVersion: batch/v1
5478
kind: Job
@@ -96,6 +120,7 @@ custom:
96120
fieldRef:
97121
fieldPath: metadata.labels
98122
restartPolicy: Never
123+
# Taskmaster environment properties
99124
taskmaster_env_properties:
100125
# Taskmaster image name
101126
imageName: docker.io/elixircloud/tesk-core-taskmaster
@@ -128,8 +153,8 @@ log:
128153
formatters:
129154
standard:
130155
class: logging.Formatter
131-
style: "{"
132-
format: "[{asctime}: {levelname:<8}] {message} [{name}]"
156+
style: '{'
157+
format: '[{asctime}: {levelname:<8}] {message} [{name}]'
133158
handlers:
134159
console:
135160
class: logging.StreamHandler
@@ -143,9 +168,9 @@ log:
143168
# Exception configuration
144169
# Cf. https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.ExceptionConfig
145170
exceptions:
146-
required_members: [['detail'], ['status'], ['title']]
147-
status_member: ['status']
148-
exceptions: tesk.exceptions.exceptions
171+
required_members: [['detail'], ['status'], ['title']]
172+
status_member: ['status']
173+
exceptions: tesk.exceptions.exceptions
149174

150175
storeLogs:
151176
execution_trace: True

poetry.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ foca = "^0.13.0"
3333
kubernetes = "^30.1.0"
3434
python = "^3.11"
3535
requests = ">=2.20.0"
36-
urllib3 = "^2.2.1"
36+
urllib3 = "^2.2.2"
3737

3838
[tool.poetry.group.docs.dependencies]
3939
added-value = "^0.24.0"

tesk/api/ga4gh/tes/controllers.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
from foca.utils.logging import log_traffic # type: ignore
66

7-
from tesk.api.kubernetes.template import KubernetesTemplateSupplier
87
from tesk.api.ga4gh.tes.models import TesTask
9-
from tesk.utils import get_custom_config
8+
from tesk.api.ga4gh.tes.service_info.service_info import ServiceInfo
109
from tesk.api.kubernetes.converter import TesKubernetesConverter
10+
from tesk.api.kubernetes.template import KubernetesTemplateSupplier
1111
from tesk.exceptions import BadRequest, InternalServerError
12-
# from tesk.api.ga4gh.tes.task.create_task import CreateTask as TaskCreater
12+
from tesk.utils import get_custom_config
1313

1414
# Get logger instance
1515
logger = logging.getLogger(__name__)
@@ -48,14 +48,10 @@ def CreateTask(**kwargs) -> dict: # type: ignore
4848

4949
# GET /tasks/service-info
5050
@log_traffic
51-
def GetServiceInfo(*args, **kwargs) -> dict: # type: ignore
52-
"""Get service info.
53-
54-
Args:
55-
*args: Variable length argument list.
56-
**kwargs: Arbitrary keyword arguments.
57-
"""
58-
pass
51+
def GetServiceInfo() -> dict: # type: ignore
52+
"""Get service info."""
53+
service_info = ServiceInfo()
54+
return service_info.response()
5955

6056

6157
# GET /tasks

tesk/api/ga4gh/tes/models.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class TesExecutor(BaseModel):
8686
example={"BLASTDB": "/data/GRC38", "HMMERDB": "/data/hmmer"},
8787
)
8888
ignore_error: Optional[bool] = Field(
89-
default=False,
89+
default=None,
9090
description="Default behavior of running an array of executors is that "
9191
"execution\nstops on the first error. If `ignore_error` is `True`, then "
9292
"the\nrunner will record error exit codes, but will continue on to the "
@@ -154,7 +154,7 @@ class TesInput(BaseModel):
154154
description="Path of the file inside the container.\nMust be an absolute path.",
155155
example="/data/file1",
156156
)
157-
type: Optional[TesFileType] = Field(default=TesFileType.FILE)
157+
type: Optional[TesFileType] = TesFileType.FILE
158158
content: Optional[str] = Field(
159159
default=None,
160160
description="File content literal.\n\nImplementations should support a minimum "
@@ -337,9 +337,9 @@ class Service(BaseModel):
337337
id: str = Field(
338338
...,
339339
description="Unique ID of this service. Reverse domain name notation is "
340-
"recommended, though not required. The identifier should attempt to be globally"
341-
" unique so it can be used in downstream aggregator services e.g. Service "
342-
"Registry.",
340+
"recommended, though not required. The identifier should attempt to be "
341+
"globally unique so it can be used in downstream aggregator services e.g. "
342+
"Service Registry.",
343343
example="org.ga4gh.myservice",
344344
)
345345
name: str = Field(
@@ -357,7 +357,7 @@ class Service(BaseModel):
357357
organization: Organization = Field(
358358
..., description="Organization providing the service"
359359
)
360-
contactUrl: Optional[AnyUrl] = Field(
360+
contactUrl: Optional[str] = Field(
361361
default=None,
362362
description="URL of the contact for the provider of this service, e.g. a link "
363363
"to a contact form (RFC 3986 format), or an email (RFC 2368 format).",
@@ -486,7 +486,7 @@ class TesTask(BaseModel):
486486
description="Task identifier assigned by the server.",
487487
example="job-0012345",
488488
)
489-
state: Optional[TesState] = Field(default=TesState.UNKNOWN)
489+
state: Optional[TesState] = TesState.UNKNOWN
490490
name: Optional[str] = Field(None, description="User-provided task name.")
491491
description: Optional[str] = Field(
492492
default=None,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Package for the TES Service Info endpoint."""
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""Service info for TES API."""
2+
3+
import json
4+
import logging
5+
from typing import Any, Optional
6+
7+
from foca import Foca
8+
from pydantic import AnyUrl
9+
10+
from tesk.api.ga4gh.tes.models import (
11+
Artifact,
12+
Organization,
13+
TesServiceInfo,
14+
TesServiceType,
15+
)
16+
from tesk.exceptions import ConfigNotFoundError
17+
from tesk.utils import get_config_path
18+
19+
logger = logging.getLogger(__name__)
20+
21+
22+
class ServiceInfo:
23+
"""Service info for TES API."""
24+
25+
def __init__(self) -> None:
26+
"""Initializes the BaseServiceInfoRequest class."""
27+
self.service_info: Optional[TesServiceInfo] = None
28+
self.config = Foca(config_file=get_config_path()).conf
29+
30+
def get_default_service_info(self) -> TesServiceInfo:
31+
"""Get the default service info.
32+
33+
if service info is not provided in the config,
34+
this method will return the default service info.
35+
36+
Returns:
37+
TesServiceInfo: Default service info.
38+
"""
39+
logger.warning("Service info not found in config. Using default service info.")
40+
return TesServiceInfo(
41+
id="org.ga4gh.tes",
42+
name="TES",
43+
type=TesServiceType(
44+
group="org.ga4gh",
45+
artifact=Artifact.tes,
46+
version="1.1.0",
47+
),
48+
organization=Organization(
49+
name="my_organization",
50+
url=AnyUrl("https://example.com"),
51+
),
52+
version="1.0.0",
53+
)
54+
55+
def get_service_info_from_config(self) -> TesServiceInfo:
56+
"""Returns service info from config.
57+
58+
Returns:
59+
TesServiceInfo: Service info from config.
60+
61+
Raises:
62+
ConfigNotFoundError: If custom config or part of it is not found
63+
in the config file.
64+
"""
65+
if not self.config.custom:
66+
raise ConfigNotFoundError("Custom configuration not found.")
67+
68+
service_info_data = self.config.custom.get("service_info")
69+
if not service_info_data:
70+
raise ConfigNotFoundError("Service info not found in custom configuration.")
71+
72+
try:
73+
service_info = TesServiceInfo(**service_info_data)
74+
except TypeError as e:
75+
logging.error(f"Exception occurred: {e}")
76+
raise ConfigNotFoundError(f"Invalid service info format: {e}") from None
77+
78+
return service_info
79+
80+
def response(self) -> dict[str, Any]:
81+
"""Returns serialized response for /service-info.
82+
83+
Returns:
84+
dict: Serialized response.
85+
"""
86+
if self.service_info is None:
87+
try:
88+
self.service_info = self.get_service_info_from_config()
89+
except ConfigNotFoundError:
90+
self.service_info = self.get_default_service_info()
91+
92+
return dict(json.loads(self.service_info.json()))

tesk/custom_config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from pydantic import BaseModel, Field
66

7+
from tesk.api.ga4gh.tes.models import Service
78
from tesk.constants import TeskConstants
89

910

@@ -151,5 +152,7 @@ class Job(BaseModel):
151152
class CustomConfig(BaseModel):
152153
"""Custom configuration model for the FOCA app."""
153154

155+
# Define custom configuration fields here
156+
service_info: Service
154157
taskmaster_template: Job # This is Pydantic model for V1Job
155158
taskmaster_env_properties: TaskmasterEnvProperties

0 commit comments

Comments
 (0)