fractal-server 2.13.0__py3-none-any.whl → 2.14.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.
Files changed (127) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/__main__.py +3 -1
  3. fractal_server/app/models/linkusergroup.py +6 -2
  4. fractal_server/app/models/v2/__init__.py +11 -1
  5. fractal_server/app/models/v2/accounting.py +35 -0
  6. fractal_server/app/models/v2/dataset.py +1 -11
  7. fractal_server/app/models/v2/history.py +78 -0
  8. fractal_server/app/models/v2/job.py +10 -3
  9. fractal_server/app/models/v2/task_group.py +2 -2
  10. fractal_server/app/models/v2/workflow.py +1 -1
  11. fractal_server/app/models/v2/workflowtask.py +1 -1
  12. fractal_server/app/routes/admin/v2/__init__.py +4 -0
  13. fractal_server/app/routes/admin/v2/accounting.py +98 -0
  14. fractal_server/app/routes/admin/v2/impersonate.py +35 -0
  15. fractal_server/app/routes/admin/v2/job.py +5 -13
  16. fractal_server/app/routes/admin/v2/task.py +1 -1
  17. fractal_server/app/routes/admin/v2/task_group.py +4 -29
  18. fractal_server/app/routes/api/__init__.py +1 -1
  19. fractal_server/app/routes/api/v2/__init__.py +8 -2
  20. fractal_server/app/routes/api/v2/_aux_functions.py +66 -0
  21. fractal_server/app/routes/api/v2/_aux_functions_history.py +166 -0
  22. fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +3 -3
  23. fractal_server/app/routes/api/v2/dataset.py +0 -17
  24. fractal_server/app/routes/api/v2/history.py +544 -0
  25. fractal_server/app/routes/api/v2/images.py +31 -43
  26. fractal_server/app/routes/api/v2/job.py +30 -0
  27. fractal_server/app/routes/api/v2/project.py +1 -53
  28. fractal_server/app/routes/api/v2/{status.py → status_legacy.py} +6 -6
  29. fractal_server/app/routes/api/v2/submit.py +17 -14
  30. fractal_server/app/routes/api/v2/task.py +3 -10
  31. fractal_server/app/routes/api/v2/task_collection_custom.py +4 -9
  32. fractal_server/app/routes/api/v2/task_group.py +2 -22
  33. fractal_server/app/routes/api/v2/verify_image_types.py +61 -0
  34. fractal_server/app/routes/api/v2/workflow.py +28 -69
  35. fractal_server/app/routes/api/v2/workflowtask.py +53 -50
  36. fractal_server/app/routes/auth/group.py +0 -16
  37. fractal_server/app/routes/auth/oauth.py +5 -3
  38. fractal_server/app/routes/aux/__init__.py +0 -20
  39. fractal_server/app/routes/pagination.py +47 -0
  40. fractal_server/app/runner/components.py +0 -3
  41. fractal_server/app/runner/compress_folder.py +57 -29
  42. fractal_server/app/runner/exceptions.py +4 -0
  43. fractal_server/app/runner/executors/base_runner.py +157 -0
  44. fractal_server/app/runner/{v2/_local/_local_config.py → executors/local/get_local_config.py} +7 -9
  45. fractal_server/app/runner/executors/local/runner.py +248 -0
  46. fractal_server/app/runner/executors/{slurm → slurm_common}/_batching.py +1 -1
  47. fractal_server/app/runner/executors/{slurm → slurm_common}/_slurm_config.py +9 -7
  48. fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +868 -0
  49. fractal_server/app/runner/{v2/_slurm_common → executors/slurm_common}/get_slurm_config.py +48 -17
  50. fractal_server/app/runner/executors/{slurm → slurm_common}/remote.py +36 -47
  51. fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +134 -0
  52. fractal_server/app/runner/executors/slurm_ssh/runner.py +268 -0
  53. fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
  54. fractal_server/app/runner/executors/{slurm/sudo → slurm_sudo}/_subprocess_run_as_user.py +2 -83
  55. fractal_server/app/runner/executors/slurm_sudo/runner.py +193 -0
  56. fractal_server/app/runner/extract_archive.py +1 -3
  57. fractal_server/app/runner/task_files.py +134 -87
  58. fractal_server/app/runner/v2/__init__.py +0 -395
  59. fractal_server/app/runner/v2/_local.py +88 -0
  60. fractal_server/app/runner/v2/{_slurm_ssh/__init__.py → _slurm_ssh.py} +22 -19
  61. fractal_server/app/runner/v2/{_slurm_sudo/__init__.py → _slurm_sudo.py} +19 -15
  62. fractal_server/app/runner/v2/db_tools.py +119 -0
  63. fractal_server/app/runner/v2/runner.py +219 -98
  64. fractal_server/app/runner/v2/runner_functions.py +491 -189
  65. fractal_server/app/runner/v2/runner_functions_low_level.py +40 -43
  66. fractal_server/app/runner/v2/submit_workflow.py +358 -0
  67. fractal_server/app/runner/v2/task_interface.py +31 -0
  68. fractal_server/app/schemas/_validators.py +13 -24
  69. fractal_server/app/schemas/user.py +10 -7
  70. fractal_server/app/schemas/user_settings.py +9 -21
  71. fractal_server/app/schemas/v2/__init__.py +10 -1
  72. fractal_server/app/schemas/v2/accounting.py +18 -0
  73. fractal_server/app/schemas/v2/dataset.py +12 -94
  74. fractal_server/app/schemas/v2/dumps.py +26 -9
  75. fractal_server/app/schemas/v2/history.py +80 -0
  76. fractal_server/app/schemas/v2/job.py +15 -8
  77. fractal_server/app/schemas/v2/manifest.py +14 -7
  78. fractal_server/app/schemas/v2/project.py +9 -7
  79. fractal_server/app/schemas/v2/status_legacy.py +35 -0
  80. fractal_server/app/schemas/v2/task.py +72 -77
  81. fractal_server/app/schemas/v2/task_collection.py +14 -32
  82. fractal_server/app/schemas/v2/task_group.py +10 -9
  83. fractal_server/app/schemas/v2/workflow.py +10 -11
  84. fractal_server/app/schemas/v2/workflowtask.py +2 -21
  85. fractal_server/app/security/__init__.py +3 -3
  86. fractal_server/app/security/signup_email.py +2 -2
  87. fractal_server/config.py +91 -90
  88. fractal_server/images/tools.py +23 -0
  89. fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +50 -0
  90. fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +250 -0
  91. fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +57 -0
  92. fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +41 -0
  93. fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +36 -0
  94. fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +39 -0
  95. fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +120 -0
  96. fractal_server/ssh/_fabric.py +28 -14
  97. fractal_server/tasks/v2/local/collect.py +2 -2
  98. fractal_server/tasks/v2/ssh/collect.py +2 -2
  99. fractal_server/tasks/v2/templates/2_pip_install.sh +1 -1
  100. fractal_server/tasks/v2/templates/4_pip_show.sh +1 -1
  101. fractal_server/tasks/v2/utils_background.py +1 -20
  102. fractal_server/tasks/v2/utils_database.py +30 -17
  103. fractal_server/tasks/v2/utils_templates.py +6 -0
  104. {fractal_server-2.13.0.dist-info → fractal_server-2.14.0.dist-info}/METADATA +4 -4
  105. {fractal_server-2.13.0.dist-info → fractal_server-2.14.0.dist-info}/RECORD +114 -99
  106. {fractal_server-2.13.0.dist-info → fractal_server-2.14.0.dist-info}/WHEEL +1 -1
  107. fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +0 -126
  108. fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -116
  109. fractal_server/app/runner/executors/slurm/ssh/executor.py +0 -1386
  110. fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +0 -71
  111. fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +0 -130
  112. fractal_server/app/runner/executors/slurm/sudo/executor.py +0 -1281
  113. fractal_server/app/runner/v2/_local/__init__.py +0 -129
  114. fractal_server/app/runner/v2/_local/_submit_setup.py +0 -52
  115. fractal_server/app/runner/v2/_local/executor.py +0 -100
  116. fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py +0 -83
  117. fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py +0 -83
  118. fractal_server/app/runner/v2/handle_failed_job.py +0 -59
  119. fractal_server/app/schemas/v2/status.py +0 -16
  120. /fractal_server/app/{runner/executors/slurm → history}/__init__.py +0 -0
  121. /fractal_server/app/runner/executors/{slurm/ssh → local}/__init__.py +0 -0
  122. /fractal_server/app/runner/executors/{slurm/sudo → slurm_common}/__init__.py +0 -0
  123. /fractal_server/app/runner/executors/{_job_states.py → slurm_common/_job_states.py} +0 -0
  124. /fractal_server/app/runner/executors/{slurm → slurm_common}/utils_executors.py +0 -0
  125. /fractal_server/app/runner/{v2/_slurm_common → executors/slurm_ssh}/__init__.py +0 -0
  126. {fractal_server-2.13.0.dist-info → fractal_server-2.14.0.dist-info}/LICENSE +0 -0
  127. {fractal_server-2.13.0.dist-info → fractal_server-2.14.0.dist-info}/entry_points.txt +0 -0
@@ -1,71 +0,0 @@
1
- from subprocess import run # nosec
2
-
3
- from ......logger import set_logger
4
- from ..._job_states import STATES_FINISHED
5
-
6
-
7
- logger = set_logger(__name__)
8
-
9
-
10
- def run_squeue(job_ids):
11
- res = run( # nosec
12
- [
13
- "squeue",
14
- "--noheader",
15
- "--format=%i %T",
16
- "--jobs",
17
- ",".join([str(j) for j in job_ids]),
18
- "--states=all",
19
- ],
20
- capture_output=True,
21
- encoding="utf-8",
22
- check=False,
23
- )
24
- if res.returncode != 0:
25
- logger.warning(
26
- f"squeue command with {job_ids}"
27
- f" failed with:\n{res.stderr=}\n{res.stdout=}"
28
- )
29
-
30
- return res
31
-
32
-
33
- def _jobs_finished(job_ids) -> set[str]:
34
- """
35
- Check which ones of the given Slurm jobs already finished
36
-
37
- The function is based on the `_jobs_finished` function from
38
- clusterfutures (version 0.5).
39
- Original Copyright: 2022 Adrian Sampson
40
- (released under the MIT licence)
41
- """
42
-
43
- # If there is no Slurm job to check, return right away
44
- if not job_ids:
45
- return set()
46
- id_to_state = dict()
47
-
48
- res = run_squeue(job_ids)
49
- if res.returncode == 0:
50
- id_to_state = {
51
- out.split()[0]: out.split()[1] for out in res.stdout.splitlines()
52
- }
53
- else:
54
- id_to_state = dict()
55
- for j in job_ids:
56
- res = run_squeue([j])
57
- if res.returncode != 0:
58
- logger.info(f"Job {j} not found. Marked it as completed")
59
- id_to_state.update({str(j): "COMPLETED"})
60
- else:
61
- id_to_state.update(
62
- {res.stdout.split()[0]: res.stdout.split()[1]}
63
- )
64
-
65
- # Finished jobs only stay in squeue for a few mins (configurable). If
66
- # a job ID isn't there, we'll assume it's finished.
67
- return {
68
- j
69
- for j in job_ids
70
- if id_to_state.get(j, "COMPLETED") in STATES_FINISHED
71
- }
@@ -1,130 +0,0 @@
1
- import os
2
- import threading
3
- import time
4
- import traceback
5
- from itertools import count
6
- from typing import Optional
7
-
8
- from ......logger import set_logger
9
- from ._check_jobs_status import _jobs_finished
10
- from fractal_server.app.runner.exceptions import JobExecutionError
11
-
12
- logger = set_logger(__name__)
13
-
14
-
15
- class FractalSlurmSudoWaitThread(threading.Thread):
16
- """
17
- Thread that monitors a pool of SLURM jobs
18
-
19
- This class is a custom re-implementation of the waiting thread class from:
20
-
21
- > clusterfutures <https://github.com/sampsyo/clusterfutures>
22
- > Original Copyright
23
- > Copyright 2021 Adrian Sampson <asampson@cs.washington.edu>
24
- > License: MIT
25
-
26
- Attributes:
27
- slurm_user:
28
- shutdown_file:
29
- shutdown_callback:
30
- slurm_poll_interval:
31
- waiting:
32
- shutdown:
33
- lock:
34
- """
35
-
36
- slurm_user: str
37
- shutdown_file: Optional[str] = None
38
- shutdown_callback: callable
39
- slurm_poll_interval: int = 30
40
- waiting: dict[tuple[str, ...], str]
41
- shutdown: bool
42
- _lock: threading.Lock
43
-
44
- def __init__(self, callback: callable, interval=1):
45
- threading.Thread.__init__(self, daemon=True)
46
- self.callback = callback
47
- self.interval = interval
48
- self.waiting = {}
49
- self._lock = threading.Lock() # To protect the .waiting dict
50
- self.shutdown = False
51
- self.active_job_ids = []
52
-
53
- def wait(
54
- self,
55
- *,
56
- filenames: tuple[str, ...],
57
- jobid: str,
58
- ):
59
- """
60
- Add a a new job to the set of jobs being waited for.
61
-
62
- A job consists of a tuple of filenames and a callback value (i.e. a
63
- SLURM job ID).
64
-
65
- Note that (with respect to clusterfutures) we replaced `filename` with
66
- `filenames`.
67
- """
68
- if self.shutdown:
69
- error_msg = "Cannot call `wait` method after executor shutdown."
70
- logger.warning(error_msg)
71
- raise JobExecutionError(info=error_msg)
72
- with self._lock:
73
- self.waiting[filenames] = jobid
74
-
75
- def check_shutdown(self, i):
76
- """
77
- Do one shutdown-file-existence check.
78
-
79
- Note: the `i` parameter allows subclasses like `SlurmWaitThread` to do
80
- something on every Nth check.
81
-
82
- Changed from clusterfutures:
83
- * Do not check for output-pickle-file existence (we rather rely on
84
- `cfut.slurm.jobs_finished`);
85
- * Check for the existence of shutdown-file.
86
- """
87
- if self.shutdown_file and os.path.exists(self.shutdown_file):
88
- logger.info(
89
- f"Detected executor-shutdown file {str(self.shutdown_file)}"
90
- )
91
- self.shutdown = True
92
-
93
- def run(self):
94
- """
95
- Overrides the original clusterfutures.FileWaitThread.run, adding a call
96
- to self.shutdown_callback.
97
-
98
- Changed from clusterfutures:
99
- * We do not rely on output-file-existence checks to verify whether a
100
- job is complete.
101
-
102
- Note that `shutdown_callback` only takes care of cleaning up the
103
- FractalSlurmExecutor variables, and then the `return` here is enough to
104
- fully clean up the `FractalFileWaitThread` object.
105
- """
106
- for i in count():
107
- if self.shutdown:
108
- self.shutdown_callback()
109
- return
110
- with self._lock:
111
- self.check(i)
112
- time.sleep(self.interval)
113
-
114
- def check(self, i):
115
- self.check_shutdown(i)
116
- if i % (self.slurm_poll_interval // self.interval) == 0:
117
- try:
118
- finished_jobs = _jobs_finished(self.waiting.values())
119
- except Exception:
120
- # Don't abandon completion checking if jobs_finished errors
121
- traceback.print_exc()
122
- return
123
-
124
- if not finished_jobs:
125
- return
126
-
127
- id_to_filenames = {v: k for (k, v) in self.waiting.items()}
128
- for finished_id in finished_jobs:
129
- self.callback(finished_id)
130
- self.waiting.pop(id_to_filenames[finished_id])