Skip to content

Commit a3e2cc2

Browse files
authored
feat: set taskmaster manifest from FOCA config (#206)
1 parent 5d385ba commit a3e2cc2

File tree

5 files changed

+244
-48
lines changed

5 files changed

+244
-48
lines changed

deployment/config.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,25 @@ custom:
7272
tesResources_backend_parameters:
7373
- VmSize
7474
- ParamToRecogniseDataComingFromConfig
75+
taskmaster:
76+
imageName: docker.io/elixircloud/tesk-core-taskmaster
77+
imageVersion: v0.10.2
78+
filerImageName: docker.io/elixircloud/tesk-core-filer
79+
filerImageVersion: v0.10.2
80+
ftp:
81+
# Name of the secret with FTP account credentials
82+
secretName: account-secret
83+
# If FTP account enabled (based on non-emptiness of secretName)
84+
enabled: true
85+
# If verbose (debug) mode of taskmaster is on (passes additional flag to taskmaster and sets image pull policy to Always)
86+
debug: false
87+
# Environment variables, that will be passed to taskmaster
88+
environment:
89+
key: value
90+
# Service Account name for taskmaster
91+
serviceAccountName: taskmaster
92+
filerBackoffLimit: 2
93+
executorBackoffLimit: 2
7594

7695
# Logging configuration
7796
# Cf. https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.LogConfig

tesk/constants.py

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,55 +19,16 @@ class TeskConstants(BaseModel):
1919
TASKMASTER_ENVIRONMENT_EXECUTOR_BACKOFF_LIMIT: Backoff limit for taskmaster env
2020
FILER_BACKOFF_LIMIT: Backoff limit got filer job
2121
EXECUTOR_BACKOFF_LIMIT: Backoff limit for executor job
22-
23-
Note:
24-
Below are the mentioned environment variable with which these constants can be
25-
configured, otherwise mentioned default will be assigned.
26-
27-
variable:
28-
ENV_VARIABLE = default
29-
30-
FILER_IMAGE_NAME:
31-
TESK_API_TASKMASTER_FILER_IMAGE_NAME = docker.io/elixircloud/tesk-core-filer
32-
FILER_IMAGE_VERSION:
33-
TESK_API_TASKMASTER_FILER_IMAGE_VERSION = latest
34-
TASKMASTER_IMAGE_NAME:
35-
TESK_API_TASKMASTER_IMAGE_NAME = docker.io/elixircloud/tesk-core-taskmaster
36-
TASKMASTER_IMAGE_VERSION:
37-
TESK_API_TASKMASTER_IMAGE_VERSION = latest
38-
TESK_NAMESPACE:
39-
TESK_API_K8S_NAMESPACE = tesk
40-
TASKMASTER_SERVICE_ACCOUNT_NAME:
41-
TESK_API_TASKMASTER_SERVICE_ACCOUNT_NAME = taskmaster
42-
TASKMASTER_ENVIRONMENT_EXECUTOR_BACKOFF_LIMIT:
43-
ENVIRONMENT_EXECUTOR_BACKOFF_LIMIT = 6
44-
FILER_BACKOFF_LIMIT:
45-
FILER_BACKOFF_LIMIT = 2
46-
EXECUTOR_BACKOFF_LIMIT:
47-
EXECUTOR_BACKOFF_LIMIT = 2
4822
"""
4923

50-
FILER_IMAGE_NAME: str = os.getenv(
51-
"TESK_API_TASKMASTER_FILER_IMAGE_NAME", "docker.io/elixircloud/tesk-core-filer"
52-
)
53-
FILER_IMAGE_VERSION: str = os.getenv(
54-
"TESK_API_TASKMASTER_FILER_IMAGE_VERSION", "latest"
55-
)
56-
TASKMASTER_IMAGE_NAME: str = os.getenv(
57-
"TESK_API_TASKMASTER_IMAGE_NAME", "docker.io/elixircloud/tesk-core-taskmaster"
58-
)
59-
TASKMASTER_IMAGE_VERSION: str = os.getenv(
60-
"TESK_API_TASKMASTER_IMAGE_VERSION", "latest"
61-
)
6224
TESK_NAMESPACE: str = os.getenv("TESK_API_K8S_NAMESPACE", "tesk")
63-
TASKMASTER_SERVICE_ACCOUNT_NAME: str = os.getenv(
64-
"TESK_API_TASKMASTER_SERVICE_ACCOUNT_NAME", "taskmaster"
65-
)
66-
TASKMASTER_ENVIRONMENT_EXECUTOR_BACKOFF_LIMIT: str = os.getenv(
67-
"ENVIRONMENT_EXECUTOR_BACKOFF_LIMIT", "6"
68-
)
69-
FILER_BACKOFF_LIMIT: str = os.getenv("FILER_BACKOFF_LIMIT", "2")
70-
EXECUTOR_BACKOFF_LIMIT: str = os.getenv("EXECUTOR_BACKOFF_LIMIT", "2")
25+
FILER_IMAGE_NAME: str = "docker.io/elixircloud/tesk-core-filer"
26+
FILER_IMAGE_VERSION: str = "latest"
27+
TASKMASTER_IMAGE_NAME: str = "docker.io/elixircloud/tesk-core-taskmaster"
28+
TASKMASTER_IMAGE_VERSION: str = "latest"
29+
TASKMASTER_SERVICE_ACCOUNT_NAME: str = "taskmaster"
30+
FILER_BACKOFF_LIMIT: str = "2"
31+
EXECUTOR_BACKOFF_LIMIT: str = "2"
7132

7233
class Config:
7334
"""Configuration for class."""

tesk/custom_config.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,77 @@
11
"""Custom configuration model for the FOCA app."""
22

3+
from typing import Dict, Optional
4+
35
from pydantic import BaseModel
46

57
from tesk.api.ga4gh.tes.models import Service
8+
from tesk.constants import tesk_constants
9+
10+
11+
class FtpConfig(BaseModel):
12+
"""Ftp configuration model for the TESK.
13+
14+
Args:
15+
secretName: Name of the secret with FTP account credentials.
16+
enabled: If FTP account enabled (based on non-emptiness of secretName).
17+
"""
18+
19+
secretName: Optional[str] = None
20+
enabled: bool = False
21+
22+
23+
class ExecutorSecret(BaseModel):
24+
"""Executor secret configuration.
25+
26+
Args:
27+
name: Name of a secret that will be mounted as volume to each executor. The same
28+
name will be used for the secret and the volume.
29+
mountPath: The path where the secret will be mounted to executors.
30+
enabled: Indicates whether the secret is enabled.
31+
"""
32+
33+
name: Optional[str] = None
34+
mountPath: Optional[str] = None
35+
enabled: bool = False
36+
37+
38+
class Taskmaster(BaseModel):
39+
"""Taskmaster's configuration model for the TESK.
40+
41+
Args:
42+
imageName: Taskmaster image name.
43+
imageVersion: Taskmaster image version.
44+
filerImageName: Filer image name.
45+
filerImageVersion: Filer image version.
46+
ftp: FTP account settings.
47+
debug: If verbose (debug) mode of taskmaster is on (passes additional flag to
48+
taskmaster and sets image pull policy to Always).
49+
environment: Environment variables, that will be passed to taskmaster.
50+
serviceAccountName: Service Account name for taskmaster.
51+
executorSecret: Executor secret configuration
52+
"""
53+
54+
imageName: str = tesk_constants.TASKMASTER_IMAGE_NAME
55+
imageVersion: str = tesk_constants.TASKMASTER_IMAGE_VERSION
56+
filerImageName: str = tesk_constants.FILER_IMAGE_NAME
57+
filerImageVersion: str = tesk_constants.FILER_IMAGE_VERSION
58+
ftp: FtpConfig = FtpConfig()
59+
debug: bool = False
60+
environment: Optional[Dict[str, str]] = None
61+
serviceAccountName: str = tesk_constants.TASKMASTER_SERVICE_ACCOUNT_NAME
62+
executorSecret: Optional[ExecutorSecret] = None
63+
filerBackoffLimit: str = tesk_constants.FILER_BACKOFF_LIMIT
64+
executorBackoffLimit: str = tesk_constants.EXECUTOR_BACKOFF_LIMIT
665

766

867
class CustomConfig(BaseModel):
9-
"""Custom configuration model for the FOCA app."""
68+
"""Custom configuration model for the FOCA app.
69+
70+
Args:
71+
service_info: Service information.
72+
taskmaster: Taskmaster environment.
73+
"""
1074

1175
# Define custom configuration fields here
1276
service_info: Service
77+
taskmaster: Taskmaster = Taskmaster()

tesk/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class ConfigNotFoundError(FileNotFoundError):
1919
"""Configuration file not found error."""
2020

2121

22+
class ConfigInvalidError(ValueError):
23+
"""Configuration file is invalid."""
24+
25+
2226
class KubernetesError(ApiException):
2327
"""Kubernetes error."""
2428

tesk/utils.py

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,162 @@
33
import os
44
from pathlib import Path
55

6+
from foca import Foca
7+
from kubernetes.client.models import (
8+
V1Container,
9+
V1DownwardAPIVolumeFile,
10+
V1DownwardAPIVolumeSource,
11+
V1EnvVar,
12+
V1EnvVarSource,
13+
V1Job,
14+
V1JobSpec,
15+
V1ObjectFieldSelector,
16+
V1ObjectMeta,
17+
V1PodSpec,
18+
V1PodTemplateSpec,
19+
V1SecretKeySelector,
20+
V1Volume,
21+
V1VolumeMount,
22+
)
23+
24+
from tesk.custom_config import (
25+
CustomConfig,
26+
Taskmaster,
27+
)
28+
from tesk.exceptions import ConfigInvalidError
29+
from tesk.k8s.constants import tesk_k8s_constants
30+
631

732
def get_config_path() -> Path:
833
"""Get the configuration path.
934
1035
Returns:
11-
The path of the config file.
36+
The path of the config file.
1237
"""
1338
# Determine the configuration path
1439
if config_path_env := os.getenv("TESK_FOCA_CONFIG_PATH"):
1540
return Path(config_path_env).resolve()
1641
else:
1742
return (Path(__file__).parents[1] / "deployment" / "config.yaml").resolve()
43+
44+
45+
def get_custom_config() -> CustomConfig:
46+
"""Get the custom configuration.
47+
48+
Returns:
49+
The custom configuration.
50+
"""
51+
conf = Foca(config_file=get_config_path()).conf
52+
try:
53+
return CustomConfig(**conf.custom)
54+
except AttributeError:
55+
raise ConfigInvalidError(
56+
"Custom configuration not found in config file."
57+
) from None
58+
59+
60+
def get_taskmaster_config() -> Taskmaster:
61+
"""Get the taskmaster env property from the custom configuration.
62+
63+
Returns:
64+
The taskmaster env property.
65+
"""
66+
custom_conf = get_custom_config()
67+
try:
68+
return custom_conf.taskmaster
69+
except AttributeError:
70+
raise ConfigInvalidError(
71+
"Custom configuration doesn't seem to have taskmaster_env_properties in "
72+
"config file."
73+
f"Custom config:\n{custom_conf}"
74+
) from None
75+
76+
77+
def get_taskmaster_template() -> V1Job:
78+
"""Get the taskmaster template from the custom configuration.
79+
80+
This will be used to create the taskmaster job, API will inject values
81+
into the template, depending upon the type of job and request.
82+
83+
Returns:
84+
The taskmaster template.
85+
"""
86+
taskmaster_conf: Taskmaster = get_taskmaster_config()
87+
88+
return V1Job(
89+
api_version=tesk_k8s_constants.k8s_constants.K8S_BATCH_API_VERSION,
90+
kind=tesk_k8s_constants.k8s_constants.K8S_BATCH_API_JOB_TYPE,
91+
metadata=V1ObjectMeta(
92+
name=tesk_k8s_constants.label_constants.LABEL_JOBTYPE_VALUE_TASKM,
93+
),
94+
spec=V1JobSpec(
95+
template=V1PodTemplateSpec(
96+
metadata=V1ObjectMeta(
97+
name=tesk_k8s_constants.label_constants.LABEL_JOBTYPE_VALUE_TASKM
98+
),
99+
spec=V1PodSpec(
100+
service_account_name=taskmaster_conf.serviceAccountName,
101+
containers=[
102+
V1Container(
103+
name=tesk_k8s_constants.label_constants.LABEL_JOBTYPE_VALUE_TASKM,
104+
image=f"{taskmaster_conf.imageName}:{taskmaster_conf.imageVersion}",
105+
args=[
106+
"-f",
107+
f"/jsoninput/{tesk_k8s_constants.job_constants.TASKMASTER_INPUT}.gz",
108+
],
109+
env=[
110+
V1EnvVar(
111+
name=tesk_k8s_constants.ftp_constants.FTP_SECRET_USERNAME_ENV,
112+
value_from=V1EnvVarSource(
113+
secret_key_ref=V1SecretKeySelector(
114+
name="ftp-secret",
115+
key="username",
116+
optional=True,
117+
)
118+
),
119+
),
120+
V1EnvVar(
121+
name=tesk_k8s_constants.ftp_constants.FTP_SECRET_PASSWORD_ENV,
122+
value_from=V1EnvVarSource(
123+
secret_key_ref=V1SecretKeySelector(
124+
name="ftp-secret",
125+
key="password",
126+
optional=True,
127+
)
128+
),
129+
),
130+
],
131+
volume_mounts=[
132+
V1VolumeMount(
133+
name="podinfo",
134+
mount_path="/podinfo",
135+
read_only=True,
136+
),
137+
V1VolumeMount(
138+
name="jsoninput",
139+
mount_path="/jsoninput",
140+
read_only=True,
141+
),
142+
],
143+
)
144+
],
145+
volumes=[
146+
V1Volume(
147+
name="podinfo",
148+
downward_api=V1DownwardAPIVolumeSource(
149+
items=[
150+
V1DownwardAPIVolumeFile(
151+
path="labels",
152+
field_ref=V1ObjectFieldSelector(
153+
field_path="metadata.labels"
154+
),
155+
),
156+
]
157+
),
158+
),
159+
],
160+
restart_policy=tesk_k8s_constants.k8s_constants.JOB_RESTART_POLICY,
161+
),
162+
)
163+
),
164+
)

0 commit comments

Comments
 (0)