fractal-server 2.16.5__py3-none-any.whl → 2.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fractal_server/__init__.py +1 -1
- fractal_server/__main__.py +178 -52
- fractal_server/app/db/__init__.py +9 -11
- fractal_server/app/models/security.py +30 -22
- fractal_server/app/models/user_settings.py +5 -4
- fractal_server/app/models/v2/__init__.py +4 -0
- fractal_server/app/models/v2/job.py +3 -4
- fractal_server/app/models/v2/profile.py +16 -0
- fractal_server/app/models/v2/project.py +5 -0
- fractal_server/app/models/v2/resource.py +130 -0
- fractal_server/app/models/v2/task_group.py +4 -0
- fractal_server/app/routes/admin/v2/__init__.py +4 -0
- fractal_server/app/routes/admin/v2/_aux_functions.py +55 -0
- fractal_server/app/routes/admin/v2/accounting.py +3 -3
- fractal_server/app/routes/admin/v2/impersonate.py +2 -2
- fractal_server/app/routes/admin/v2/job.py +51 -15
- fractal_server/app/routes/admin/v2/profile.py +100 -0
- fractal_server/app/routes/admin/v2/project.py +2 -2
- fractal_server/app/routes/admin/v2/resource.py +222 -0
- fractal_server/app/routes/admin/v2/task.py +59 -32
- fractal_server/app/routes/admin/v2/task_group.py +17 -12
- fractal_server/app/routes/admin/v2/task_group_lifecycle.py +52 -86
- fractal_server/app/routes/api/__init__.py +45 -8
- fractal_server/app/routes/api/v2/_aux_functions.py +17 -1
- fractal_server/app/routes/api/v2/_aux_functions_history.py +2 -2
- fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +3 -3
- fractal_server/app/routes/api/v2/_aux_functions_tasks.py +55 -19
- fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +21 -17
- fractal_server/app/routes/api/v2/dataset.py +10 -19
- fractal_server/app/routes/api/v2/history.py +8 -8
- fractal_server/app/routes/api/v2/images.py +5 -5
- fractal_server/app/routes/api/v2/job.py +8 -8
- fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
- fractal_server/app/routes/api/v2/project.py +15 -7
- fractal_server/app/routes/api/v2/status_legacy.py +2 -2
- fractal_server/app/routes/api/v2/submit.py +49 -42
- fractal_server/app/routes/api/v2/task.py +26 -8
- fractal_server/app/routes/api/v2/task_collection.py +39 -50
- fractal_server/app/routes/api/v2/task_collection_custom.py +10 -6
- fractal_server/app/routes/api/v2/task_collection_pixi.py +34 -42
- fractal_server/app/routes/api/v2/task_group.py +19 -9
- fractal_server/app/routes/api/v2/task_group_lifecycle.py +43 -86
- fractal_server/app/routes/api/v2/task_version_update.py +3 -3
- fractal_server/app/routes/api/v2/workflow.py +9 -9
- fractal_server/app/routes/api/v2/workflow_import.py +29 -16
- fractal_server/app/routes/api/v2/workflowtask.py +5 -5
- fractal_server/app/routes/auth/__init__.py +34 -5
- fractal_server/app/routes/auth/_aux_auth.py +39 -20
- fractal_server/app/routes/auth/current_user.py +56 -67
- fractal_server/app/routes/auth/group.py +29 -46
- fractal_server/app/routes/auth/oauth.py +55 -38
- fractal_server/app/routes/auth/register.py +2 -2
- fractal_server/app/routes/auth/router.py +4 -2
- fractal_server/app/routes/auth/users.py +29 -53
- fractal_server/app/routes/aux/_runner.py +2 -1
- fractal_server/app/routes/aux/validate_user_profile.py +62 -0
- fractal_server/app/schemas/__init__.py +0 -1
- fractal_server/app/schemas/user.py +43 -13
- fractal_server/app/schemas/user_group.py +2 -1
- fractal_server/app/schemas/v2/__init__.py +12 -0
- fractal_server/app/schemas/v2/profile.py +78 -0
- fractal_server/app/schemas/v2/resource.py +137 -0
- fractal_server/app/schemas/v2/task_collection.py +11 -3
- fractal_server/app/schemas/v2/task_group.py +5 -0
- fractal_server/app/security/__init__.py +174 -75
- fractal_server/app/security/signup_email.py +52 -34
- fractal_server/config/__init__.py +27 -0
- fractal_server/config/_data.py +68 -0
- fractal_server/config/_database.py +59 -0
- fractal_server/config/_email.py +133 -0
- fractal_server/config/_main.py +78 -0
- fractal_server/config/_oauth.py +69 -0
- fractal_server/config/_settings_config.py +7 -0
- fractal_server/data_migrations/2_17_0.py +339 -0
- fractal_server/images/tools.py +3 -3
- fractal_server/logger.py +3 -3
- fractal_server/main.py +17 -23
- fractal_server/migrations/naming_convention.py +1 -1
- fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +195 -0
- fractal_server/runner/config/__init__.py +2 -0
- fractal_server/runner/config/_local.py +21 -0
- fractal_server/runner/config/_slurm.py +129 -0
- fractal_server/runner/config/slurm_mem_to_MB.py +63 -0
- fractal_server/runner/exceptions.py +4 -0
- fractal_server/runner/executors/base_runner.py +17 -7
- fractal_server/runner/executors/local/get_local_config.py +21 -86
- fractal_server/runner/executors/local/runner.py +48 -5
- fractal_server/runner/executors/slurm_common/_batching.py +2 -2
- fractal_server/runner/executors/slurm_common/base_slurm_runner.py +60 -26
- fractal_server/runner/executors/slurm_common/get_slurm_config.py +39 -55
- fractal_server/runner/executors/slurm_common/remote.py +1 -1
- fractal_server/runner/executors/slurm_common/slurm_config.py +214 -0
- fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +1 -1
- fractal_server/runner/executors/slurm_ssh/runner.py +12 -14
- fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +2 -2
- fractal_server/runner/executors/slurm_sudo/runner.py +12 -12
- fractal_server/runner/v2/_local.py +36 -21
- fractal_server/runner/v2/_slurm_ssh.py +41 -4
- fractal_server/runner/v2/_slurm_sudo.py +42 -12
- fractal_server/runner/v2/db_tools.py +1 -1
- fractal_server/runner/v2/runner.py +3 -11
- fractal_server/runner/v2/runner_functions.py +42 -28
- fractal_server/runner/v2/submit_workflow.py +88 -109
- fractal_server/runner/versions.py +8 -3
- fractal_server/ssh/_fabric.py +6 -6
- fractal_server/tasks/config/__init__.py +3 -0
- fractal_server/tasks/config/_pixi.py +127 -0
- fractal_server/tasks/config/_python.py +51 -0
- fractal_server/tasks/v2/local/_utils.py +7 -7
- fractal_server/tasks/v2/local/collect.py +13 -5
- fractal_server/tasks/v2/local/collect_pixi.py +26 -10
- fractal_server/tasks/v2/local/deactivate.py +7 -1
- fractal_server/tasks/v2/local/deactivate_pixi.py +5 -1
- fractal_server/tasks/v2/local/delete.py +5 -1
- fractal_server/tasks/v2/local/reactivate.py +13 -5
- fractal_server/tasks/v2/local/reactivate_pixi.py +27 -9
- fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py +11 -10
- fractal_server/tasks/v2/ssh/_utils.py +6 -7
- fractal_server/tasks/v2/ssh/collect.py +19 -12
- fractal_server/tasks/v2/ssh/collect_pixi.py +34 -16
- fractal_server/tasks/v2/ssh/deactivate.py +12 -8
- fractal_server/tasks/v2/ssh/deactivate_pixi.py +14 -10
- fractal_server/tasks/v2/ssh/delete.py +12 -9
- fractal_server/tasks/v2/ssh/reactivate.py +18 -12
- fractal_server/tasks/v2/ssh/reactivate_pixi.py +36 -17
- fractal_server/tasks/v2/templates/4_pip_show.sh +4 -6
- fractal_server/tasks/v2/utils_database.py +2 -2
- fractal_server/tasks/v2/utils_pixi.py +3 -0
- fractal_server/tasks/v2/utils_python_interpreter.py +8 -16
- fractal_server/tasks/v2/utils_templates.py +7 -10
- fractal_server/utils.py +1 -1
- {fractal_server-2.16.5.dist-info → fractal_server-2.17.0.dist-info}/METADATA +8 -10
- {fractal_server-2.16.5.dist-info → fractal_server-2.17.0.dist-info}/RECORD +137 -118
- {fractal_server-2.16.5.dist-info → fractal_server-2.17.0.dist-info}/WHEEL +1 -1
- fractal_server/app/routes/aux/validate_user_settings.py +0 -73
- fractal_server/app/schemas/user_settings.py +0 -67
- fractal_server/app/user_settings.py +0 -42
- fractal_server/config.py +0 -906
- fractal_server/data_migrations/2_14_10.py +0 -48
- fractal_server/runner/executors/slurm_common/_slurm_config.py +0 -471
- /fractal_server/{runner → app}/shutdown.py +0 -0
- {fractal_server-2.16.5.dist-info → fractal_server-2.17.0.dist-info}/entry_points.txt +0 -0
- {fractal_server-2.16.5.dist-info → fractal_server-2.17.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -6,13 +6,13 @@ from ..slurm_common.slurm_job_task_models import SlurmJob
|
|
|
6
6
|
from .run_subprocess import run_subprocess
|
|
7
7
|
from .tar_commands import get_tar_compression_cmd
|
|
8
8
|
from .tar_commands import get_tar_extraction_cmd
|
|
9
|
-
from fractal_server.
|
|
9
|
+
from fractal_server.app.models import Profile
|
|
10
|
+
from fractal_server.app.models import Resource
|
|
10
11
|
from fractal_server.logger import set_logger
|
|
12
|
+
from fractal_server.runner.config import JobRunnerConfigSLURM
|
|
11
13
|
from fractal_server.ssh._fabric import FractalSSH
|
|
12
14
|
from fractal_server.ssh._fabric import FractalSSHCommandError
|
|
13
15
|
from fractal_server.ssh._fabric import FractalSSHTimeoutError
|
|
14
|
-
from fractal_server.syringe import Inject
|
|
15
|
-
|
|
16
16
|
|
|
17
17
|
logger = set_logger(__name__)
|
|
18
18
|
|
|
@@ -27,10 +27,11 @@ class SlurmSSHRunner(BaseSlurmRunner):
|
|
|
27
27
|
root_dir_local: Path,
|
|
28
28
|
root_dir_remote: Path,
|
|
29
29
|
common_script_lines: list[str] | None = None,
|
|
30
|
-
|
|
31
|
-
poll_interval: int | None = None,
|
|
30
|
+
resource: Resource,
|
|
32
31
|
# Specific
|
|
33
32
|
slurm_account: str | None = None,
|
|
33
|
+
profile: Profile,
|
|
34
|
+
user_cache_dir: str,
|
|
34
35
|
fractal_ssh: FractalSSH,
|
|
35
36
|
) -> None:
|
|
36
37
|
"""
|
|
@@ -38,20 +39,21 @@ class SlurmSSHRunner(BaseSlurmRunner):
|
|
|
38
39
|
different SLURM jobs/tasks.
|
|
39
40
|
"""
|
|
40
41
|
self.fractal_ssh = fractal_ssh
|
|
42
|
+
self.shared_config = JobRunnerConfigSLURM(
|
|
43
|
+
**resource.jobs_runner_config
|
|
44
|
+
)
|
|
41
45
|
logger.warning(self.fractal_ssh)
|
|
42
46
|
|
|
43
47
|
# Check SSH connection and try to recover from a closed-socket error
|
|
44
48
|
self.fractal_ssh.check_connection()
|
|
45
|
-
|
|
46
|
-
settings = Inject(get_settings)
|
|
47
49
|
super().__init__(
|
|
48
50
|
slurm_runner_type="ssh",
|
|
49
51
|
root_dir_local=root_dir_local,
|
|
50
52
|
root_dir_remote=root_dir_remote,
|
|
51
53
|
common_script_lines=common_script_lines,
|
|
52
54
|
user_cache_dir=user_cache_dir,
|
|
53
|
-
poll_interval=
|
|
54
|
-
python_worker_interpreter=
|
|
55
|
+
poll_interval=resource.jobs_poll_interval,
|
|
56
|
+
python_worker_interpreter=resource.jobs_slurm_python_worker,
|
|
55
57
|
slurm_account=slurm_account,
|
|
56
58
|
)
|
|
57
59
|
|
|
@@ -225,11 +227,7 @@ class SlurmSSHRunner(BaseSlurmRunner):
|
|
|
225
227
|
|
|
226
228
|
logger.debug("[_send_many_job_inputs] END.")
|
|
227
229
|
|
|
228
|
-
def run_squeue(
|
|
229
|
-
self,
|
|
230
|
-
*,
|
|
231
|
-
job_ids: list[str],
|
|
232
|
-
) -> str:
|
|
230
|
+
def run_squeue(self, *, job_ids: list[str]) -> str:
|
|
233
231
|
"""
|
|
234
232
|
Run `squeue` for a set of SLURM job IDs.
|
|
235
233
|
|
|
@@ -33,7 +33,7 @@ def _run_command_as_user(
|
|
|
33
33
|
"""
|
|
34
34
|
Use `sudo -u` to impersonate another user and run a command
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Args:
|
|
37
37
|
cmd: Command to be run
|
|
38
38
|
user: User to be impersonated
|
|
39
39
|
check: If `True`, check that `returncode=0` and fail otherwise.
|
|
@@ -71,7 +71,7 @@ def _mkdir_as_user(*, folder: str, user: str) -> None:
|
|
|
71
71
|
"""
|
|
72
72
|
Create a folder as a different user
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
Args:
|
|
75
75
|
folder: Absolute path to the folder
|
|
76
76
|
user: User to be impersonated
|
|
77
77
|
|
|
@@ -2,7 +2,6 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
import shlex
|
|
4
4
|
import subprocess # nosec
|
|
5
|
-
import sys
|
|
6
5
|
from concurrent.futures import ThreadPoolExecutor
|
|
7
6
|
from pathlib import Path
|
|
8
7
|
|
|
@@ -10,10 +9,11 @@ from ..slurm_common.base_slurm_runner import BaseSlurmRunner
|
|
|
10
9
|
from ..slurm_common.slurm_job_task_models import SlurmJob
|
|
11
10
|
from ._subprocess_run_as_user import _mkdir_as_user
|
|
12
11
|
from ._subprocess_run_as_user import _run_command_as_user
|
|
13
|
-
from fractal_server.
|
|
12
|
+
from fractal_server.app.models import Profile
|
|
13
|
+
from fractal_server.app.models import Resource
|
|
14
14
|
from fractal_server.logger import set_logger
|
|
15
|
+
from fractal_server.runner.config import JobRunnerConfigSLURM
|
|
15
16
|
from fractal_server.runner.exceptions import JobExecutionError
|
|
16
|
-
from fractal_server.syringe import Inject
|
|
17
17
|
|
|
18
18
|
logger = set_logger(__name__)
|
|
19
19
|
|
|
@@ -51,19 +51,21 @@ class SudoSlurmRunner(BaseSlurmRunner):
|
|
|
51
51
|
root_dir_local: Path,
|
|
52
52
|
root_dir_remote: Path,
|
|
53
53
|
common_script_lines: list[str] | None = None,
|
|
54
|
-
|
|
55
|
-
poll_interval: int | None = None,
|
|
54
|
+
resource: Resource,
|
|
56
55
|
# Specific
|
|
56
|
+
profile: Profile,
|
|
57
|
+
user_cache_dir: str,
|
|
57
58
|
slurm_account: str | None = None,
|
|
58
|
-
slurm_user: str,
|
|
59
59
|
) -> None:
|
|
60
60
|
"""
|
|
61
61
|
Set parameters that are the same for different Fractal tasks and for
|
|
62
62
|
different SLURM jobs/tasks.
|
|
63
63
|
"""
|
|
64
64
|
|
|
65
|
-
self.slurm_user =
|
|
66
|
-
|
|
65
|
+
self.slurm_user = profile.username
|
|
66
|
+
self.shared_config = JobRunnerConfigSLURM(
|
|
67
|
+
**resource.jobs_runner_config
|
|
68
|
+
)
|
|
67
69
|
|
|
68
70
|
super().__init__(
|
|
69
71
|
slurm_runner_type="sudo",
|
|
@@ -71,10 +73,8 @@ class SudoSlurmRunner(BaseSlurmRunner):
|
|
|
71
73
|
root_dir_remote=root_dir_remote,
|
|
72
74
|
common_script_lines=common_script_lines,
|
|
73
75
|
user_cache_dir=user_cache_dir,
|
|
74
|
-
poll_interval=
|
|
75
|
-
python_worker_interpreter=
|
|
76
|
-
settings.FRACTAL_SLURM_WORKER_PYTHON or sys.executable
|
|
77
|
-
),
|
|
76
|
+
poll_interval=resource.jobs_poll_interval,
|
|
77
|
+
python_worker_interpreter=resource.jobs_slurm_python_worker,
|
|
78
78
|
slurm_account=slurm_account,
|
|
79
79
|
)
|
|
80
80
|
|
|
@@ -5,16 +5,19 @@ from ..executors.local.runner import LocalRunner
|
|
|
5
5
|
from ..set_start_and_last_task_index import set_start_and_last_task_index
|
|
6
6
|
from .runner import execute_tasks_v2
|
|
7
7
|
from fractal_server.app.models.v2 import DatasetV2
|
|
8
|
+
from fractal_server.app.models.v2 import Profile
|
|
9
|
+
from fractal_server.app.models.v2 import Resource
|
|
8
10
|
from fractal_server.app.models.v2 import WorkflowV2
|
|
11
|
+
from fractal_server.ssh._fabric import FractalSSH
|
|
9
12
|
from fractal_server.types import AttributeFilters
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
def process_workflow(
|
|
13
16
|
*,
|
|
17
|
+
job_id: int,
|
|
14
18
|
workflow: WorkflowV2,
|
|
15
19
|
dataset: DatasetV2,
|
|
16
20
|
workflow_dir_local: Path,
|
|
17
|
-
job_id: int,
|
|
18
21
|
workflow_dir_remote: Path | None = None,
|
|
19
22
|
first_task_index: int | None = None,
|
|
20
23
|
last_task_index: int | None = None,
|
|
@@ -22,23 +25,24 @@ def process_workflow(
|
|
|
22
25
|
job_attribute_filters: AttributeFilters,
|
|
23
26
|
job_type_filters: dict[str, bool],
|
|
24
27
|
user_id: int,
|
|
25
|
-
|
|
28
|
+
resource: Resource,
|
|
29
|
+
profile: Profile,
|
|
30
|
+
user_cache_dir: str | None = None,
|
|
31
|
+
fractal_ssh: FractalSSH | None = None,
|
|
32
|
+
slurm_account: str | None = None,
|
|
33
|
+
worker_init: str | None = None,
|
|
26
34
|
) -> None:
|
|
27
35
|
"""
|
|
28
|
-
Run a workflow through
|
|
36
|
+
Run a workflow through a local backend.
|
|
29
37
|
|
|
30
38
|
Args:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
dataset:
|
|
34
|
-
|
|
35
|
-
workflow_dir_local:
|
|
36
|
-
Working directory for this run.
|
|
39
|
+
job_id: Job ID.
|
|
40
|
+
workflow: Workflow to be run
|
|
41
|
+
dataset: Dataset to be used.
|
|
42
|
+
workflow_dir_local: Local working directory for this job.
|
|
37
43
|
workflow_dir_remote:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
for the `local` backend it cannot be different from
|
|
41
|
-
`workflow_dir_local`.
|
|
44
|
+
Remote working directory for this job - only relevant for
|
|
45
|
+
`slurm_sudo` and `slurm_ssh` backends.
|
|
42
46
|
first_task_index:
|
|
43
47
|
Positional index of the first task to execute; if `None`, start
|
|
44
48
|
from `0`.
|
|
@@ -46,13 +50,20 @@ def process_workflow(
|
|
|
46
50
|
Positional index of the last task to execute; if `None`, proceed
|
|
47
51
|
until the last task.
|
|
48
52
|
logger_name: Logger name
|
|
49
|
-
user_id:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
user_id: User ID.
|
|
54
|
+
resource: Computational resource for running this job.
|
|
55
|
+
profile: Computational profile for running this job.
|
|
56
|
+
user_cache_dir:
|
|
57
|
+
User-writeable folder (typically a subfolder of `project_dir`).
|
|
58
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
59
|
+
fractal_ssh:
|
|
60
|
+
`FractalSSH` object, only relevant for the `slurm_ssh` backend.
|
|
61
|
+
slurm_account:
|
|
62
|
+
SLURM account to set.
|
|
63
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
64
|
+
worker_init:
|
|
65
|
+
Additional preamble lines for SLURM submission script.
|
|
66
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
56
67
|
"""
|
|
57
68
|
|
|
58
69
|
if workflow_dir_remote and (workflow_dir_remote != workflow_dir_local):
|
|
@@ -69,7 +80,11 @@ def process_workflow(
|
|
|
69
80
|
last_task_index=last_task_index,
|
|
70
81
|
)
|
|
71
82
|
|
|
72
|
-
with LocalRunner(
|
|
83
|
+
with LocalRunner(
|
|
84
|
+
root_dir_local=workflow_dir_local,
|
|
85
|
+
resource=resource,
|
|
86
|
+
profile=profile,
|
|
87
|
+
) as runner:
|
|
73
88
|
execute_tasks_v2(
|
|
74
89
|
wf_task_list=workflow.task_list[
|
|
75
90
|
first_task_index : (last_task_index + 1)
|
|
@@ -23,6 +23,8 @@ from ..executors.slurm_ssh.runner import SlurmSSHRunner
|
|
|
23
23
|
from ..set_start_and_last_task_index import set_start_and_last_task_index
|
|
24
24
|
from .runner import execute_tasks_v2
|
|
25
25
|
from fractal_server.app.models.v2 import DatasetV2
|
|
26
|
+
from fractal_server.app.models.v2 import Profile
|
|
27
|
+
from fractal_server.app.models.v2 import Resource
|
|
26
28
|
from fractal_server.app.models.v2 import WorkflowV2
|
|
27
29
|
from fractal_server.logger import set_logger
|
|
28
30
|
from fractal_server.types import AttributeFilters
|
|
@@ -32,10 +34,10 @@ logger = set_logger(__name__)
|
|
|
32
34
|
|
|
33
35
|
def process_workflow(
|
|
34
36
|
*,
|
|
37
|
+
job_id: int,
|
|
35
38
|
workflow: WorkflowV2,
|
|
36
39
|
dataset: DatasetV2,
|
|
37
40
|
workflow_dir_local: Path,
|
|
38
|
-
job_id: int,
|
|
39
41
|
workflow_dir_remote: Path | None = None,
|
|
40
42
|
first_task_index: int | None = None,
|
|
41
43
|
last_task_index: int | None = None,
|
|
@@ -43,13 +45,45 @@ def process_workflow(
|
|
|
43
45
|
job_attribute_filters: AttributeFilters,
|
|
44
46
|
job_type_filters: dict[str, bool],
|
|
45
47
|
user_id: int,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
resource: Resource,
|
|
49
|
+
profile: Profile,
|
|
50
|
+
fractal_ssh: FractalSSH | None = None,
|
|
48
51
|
slurm_account: str | None = None,
|
|
49
52
|
worker_init: str | None = None,
|
|
53
|
+
user_cache_dir: str,
|
|
50
54
|
) -> None:
|
|
51
55
|
"""
|
|
52
|
-
|
|
56
|
+
Run a workflow through a `slurm_ssh` backend.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
job_id: Job ID.
|
|
60
|
+
workflow: Workflow to be run
|
|
61
|
+
dataset: Dataset to be used.
|
|
62
|
+
workflow_dir_local: Local working directory for this job.
|
|
63
|
+
workflow_dir_remote:
|
|
64
|
+
Remote working directory for this job - only relevant for
|
|
65
|
+
`slurm_sudo` and `slurm_ssh` backends.
|
|
66
|
+
first_task_index:
|
|
67
|
+
Positional index of the first task to execute; if `None`, start
|
|
68
|
+
from `0`.
|
|
69
|
+
last_task_index:
|
|
70
|
+
Positional index of the last task to execute; if `None`, proceed
|
|
71
|
+
until the last task.
|
|
72
|
+
logger_name: Logger name
|
|
73
|
+
user_id: User ID.
|
|
74
|
+
resource: Computational resource for running this job.
|
|
75
|
+
profile: Computational profile for running this job.
|
|
76
|
+
user_cache_dir:
|
|
77
|
+
User-writeable folder (typically a subfolder of `project_dir`).
|
|
78
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
79
|
+
fractal_ssh:
|
|
80
|
+
`FractalSSH` object, only relevant for the `slurm_ssh` backend.
|
|
81
|
+
slurm_account:
|
|
82
|
+
SLURM account to set.
|
|
83
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
84
|
+
worker_init:
|
|
85
|
+
Additional preamble lines for SLURM submission script.
|
|
86
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
53
87
|
"""
|
|
54
88
|
|
|
55
89
|
# Set values of first_task_index and last_task_index
|
|
@@ -68,7 +102,10 @@ def process_workflow(
|
|
|
68
102
|
root_dir_local=workflow_dir_local,
|
|
69
103
|
root_dir_remote=workflow_dir_remote,
|
|
70
104
|
slurm_account=slurm_account,
|
|
105
|
+
resource=resource,
|
|
106
|
+
profile=profile,
|
|
71
107
|
common_script_lines=worker_init,
|
|
108
|
+
user_cache_dir=user_cache_dir,
|
|
72
109
|
) as runner:
|
|
73
110
|
execute_tasks_v2(
|
|
74
111
|
wf_task_list=workflow.task_list[
|
|
@@ -22,16 +22,19 @@ from ..executors.slurm_sudo.runner import SudoSlurmRunner
|
|
|
22
22
|
from ..set_start_and_last_task_index import set_start_and_last_task_index
|
|
23
23
|
from .runner import execute_tasks_v2
|
|
24
24
|
from fractal_server.app.models.v2 import DatasetV2
|
|
25
|
+
from fractal_server.app.models.v2 import Profile
|
|
26
|
+
from fractal_server.app.models.v2 import Resource
|
|
25
27
|
from fractal_server.app.models.v2 import WorkflowV2
|
|
28
|
+
from fractal_server.ssh._fabric import FractalSSH
|
|
26
29
|
from fractal_server.types import AttributeFilters
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
def process_workflow(
|
|
30
33
|
*,
|
|
34
|
+
job_id: int,
|
|
31
35
|
workflow: WorkflowV2,
|
|
32
36
|
dataset: DatasetV2,
|
|
33
37
|
workflow_dir_local: Path,
|
|
34
|
-
job_id: int,
|
|
35
38
|
workflow_dir_remote: Path | None = None,
|
|
36
39
|
first_task_index: int | None = None,
|
|
37
40
|
last_task_index: int | None = None,
|
|
@@ -39,14 +42,45 @@ def process_workflow(
|
|
|
39
42
|
job_attribute_filters: AttributeFilters,
|
|
40
43
|
job_type_filters: dict[str, bool],
|
|
41
44
|
user_id: int,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
resource: Resource,
|
|
46
|
+
profile: Profile,
|
|
47
|
+
user_cache_dir: str,
|
|
45
48
|
slurm_account: str | None = None,
|
|
46
49
|
worker_init: str | None = None,
|
|
50
|
+
fractal_ssh: FractalSSH | None = None,
|
|
47
51
|
) -> None:
|
|
48
52
|
"""
|
|
49
|
-
|
|
53
|
+
Run a workflow through a `slurm_sudo` backend.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
job_id: Job ID.
|
|
57
|
+
workflow: Workflow to be run
|
|
58
|
+
dataset: Dataset to be used.
|
|
59
|
+
workflow_dir_local: Local working directory for this job.
|
|
60
|
+
workflow_dir_remote:
|
|
61
|
+
Remote working directory for this job - only relevant for
|
|
62
|
+
`slurm_sudo` and `slurm_ssh` backends.
|
|
63
|
+
first_task_index:
|
|
64
|
+
Positional index of the first task to execute; if `None`, start
|
|
65
|
+
from `0`.
|
|
66
|
+
last_task_index:
|
|
67
|
+
Positional index of the last task to execute; if `None`, proceed
|
|
68
|
+
until the last task.
|
|
69
|
+
logger_name: Logger name
|
|
70
|
+
user_id: User ID.
|
|
71
|
+
resource: Computational resource for running this job.
|
|
72
|
+
profile: Computational profile for running this job.
|
|
73
|
+
user_cache_dir:
|
|
74
|
+
User-writeable folder (typically a subfolder of `project_dir`).
|
|
75
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
76
|
+
fractal_ssh:
|
|
77
|
+
`FractalSSH` object, only relevant for the `slurm_ssh` backend.
|
|
78
|
+
slurm_account:
|
|
79
|
+
SLURM account to set.
|
|
80
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
81
|
+
worker_init:
|
|
82
|
+
Additional preamble lines for SLURM submission script.
|
|
83
|
+
Only relevant for `slurm_sudo` and `slurm_ssh` backends.
|
|
50
84
|
"""
|
|
51
85
|
|
|
52
86
|
# Set values of first_task_index and last_task_index
|
|
@@ -57,20 +91,16 @@ def process_workflow(
|
|
|
57
91
|
last_task_index=last_task_index,
|
|
58
92
|
)
|
|
59
93
|
|
|
60
|
-
if not slurm_user:
|
|
61
|
-
raise RuntimeError(
|
|
62
|
-
"slurm_user argument is required, for slurm backend"
|
|
63
|
-
)
|
|
64
|
-
|
|
65
94
|
if isinstance(worker_init, str):
|
|
66
95
|
worker_init = worker_init.split("\n")
|
|
67
96
|
|
|
68
97
|
with SudoSlurmRunner(
|
|
69
|
-
slurm_user=slurm_user,
|
|
70
|
-
user_cache_dir=user_cache_dir,
|
|
71
98
|
root_dir_local=workflow_dir_local,
|
|
72
99
|
root_dir_remote=workflow_dir_remote,
|
|
73
100
|
common_script_lines=worker_init,
|
|
101
|
+
resource=resource,
|
|
102
|
+
profile=profile,
|
|
103
|
+
user_cache_dir=user_cache_dir,
|
|
74
104
|
slurm_account=slurm_account,
|
|
75
105
|
) as runner:
|
|
76
106
|
execute_tasks_v2(
|
|
@@ -88,7 +88,7 @@ def bulk_upsert_image_cache_fast(
|
|
|
88
88
|
NOTE: we tried to replace `index_elements` with
|
|
89
89
|
`constraint="pk_historyimagecache"`, but it did not work as expected.
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Args:
|
|
92
92
|
list_upsert_objects:
|
|
93
93
|
List of dictionaries for objects to be upsert-ed.
|
|
94
94
|
db: A sync database session
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
2
1
|
from copy import copy
|
|
3
2
|
from copy import deepcopy
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
from typing import Any
|
|
6
|
-
from typing import Literal
|
|
7
5
|
|
|
8
6
|
from sqlalchemy.orm.attributes import flag_modified
|
|
9
7
|
from sqlmodel import delete
|
|
10
8
|
from sqlmodel import update
|
|
11
9
|
|
|
12
10
|
from .merge_outputs import merge_outputs
|
|
11
|
+
from .runner_functions import GetRunnerConfigType
|
|
13
12
|
from .runner_functions import run_v2_task_compound
|
|
14
13
|
from .runner_functions import run_v2_task_non_parallel
|
|
15
14
|
from .runner_functions import run_v2_task_parallel
|
|
@@ -92,14 +91,7 @@ def execute_tasks_v2(
|
|
|
92
91
|
job_id: int,
|
|
93
92
|
workflow_dir_remote: Path | None = None,
|
|
94
93
|
logger_name: str | None = None,
|
|
95
|
-
get_runner_config:
|
|
96
|
-
[
|
|
97
|
-
WorkflowTaskV2,
|
|
98
|
-
Literal["non_parallel", "parallel"],
|
|
99
|
-
Path | None,
|
|
100
|
-
],
|
|
101
|
-
Any,
|
|
102
|
-
],
|
|
94
|
+
get_runner_config: GetRunnerConfigType,
|
|
103
95
|
job_type_filters: dict[str, bool],
|
|
104
96
|
job_attribute_filters: AttributeFilters,
|
|
105
97
|
) -> None:
|
|
@@ -257,7 +249,7 @@ def execute_tasks_v2(
|
|
|
257
249
|
except Exception as e:
|
|
258
250
|
outcomes_dict = {
|
|
259
251
|
0: SubmissionOutcome(
|
|
260
|
-
|
|
252
|
+
task_output=None,
|
|
261
253
|
exception=e,
|
|
262
254
|
)
|
|
263
255
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
2
1
|
from pathlib import Path
|
|
3
2
|
from typing import Any
|
|
4
3
|
from typing import Literal
|
|
4
|
+
from typing import Protocol
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
from pydantic import ConfigDict
|
|
@@ -20,7 +20,12 @@ from fractal_server.app.schemas.v2 import HistoryUnitStatus
|
|
|
20
20
|
from fractal_server.app.schemas.v2 import TaskType
|
|
21
21
|
from fractal_server.exceptions import UnreachableBranchError
|
|
22
22
|
from fractal_server.logger import set_logger
|
|
23
|
+
from fractal_server.runner.config import JobRunnerConfigLocal
|
|
24
|
+
from fractal_server.runner.config import JobRunnerConfigSLURM
|
|
23
25
|
from fractal_server.runner.executors.base_runner import BaseRunner
|
|
26
|
+
from fractal_server.runner.executors.slurm_common.slurm_config import (
|
|
27
|
+
SlurmConfig,
|
|
28
|
+
)
|
|
24
29
|
from fractal_server.runner.task_files import enrich_task_files_multisubmit
|
|
25
30
|
from fractal_server.runner.task_files import SUBMIT_PREFIX
|
|
26
31
|
from fractal_server.runner.task_files import TaskFiles
|
|
@@ -35,6 +40,32 @@ from fractal_server.runner.v2.task_interface import (
|
|
|
35
40
|
_cast_and_validate_TaskOutput,
|
|
36
41
|
)
|
|
37
42
|
|
|
43
|
+
|
|
44
|
+
class GetRunnerConfigTypeLocal(Protocol):
|
|
45
|
+
def __call__(
|
|
46
|
+
self,
|
|
47
|
+
shared_config: JobRunnerConfigLocal,
|
|
48
|
+
wftask: WorkflowTaskV2,
|
|
49
|
+
which_type: Literal["non_parallel", "parallel"],
|
|
50
|
+
tot_tasks: int,
|
|
51
|
+
) -> JobRunnerConfigLocal:
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class GetRunnerConfigTypeSLURM(Protocol):
|
|
56
|
+
def __call__(
|
|
57
|
+
self,
|
|
58
|
+
shared_config: JobRunnerConfigSLURM,
|
|
59
|
+
wftask: WorkflowTaskV2,
|
|
60
|
+
which_type: Literal["non_parallel", "parallel"],
|
|
61
|
+
tot_tasks: int,
|
|
62
|
+
) -> SlurmConfig:
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
GetRunnerConfigType = GetRunnerConfigTypeLocal | GetRunnerConfigTypeSLURM
|
|
67
|
+
|
|
68
|
+
|
|
38
69
|
__all__ = [
|
|
39
70
|
"run_v2_task_parallel",
|
|
40
71
|
"run_v2_task_non_parallel",
|
|
@@ -126,15 +157,7 @@ def run_v2_task_non_parallel(
|
|
|
126
157
|
workflow_dir_local: Path,
|
|
127
158
|
workflow_dir_remote: Path,
|
|
128
159
|
runner: BaseRunner,
|
|
129
|
-
get_runner_config:
|
|
130
|
-
[
|
|
131
|
-
WorkflowTaskV2,
|
|
132
|
-
Literal["non_parallel", "parallel"],
|
|
133
|
-
Path | None,
|
|
134
|
-
int,
|
|
135
|
-
],
|
|
136
|
-
Any,
|
|
137
|
-
],
|
|
160
|
+
get_runner_config: GetRunnerConfigType,
|
|
138
161
|
dataset_id: int,
|
|
139
162
|
history_run_id: int,
|
|
140
163
|
task_type: Literal[TaskType.NON_PARALLEL, TaskType.CONVERTER_NON_PARALLEL],
|
|
@@ -163,8 +186,10 @@ def run_v2_task_non_parallel(
|
|
|
163
186
|
)
|
|
164
187
|
|
|
165
188
|
runner_config = get_runner_config(
|
|
189
|
+
shared_config=runner.shared_config,
|
|
166
190
|
wftask=wftask,
|
|
167
191
|
which_type="non_parallel",
|
|
192
|
+
tot_tasks=1,
|
|
168
193
|
)
|
|
169
194
|
|
|
170
195
|
function_kwargs = {
|
|
@@ -251,15 +276,7 @@ def run_v2_task_parallel(
|
|
|
251
276
|
runner: BaseRunner,
|
|
252
277
|
workflow_dir_local: Path,
|
|
253
278
|
workflow_dir_remote: Path,
|
|
254
|
-
get_runner_config:
|
|
255
|
-
[
|
|
256
|
-
WorkflowTaskV2,
|
|
257
|
-
Literal["non_parallel", "parallel"],
|
|
258
|
-
Path | None,
|
|
259
|
-
int,
|
|
260
|
-
],
|
|
261
|
-
Any,
|
|
262
|
-
],
|
|
279
|
+
get_runner_config: GetRunnerConfigType,
|
|
263
280
|
dataset_id: int,
|
|
264
281
|
history_run_id: int,
|
|
265
282
|
user_id: int,
|
|
@@ -278,6 +295,7 @@ def run_v2_task_parallel(
|
|
|
278
295
|
)
|
|
279
296
|
|
|
280
297
|
runner_config = get_runner_config(
|
|
298
|
+
shared_config=runner.shared_config,
|
|
281
299
|
wftask=wftask,
|
|
282
300
|
which_type="parallel",
|
|
283
301
|
tot_tasks=len(images),
|
|
@@ -382,15 +400,7 @@ def run_v2_task_compound(
|
|
|
382
400
|
runner: BaseRunner,
|
|
383
401
|
workflow_dir_local: Path,
|
|
384
402
|
workflow_dir_remote: Path,
|
|
385
|
-
get_runner_config:
|
|
386
|
-
[
|
|
387
|
-
WorkflowTaskV2,
|
|
388
|
-
Literal["non_parallel", "parallel"],
|
|
389
|
-
Path | None,
|
|
390
|
-
int,
|
|
391
|
-
],
|
|
392
|
-
Any,
|
|
393
|
-
],
|
|
403
|
+
get_runner_config: GetRunnerConfigType,
|
|
394
404
|
dataset_id: int,
|
|
395
405
|
history_run_id: int,
|
|
396
406
|
task_type: Literal[TaskType.COMPOUND, TaskType.CONVERTER_COMPOUND],
|
|
@@ -407,9 +417,12 @@ def run_v2_task_compound(
|
|
|
407
417
|
)
|
|
408
418
|
|
|
409
419
|
runner_config_init = get_runner_config(
|
|
420
|
+
shared_config=runner.shared_config,
|
|
410
421
|
wftask=wftask,
|
|
411
422
|
which_type="non_parallel",
|
|
423
|
+
tot_tasks=1,
|
|
412
424
|
)
|
|
425
|
+
|
|
413
426
|
# 3/A: non-parallel init task
|
|
414
427
|
function_kwargs = {
|
|
415
428
|
"zarr_dir": zarr_dir,
|
|
@@ -505,6 +518,7 @@ def run_v2_task_compound(
|
|
|
505
518
|
return init_outcome, num_tasks
|
|
506
519
|
|
|
507
520
|
runner_config_compute = get_runner_config(
|
|
521
|
+
shared_config=runner.shared_config,
|
|
508
522
|
wftask=wftask,
|
|
509
523
|
which_type="parallel",
|
|
510
524
|
tot_tasks=len(parallelization_list),
|