fractal-server 2.9.0a2__tar.gz → 2.9.0a4__tar.gz

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 (249) hide show
  1. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/PKG-INFO +1 -1
  2. fractal_server-2.9.0a4/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/admin/v2/__init__.py +4 -0
  4. fractal_server-2.9.0a4/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +260 -0
  5. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/task_collection.py +3 -10
  6. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +50 -6
  7. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/_validators.py +0 -14
  8. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/applyworkflow.py +0 -8
  9. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/dataset.py +0 -5
  10. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/project.py +0 -5
  11. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/state.py +0 -5
  12. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/workflow.py +0 -5
  13. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/dataset.py +0 -6
  14. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/job.py +0 -8
  15. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/project.py +0 -5
  16. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/workflow.py +0 -5
  17. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/ssh/_fabric.py +4 -2
  18. fractal_server-2.9.0a2/fractal_server/tasks/v2/local/utils_local.py → fractal_server-2.9.0a4/fractal_server/tasks/v2/local/_utils.py +25 -0
  19. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/local/collect.py +2 -2
  20. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/local/deactivate.py +1 -1
  21. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/local/reactivate.py +1 -1
  22. fractal_server-2.9.0a4/fractal_server/tasks/v2/ssh/__init__.py +3 -0
  23. fractal_server-2.9.0a4/fractal_server/tasks/v2/ssh/_utils.py +87 -0
  24. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/ssh/collect.py +4 -79
  25. fractal_server-2.9.0a4/fractal_server/tasks/v2/ssh/deactivate.py +243 -0
  26. fractal_server-2.9.0a4/fractal_server/tasks/v2/ssh/reactivate.py +199 -0
  27. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/utils_background.py +0 -24
  28. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/zip_tools.py +21 -4
  29. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/pyproject.toml +2 -2
  30. fractal_server-2.9.0a2/fractal_server/__init__.py +0 -1
  31. fractal_server-2.9.0a2/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  32. fractal_server-2.9.0a2/fractal_server/tasks/v2/ssh/deactivate.py +0 -2
  33. fractal_server-2.9.0a2/fractal_server/tasks/v2/ssh/reactivate.py +0 -2
  34. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/LICENSE +0 -0
  35. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/README.md +0 -0
  36. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/__main__.py +0 -0
  37. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/alembic.ini +0 -0
  38. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/__init__.py +0 -0
  39. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/db/__init__.py +0 -0
  40. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/__init__.py +0 -0
  41. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/linkusergroup.py +0 -0
  42. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/linkuserproject.py +0 -0
  43. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/security.py +0 -0
  44. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/user_settings.py +0 -0
  45. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v1/__init__.py +0 -0
  46. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v1/dataset.py +0 -0
  47. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v1/job.py +0 -0
  48. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v1/project.py +0 -0
  49. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v1/state.py +0 -0
  50. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v1/task.py +0 -0
  51. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v1/workflow.py +0 -0
  52. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/__init__.py +0 -0
  53. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/dataset.py +0 -0
  54. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/job.py +0 -0
  55. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/project.py +0 -0
  56. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/task.py +0 -0
  57. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/task_group.py +0 -0
  58. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/workflow.py +0 -0
  59. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/models/v2/workflowtask.py +0 -0
  60. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/__init__.py +0 -0
  61. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/admin/__init__.py +0 -0
  62. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/admin/v1.py +0 -0
  63. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/admin/v2/job.py +0 -0
  64. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/admin/v2/project.py +0 -0
  65. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/admin/v2/task.py +0 -0
  66. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  67. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/__init__.py +0 -0
  68. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/__init__.py +0 -0
  69. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/_aux_functions.py +0 -0
  70. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/dataset.py +0 -0
  71. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/job.py +0 -0
  72. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/project.py +0 -0
  73. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/task.py +0 -0
  74. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/task_collection.py +0 -0
  75. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/workflow.py +0 -0
  76. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v1/workflowtask.py +0 -0
  77. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  78. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  79. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
  80. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
  81. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  82. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/images.py +0 -0
  83. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/job.py +0 -0
  84. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/project.py +0 -0
  85. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/status.py +0 -0
  86. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/submit.py +0 -0
  87. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/task.py +0 -0
  88. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  89. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  90. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  91. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  92. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  93. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/__init__.py +0 -0
  94. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  95. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/current_user.py +0 -0
  96. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/group.py +0 -0
  97. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/login.py +0 -0
  98. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/oauth.py +0 -0
  99. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/register.py +0 -0
  100. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/router.py +0 -0
  101. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/auth/users.py +0 -0
  102. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/aux/__init__.py +0 -0
  103. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/aux/_job.py +0 -0
  104. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/aux/_runner.py +0 -0
  105. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/aux/_timestamp.py +0 -0
  106. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
  107. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/.gitignore +0 -0
  108. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/__init__.py +0 -0
  109. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/async_wrap.py +0 -0
  110. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/components.py +0 -0
  111. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/compress_folder.py +0 -0
  112. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/exceptions.py +0 -0
  113. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/__init__.py +0 -0
  114. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/__init__.py +0 -0
  115. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/_batching.py +0 -0
  116. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/_slurm_config.py +0 -0
  117. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/remote.py +0 -0
  118. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/ssh/__init__.py +0 -0
  119. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py +0 -0
  120. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -0
  121. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/ssh/executor.py +0 -0
  122. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/sudo/__init__.py +0 -0
  123. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py +0 -0
  124. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py +0 -0
  125. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/sudo/_subprocess_run_as_user.py +0 -0
  126. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/executors/slurm/sudo/executor.py +0 -0
  127. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/extract_archive.py +0 -0
  128. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/filenames.py +0 -0
  129. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/run_subprocess.py +0 -0
  130. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
  131. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/shutdown.py +0 -0
  132. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/task_files.py +0 -0
  133. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/__init__.py +0 -0
  134. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_common.py +0 -0
  135. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_local/__init__.py +0 -0
  136. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_local/_local_config.py +0 -0
  137. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_local/_submit_setup.py +0 -0
  138. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_local/executor.py +0 -0
  139. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_slurm/__init__.py +0 -0
  140. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_slurm/_submit_setup.py +0 -0
  141. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/_slurm/get_slurm_config.py +0 -0
  142. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/common.py +0 -0
  143. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v1/handle_failed_job.py +0 -0
  144. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/__init__.py +0 -0
  145. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local/__init__.py +0 -0
  146. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local/_local_config.py +0 -0
  147. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local/_submit_setup.py +0 -0
  148. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local/executor.py +0 -0
  149. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local_experimental/__init__.py +0 -0
  150. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local_experimental/_local_config.py +0 -0
  151. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local_experimental/_submit_setup.py +0 -0
  152. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_local_experimental/executor.py +0 -0
  153. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_slurm_common/__init__.py +0 -0
  154. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py +0 -0
  155. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_slurm_ssh/__init__.py +0 -0
  156. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py +0 -0
  157. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_slurm_sudo/__init__.py +0 -0
  158. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py +0 -0
  159. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
  160. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/handle_failed_job.py +0 -0
  161. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
  162. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/runner.py +0 -0
  163. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/runner_functions.py +0 -0
  164. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
  165. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/v2/task_interface.py +0 -0
  166. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/runner/versions.py +0 -0
  167. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/__init__.py +0 -0
  168. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/user.py +0 -0
  169. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/user_group.py +0 -0
  170. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/user_settings.py +0 -0
  171. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/__init__.py +0 -0
  172. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/dumps.py +0 -0
  173. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/manifest.py +0 -0
  174. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/task.py +0 -0
  175. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v1/task_collection.py +0 -0
  176. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/__init__.py +0 -0
  177. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/dumps.py +0 -0
  178. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/manifest.py +0 -0
  179. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/status.py +0 -0
  180. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/task.py +0 -0
  181. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  182. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/task_group.py +0 -0
  183. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  184. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/security/__init__.py +0 -0
  185. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/app/user_settings.py +0 -0
  186. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/config.py +0 -0
  187. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/data_migrations/README.md +0 -0
  188. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/data_migrations/tools.py +0 -0
  189. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/gunicorn_fractal.py +0 -0
  190. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/images/__init__.py +0 -0
  191. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/images/models.py +0 -0
  192. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/images/tools.py +0 -0
  193. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/logger.py +0 -0
  194. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/main.py +0 -0
  195. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/README +0 -0
  196. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/env.py +0 -0
  197. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/naming_convention.py +0 -0
  198. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/script.py.mako +0 -0
  199. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  200. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  201. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  202. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/3082479ac4ea_taskgroup_activity_and_venv_info_to_.py +0 -0
  203. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  204. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  205. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  206. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  207. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  208. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  209. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  210. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  211. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  212. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  213. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  214. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  215. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  216. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  217. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  218. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  219. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  220. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  221. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  222. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  223. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  224. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/py.typed +0 -0
  225. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/ssh/__init__.py +0 -0
  226. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/string_tools.py +0 -0
  227. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/syringe.py +0 -0
  228. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/__init__.py +0 -0
  229. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/utils.py +0 -0
  230. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v1/_TaskCollectPip.py +0 -0
  231. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v1/__init__.py +0 -0
  232. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v1/background_operations.py +0 -0
  233. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v1/endpoint_operations.py +0 -0
  234. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v1/get_collection_data.py +0 -0
  235. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v1/utils.py +0 -0
  236. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/__init__.py +0 -0
  237. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/local/__init__.py +0 -0
  238. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  239. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  240. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  241. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  242. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  243. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  244. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/utils_database.py +0 -0
  245. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  246. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  247. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/tasks/v2/utils_templates.py +0 -0
  248. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/urls.py +0 -0
  249. {fractal_server-2.9.0a2 → fractal_server-2.9.0a4}/fractal_server/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 2.9.0a2
3
+ Version: 2.9.0a4
4
4
  Summary: Server component of the Fractal analytics platform
5
5
  Home-page: https://github.com/fractal-analytics-platform/fractal-server
6
6
  License: BSD-3-Clause
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.9.0a4"
@@ -7,6 +7,7 @@ from .job import router as job_router
7
7
  from .project import router as project_router
8
8
  from .task import router as task_router
9
9
  from .task_group import router as task_group_router
10
+ from .task_group_lifecycle import router as task_group_lifecycle_router
10
11
 
11
12
  router_admin_v2 = APIRouter()
12
13
 
@@ -14,3 +15,6 @@ router_admin_v2.include_router(job_router, prefix="/job")
14
15
  router_admin_v2.include_router(project_router, prefix="/project")
15
16
  router_admin_v2.include_router(task_router, prefix="/task")
16
17
  router_admin_v2.include_router(task_group_router, prefix="/task-group")
18
+ router_admin_v2.include_router(
19
+ task_group_lifecycle_router, prefix="/task-group"
20
+ )
@@ -0,0 +1,260 @@
1
+ from fastapi import APIRouter
2
+ from fastapi import BackgroundTasks
3
+ from fastapi import Depends
4
+ from fastapi import HTTPException
5
+ from fastapi import Request
6
+ from fastapi import Response
7
+ from fastapi import status
8
+
9
+ from fractal_server.app.db import AsyncSession
10
+ from fractal_server.app.db import get_async_db
11
+ from fractal_server.app.models import UserOAuth
12
+ from fractal_server.app.models.v2 import TaskGroupActivityV2
13
+ from fractal_server.app.routes.api.v2._aux_functions_task_lifecycle import (
14
+ check_no_ongoing_activity,
15
+ )
16
+ from fractal_server.app.routes.api.v2._aux_functions_tasks import (
17
+ _get_task_group_or_404,
18
+ )
19
+ from fractal_server.app.routes.auth import current_active_superuser
20
+ from fractal_server.app.routes.aux.validate_user_settings import (
21
+ validate_user_settings,
22
+ )
23
+ from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
24
+ from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
25
+ from fractal_server.app.schemas.v2 import TaskGroupActivityV2Read
26
+ from fractal_server.app.schemas.v2 import TaskGroupReadV2
27
+ from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
28
+ from fractal_server.config import get_settings
29
+ from fractal_server.logger import set_logger
30
+ from fractal_server.syringe import Inject
31
+ from fractal_server.tasks.v2.local import deactivate_local
32
+ from fractal_server.tasks.v2.local import reactivate_local
33
+ from fractal_server.tasks.v2.ssh import deactivate_ssh
34
+ from fractal_server.tasks.v2.ssh import reactivate_ssh
35
+ from fractal_server.utils import get_timestamp
36
+
37
+ router = APIRouter()
38
+
39
+ logger = set_logger(__name__)
40
+
41
+
42
+ @router.post(
43
+ "/{task_group_id}/deactivate/",
44
+ response_model=TaskGroupActivityV2Read,
45
+ )
46
+ async def deactivate_task_group(
47
+ task_group_id: int,
48
+ background_tasks: BackgroundTasks,
49
+ response: Response,
50
+ request: Request,
51
+ superuser: UserOAuth = Depends(current_active_superuser),
52
+ db: AsyncSession = Depends(get_async_db),
53
+ ) -> TaskGroupReadV2:
54
+ """
55
+ Deactivate task-group venv
56
+ """
57
+ task_group = await _get_task_group_or_404(
58
+ task_group_id=task_group_id, db=db
59
+ )
60
+
61
+ # Check no other activity is ongoing
62
+ await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
63
+
64
+ # Check that task-group is active
65
+ if not task_group.active:
66
+ raise HTTPException(
67
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
68
+ detail=(
69
+ f"Cannot deactivate a task group with {task_group.active=}."
70
+ ),
71
+ )
72
+
73
+ # Shortcut for task-group with origin="other"
74
+ if task_group.origin == TaskGroupV2OriginEnum.OTHER:
75
+ task_group.active = False
76
+ task_group_activity = TaskGroupActivityV2(
77
+ user_id=task_group.user_id,
78
+ taskgroupv2_id=task_group.id,
79
+ status=TaskGroupActivityStatusV2.OK,
80
+ action=TaskGroupActivityActionV2.DEACTIVATE,
81
+ pkg_name=task_group.pkg_name,
82
+ version=(task_group.version or "N/A"),
83
+ log=(
84
+ f"Task group has {task_group.origin=}, set "
85
+ "task_group.active to False and exit."
86
+ ),
87
+ timestamp_started=get_timestamp(),
88
+ timestamp_ended=get_timestamp(),
89
+ )
90
+ db.add(task_group)
91
+ db.add(task_group_activity)
92
+ await db.commit()
93
+ response.status_code = status.HTTP_202_ACCEPTED
94
+ return task_group_activity
95
+
96
+ task_group_activity = TaskGroupActivityV2(
97
+ user_id=task_group.user_id,
98
+ taskgroupv2_id=task_group.id,
99
+ status=TaskGroupActivityStatusV2.PENDING,
100
+ action=TaskGroupActivityActionV2.DEACTIVATE,
101
+ pkg_name=task_group.pkg_name,
102
+ version=task_group.version,
103
+ timestamp_started=get_timestamp(),
104
+ )
105
+ task_group.active = False
106
+ db.add(task_group)
107
+ db.add(task_group_activity)
108
+ await db.commit()
109
+
110
+ # Submit background task
111
+ settings = Inject(get_settings)
112
+ if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
113
+ # Validate user settings (backend-specific)
114
+ user = await db.get(UserOAuth, task_group.user_id)
115
+ user_settings = await validate_user_settings(
116
+ user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
117
+ )
118
+ # User appropriate FractalSSH object
119
+ ssh_credentials = dict(
120
+ user=user_settings.ssh_username,
121
+ host=user_settings.ssh_host,
122
+ key_path=user_settings.ssh_private_key_path,
123
+ )
124
+ fractal_ssh_list = request.app.state.fractal_ssh_list
125
+ fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
126
+
127
+ background_tasks.add_task(
128
+ deactivate_ssh,
129
+ task_group_id=task_group.id,
130
+ task_group_activity_id=task_group_activity.id,
131
+ fractal_ssh=fractal_ssh,
132
+ tasks_base_dir=user_settings.ssh_tasks_dir,
133
+ )
134
+ else:
135
+ background_tasks.add_task(
136
+ deactivate_local,
137
+ task_group_id=task_group.id,
138
+ task_group_activity_id=task_group_activity.id,
139
+ )
140
+
141
+ logger.debug(
142
+ "Admin task group deactivation endpoint: start deactivate "
143
+ "and return task_group_activity"
144
+ )
145
+ response.status_code = status.HTTP_202_ACCEPTED
146
+ return task_group_activity
147
+
148
+
149
+ @router.post(
150
+ "/{task_group_id}/reactivate/",
151
+ response_model=TaskGroupActivityV2Read,
152
+ )
153
+ async def reactivate_task_group(
154
+ task_group_id: int,
155
+ background_tasks: BackgroundTasks,
156
+ response: Response,
157
+ request: Request,
158
+ superuser: UserOAuth = Depends(current_active_superuser),
159
+ db: AsyncSession = Depends(get_async_db),
160
+ ) -> TaskGroupReadV2:
161
+ """
162
+ Deactivate task-group venv
163
+ """
164
+
165
+ task_group = await _get_task_group_or_404(
166
+ task_group_id=task_group_id, db=db
167
+ )
168
+
169
+ # Check that task-group is not active
170
+ if task_group.active:
171
+ raise HTTPException(
172
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
173
+ detail=(
174
+ f"Cannot reactivate a task group with {task_group.active=}."
175
+ ),
176
+ )
177
+
178
+ # Check no other activity is ongoing
179
+ await check_no_ongoing_activity(task_group_id=task_group_id, db=db)
180
+
181
+ # Shortcut for task-group with origin="other"
182
+ if task_group.origin == TaskGroupV2OriginEnum.OTHER:
183
+ task_group.active = True
184
+ task_group_activity = TaskGroupActivityV2(
185
+ user_id=task_group.user_id,
186
+ taskgroupv2_id=task_group.id,
187
+ status=TaskGroupActivityStatusV2.OK,
188
+ action=TaskGroupActivityActionV2.REACTIVATE,
189
+ pkg_name=task_group.pkg_name,
190
+ version=(task_group.version or "N/A"),
191
+ log=(
192
+ f"Task group has {task_group.origin=}, set "
193
+ "task_group.active to True and exit."
194
+ ),
195
+ timestamp_started=get_timestamp(),
196
+ timestamp_ended=get_timestamp(),
197
+ )
198
+ db.add(task_group)
199
+ db.add(task_group_activity)
200
+ await db.commit()
201
+ response.status_code = status.HTTP_202_ACCEPTED
202
+ return task_group_activity
203
+
204
+ if task_group.pip_freeze is None:
205
+ raise HTTPException(
206
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
207
+ detail=(
208
+ "Cannot reactivate a task group with "
209
+ f"{task_group.pip_freeze=}."
210
+ ),
211
+ )
212
+
213
+ task_group_activity = TaskGroupActivityV2(
214
+ user_id=task_group.user_id,
215
+ taskgroupv2_id=task_group.id,
216
+ status=TaskGroupActivityStatusV2.PENDING,
217
+ action=TaskGroupActivityActionV2.REACTIVATE,
218
+ pkg_name=task_group.pkg_name,
219
+ version=task_group.version,
220
+ timestamp_started=get_timestamp(),
221
+ )
222
+ db.add(task_group_activity)
223
+ await db.commit()
224
+
225
+ # Submit background task
226
+ settings = Inject(get_settings)
227
+ if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
228
+ # Validate user settings (backend-specific)
229
+ user = await db.get(UserOAuth, task_group.user_id)
230
+ user_settings = await validate_user_settings(
231
+ user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
232
+ )
233
+ # Use appropriate FractalSSH object
234
+ ssh_credentials = dict(
235
+ user=user_settings.ssh_username,
236
+ host=user_settings.ssh_host,
237
+ key_path=user_settings.ssh_private_key_path,
238
+ )
239
+ fractal_ssh_list = request.app.state.fractal_ssh_list
240
+ fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
241
+
242
+ background_tasks.add_task(
243
+ reactivate_ssh,
244
+ task_group_id=task_group.id,
245
+ task_group_activity_id=task_group_activity.id,
246
+ fractal_ssh=fractal_ssh,
247
+ tasks_base_dir=user_settings.ssh_tasks_dir,
248
+ )
249
+ else:
250
+ background_tasks.add_task(
251
+ reactivate_local,
252
+ task_group_id=task_group.id,
253
+ task_group_activity_id=task_group_activity.id,
254
+ )
255
+ logger.debug(
256
+ "Admin task group reactivation endpoint: start reactivate "
257
+ "and return task_group_activity"
258
+ )
259
+ response.status_code = status.HTTP_202_ACCEPTED
260
+ return task_group_activity
@@ -37,6 +37,7 @@ from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
37
37
  from fractal_server.tasks.v2.local.collect import (
38
38
  collect_local,
39
39
  )
40
+ from fractal_server.tasks.v2.ssh import collect_ssh
40
41
  from fractal_server.tasks.v2.utils_package_names import _parse_wheel_filename
41
42
  from fractal_server.tasks.v2.utils_package_names import normalize_package_name
42
43
  from fractal_server.tasks.v2.utils_python_interpreter import (
@@ -63,10 +64,7 @@ async def collect_tasks_pip(
63
64
  db: AsyncSession = Depends(get_async_db),
64
65
  ) -> TaskGroupActivityV2Read:
65
66
  """
66
- Task collection endpoint
67
-
68
- Trigger the creation of a dedicated virtual environment, the installation
69
- of a package and the collection of tasks as advertised in the manifest.
67
+ Task-collection endpoint
70
68
  """
71
69
 
72
70
  # Get settings
@@ -246,12 +244,7 @@ async def collect_tasks_pip(
246
244
 
247
245
  if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
248
246
  # SSH task collection
249
-
250
- from fractal_server.tasks.v2.ssh.collect import (
251
- collect_ssh,
252
- )
253
-
254
- # User appropriate FractalSSH object
247
+ # Use appropriate FractalSSH object
255
248
  ssh_credentials = dict(
256
249
  user=user_settings.ssh_username,
257
250
  host=user_settings.ssh_host,
@@ -2,9 +2,11 @@ from fastapi import APIRouter
2
2
  from fastapi import BackgroundTasks
3
3
  from fastapi import Depends
4
4
  from fastapi import HTTPException
5
+ from fastapi import Request
5
6
  from fastapi import Response
6
7
  from fastapi import status
7
8
 
9
+ from ...aux.validate_user_settings import validate_user_settings
8
10
  from ._aux_functions_task_lifecycle import check_no_ongoing_activity
9
11
  from ._aux_functions_tasks import _get_task_group_full_access
10
12
  from fractal_server.app.db import AsyncSession
@@ -22,6 +24,8 @@ from fractal_server.logger import set_logger
22
24
  from fractal_server.syringe import Inject
23
25
  from fractal_server.tasks.v2.local import deactivate_local
24
26
  from fractal_server.tasks.v2.local import reactivate_local
27
+ from fractal_server.tasks.v2.ssh import deactivate_ssh
28
+ from fractal_server.tasks.v2.ssh import reactivate_ssh
25
29
  from fractal_server.utils import get_timestamp
26
30
 
27
31
  router = APIRouter()
@@ -38,6 +42,7 @@ async def deactivate_task_group(
38
42
  task_group_id: int,
39
43
  background_tasks: BackgroundTasks,
40
44
  response: Response,
45
+ request: Request,
41
46
  user: UserOAuth = Depends(current_active_user),
42
47
  db: AsyncSession = Depends(get_async_db),
43
48
  ) -> TaskGroupReadV2:
@@ -103,10 +108,29 @@ async def deactivate_task_group(
103
108
  # Submit background task
104
109
  settings = Inject(get_settings)
105
110
  if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
106
- raise HTTPException(
107
- status_code=status.HTTP_501_NOT_IMPLEMENTED,
108
- detail="Not implemented (yet) for SSH.",
111
+
112
+ # Validate user settings (backend-specific)
113
+ user_settings = await validate_user_settings(
114
+ user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
115
+ )
116
+
117
+ # User appropriate FractalSSH object
118
+ ssh_credentials = dict(
119
+ user=user_settings.ssh_username,
120
+ host=user_settings.ssh_host,
121
+ key_path=user_settings.ssh_private_key_path,
122
+ )
123
+ fractal_ssh_list = request.app.state.fractal_ssh_list
124
+ fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
125
+
126
+ background_tasks.add_task(
127
+ deactivate_ssh,
128
+ task_group_id=task_group.id,
129
+ task_group_activity_id=task_group_activity.id,
130
+ fractal_ssh=fractal_ssh,
131
+ tasks_base_dir=user_settings.ssh_tasks_dir,
109
132
  )
133
+
110
134
  else:
111
135
  background_tasks.add_task(
112
136
  deactivate_local,
@@ -130,6 +154,7 @@ async def reactivate_task_group(
130
154
  task_group_id: int,
131
155
  background_tasks: BackgroundTasks,
132
156
  response: Response,
157
+ request: Request,
133
158
  user: UserOAuth = Depends(current_active_user),
134
159
  db: AsyncSession = Depends(get_async_db),
135
160
  ) -> TaskGroupReadV2:
@@ -203,10 +228,29 @@ async def reactivate_task_group(
203
228
  # Submit background task
204
229
  settings = Inject(get_settings)
205
230
  if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
206
- raise HTTPException(
207
- status_code=status.HTTP_501_NOT_IMPLEMENTED,
208
- detail="Not implemented (yet) for SSH.",
231
+
232
+ # Validate user settings (backend-specific)
233
+ user_settings = await validate_user_settings(
234
+ user=user, backend=settings.FRACTAL_RUNNER_BACKEND, db=db
235
+ )
236
+
237
+ # Use appropriate FractalSSH object
238
+ ssh_credentials = dict(
239
+ user=user_settings.ssh_username,
240
+ host=user_settings.ssh_host,
241
+ key_path=user_settings.ssh_private_key_path,
242
+ )
243
+ fractal_ssh_list = request.app.state.fractal_ssh_list
244
+ fractal_ssh = fractal_ssh_list.get(**ssh_credentials)
245
+
246
+ background_tasks.add_task(
247
+ reactivate_ssh,
248
+ task_group_id=task_group.id,
249
+ task_group_activity_id=task_group_activity.id,
250
+ fractal_ssh=fractal_ssh,
251
+ tasks_base_dir=user_settings.ssh_tasks_dir,
209
252
  )
253
+
210
254
  else:
211
255
  background_tasks.add_task(
212
256
  reactivate_local,
@@ -1,6 +1,4 @@
1
1
  import os
2
- from datetime import datetime
3
- from datetime import timezone
4
2
  from typing import Any
5
3
  from typing import Optional
6
4
 
@@ -103,15 +101,3 @@ def val_unique_list(attribute: str):
103
101
  return must_be_unique
104
102
 
105
103
  return val
106
-
107
-
108
- def valutc(attribute: str):
109
- def val(timestamp: Optional[datetime]) -> Optional[datetime]:
110
- """
111
- Replace `tzinfo` with `timezone.utc`.
112
- """
113
- if timestamp is not None:
114
- return timestamp.replace(tzinfo=timezone.utc)
115
- return None
116
-
117
- return val
@@ -7,7 +7,6 @@ from pydantic import validator
7
7
  from pydantic.types import StrictStr
8
8
 
9
9
  from .._validators import valstr
10
- from .._validators import valutc
11
10
  from .dumps import DatasetDumpV1
12
11
  from .dumps import ProjectDumpV1
13
12
  from .dumps import WorkflowDumpV1
@@ -150,13 +149,6 @@ class ApplyWorkflowReadV1(_ApplyWorkflowBaseV1):
150
149
  first_task_index: Optional[int]
151
150
  last_task_index: Optional[int]
152
151
 
153
- _start_timestamp = validator("start_timestamp", allow_reuse=True)(
154
- valutc("start_timestamp")
155
- )
156
- _end_timestamp = validator("end_timestamp", allow_reuse=True)(
157
- valutc("end_timestamp")
158
- )
159
-
160
152
 
161
153
  class ApplyWorkflowUpdateV1(BaseModel):
162
154
  """
@@ -8,7 +8,6 @@ from pydantic import validator
8
8
 
9
9
  from .._validators import val_absolute_path
10
10
  from .._validators import valstr
11
- from .._validators import valutc
12
11
  from .dumps import WorkflowTaskDumpV1
13
12
  from .project import ProjectReadV1
14
13
  from .workflow import WorkflowTaskStatusTypeV1
@@ -151,10 +150,6 @@ class DatasetReadV1(_DatasetBaseV1):
151
150
  project: ProjectReadV1
152
151
  timestamp_created: datetime
153
152
 
154
- _timestamp_created = validator("timestamp_created", allow_reuse=True)(
155
- valutc("timestamp_created")
156
- )
157
-
158
153
 
159
154
  class DatasetStatusReadV1(BaseModel):
160
155
  """
@@ -5,7 +5,6 @@ from pydantic import BaseModel
5
5
  from pydantic import validator
6
6
 
7
7
  from .._validators import valstr
8
- from .._validators import valutc
9
8
 
10
9
 
11
10
  __all__ = (
@@ -50,10 +49,6 @@ class ProjectReadV1(_ProjectBaseV1):
50
49
  id: int
51
50
  timestamp_created: datetime
52
51
 
53
- _timestamp_created = validator("timestamp_created", allow_reuse=True)(
54
- valutc("timestamp_created")
55
- )
56
-
57
52
 
58
53
  class ProjectUpdateV1(_ProjectBaseV1):
59
54
  """
@@ -3,9 +3,6 @@ from typing import Any
3
3
  from typing import Optional
4
4
 
5
5
  from pydantic import BaseModel
6
- from pydantic import validator
7
-
8
- from fractal_server.app.schemas._validators import valutc
9
6
 
10
7
 
11
8
  class StateRead(BaseModel):
@@ -19,5 +16,3 @@ class StateRead(BaseModel):
19
16
  id: Optional[int]
20
17
  data: dict[str, Any]
21
18
  timestamp: datetime
22
-
23
- _timestamp = validator("timestamp", allow_reuse=True)(valutc("timestamp"))
@@ -8,7 +8,6 @@ from pydantic import validator
8
8
 
9
9
  from .._validators import valint
10
10
  from .._validators import valstr
11
- from .._validators import valutc
12
11
  from .project import ProjectReadV1
13
12
  from .task import TaskExportV1
14
13
  from .task import TaskImportV1
@@ -135,10 +134,6 @@ class WorkflowReadV1(_WorkflowBaseV1):
135
134
  project: ProjectReadV1
136
135
  timestamp_created: datetime
137
136
 
138
- _timestamp_created = validator("timestamp_created", allow_reuse=True)(
139
- valutc("timestamp_created")
140
- )
141
-
142
137
 
143
138
  class WorkflowCreateV1(_WorkflowBaseV1):
144
139
  """
@@ -7,7 +7,6 @@ from pydantic import Field
7
7
  from pydantic import validator
8
8
 
9
9
  from .._validators import valstr
10
- from .._validators import valutc
11
10
  from .dumps import WorkflowTaskDumpV2
12
11
  from .project import ProjectReadV2
13
12
  from .workflowtask import WorkflowTaskStatusTypeV2
@@ -62,11 +61,6 @@ class DatasetReadV2(BaseModel):
62
61
  zarr_dir: str
63
62
  filters: Filters = Field(default_factory=Filters)
64
63
 
65
- # Validators
66
- _timestamp_created = validator("timestamp_created", allow_reuse=True)(
67
- valutc("timestamp_created")
68
- )
69
-
70
64
 
71
65
  class DatasetUpdateV2(BaseModel, extra=Extra.forbid):
72
66
 
@@ -8,7 +8,6 @@ from pydantic import validator
8
8
  from pydantic.types import StrictStr
9
9
 
10
10
  from .._validators import valstr
11
- from .._validators import valutc
12
11
  from .dumps import DatasetDumpV2
13
12
  from .dumps import ProjectDumpV2
14
13
  from .dumps import WorkflowDumpV2
@@ -101,13 +100,6 @@ class JobReadV2(BaseModel):
101
100
  last_task_index: Optional[int]
102
101
  worker_init: Optional[str]
103
102
 
104
- _start_timestamp = validator("start_timestamp", allow_reuse=True)(
105
- valutc("start_timestamp")
106
- )
107
- _end_timestamp = validator("end_timestamp", allow_reuse=True)(
108
- valutc("end_timestamp")
109
- )
110
-
111
103
 
112
104
  class JobUpdateV2(BaseModel, extra=Extra.forbid):
113
105
 
@@ -6,7 +6,6 @@ from pydantic import Extra
6
6
  from pydantic import validator
7
7
 
8
8
  from .._validators import valstr
9
- from .._validators import valutc
10
9
 
11
10
 
12
11
  class ProjectCreateV2(BaseModel, extra=Extra.forbid):
@@ -21,10 +20,6 @@ class ProjectReadV2(BaseModel):
21
20
  id: int
22
21
  name: str
23
22
  timestamp_created: datetime
24
- # Validators
25
- _timestamp_created = validator("timestamp_created", allow_reuse=True)(
26
- valutc("timestamp_created")
27
- )
28
23
 
29
24
 
30
25
  class ProjectUpdateV2(BaseModel, extra=Extra.forbid):
@@ -6,7 +6,6 @@ from pydantic import Extra
6
6
  from pydantic import validator
7
7
 
8
8
  from .._validators import valstr
9
- from .._validators import valutc
10
9
  from .project import ProjectReadV2
11
10
  from .workflowtask import WorkflowTaskExportV2
12
11
  from .workflowtask import WorkflowTaskImportV2
@@ -31,10 +30,6 @@ class WorkflowReadV2(BaseModel):
31
30
  project: ProjectReadV2
32
31
  timestamp_created: datetime
33
32
 
34
- _timestamp_created = validator("timestamp_created", allow_reuse=True)(
35
- valutc("timestamp_created")
36
- )
37
-
38
33
 
39
34
  class WorkflowReadV2WithWarnings(WorkflowReadV2):
40
35
  task_list: list[WorkflowTaskReadV2WithWarning]
@@ -321,8 +321,10 @@ class FractalSSH(object):
321
321
  f"{prefix} END running '{cmd}' over SSH, "
322
322
  f"elapsed {t_1-t_0:.3f}"
323
323
  )
324
- self.logger.debug(f"STDOUT: {res.stdout}")
325
- self.logger.debug(f"STDERR: {res.stderr}")
324
+ self.logger.debug("STDOUT:")
325
+ self.logger.debug(res.stdout)
326
+ self.logger.debug("STDERR:")
327
+ self.logger.debug(res.stderr)
326
328
  return res.stdout
327
329
  except NoValidConnectionsError as e:
328
330
  # Case 2: Command fails with a connection error
@@ -1,5 +1,6 @@
1
1
  from pathlib import Path
2
2
 
3
+ from fractal_server.app.schemas.v2 import TaskCreateV2
3
4
  from fractal_server.logger import get_logger
4
5
  from fractal_server.tasks.v2.utils_templates import customize_template
5
6
  from fractal_server.utils import execute_command_sync
@@ -43,3 +44,27 @@ def _customize_and_run_template(
43
44
  stdout = execute_command_sync(command=cmd, logger_name=logger_name)
44
45
  logger.debug(f"_customize_and_run_template {template_filename} - END")
45
46
  return stdout
47
+
48
+
49
+ def check_task_files_exist(task_list: list[TaskCreateV2]) -> None:
50
+ """
51
+ Check that the modules listed in task commands point to existing files.
52
+
53
+ Args:
54
+ task_list:
55
+ """
56
+ for _task in task_list:
57
+ if _task.command_non_parallel is not None:
58
+ _task_path = _task.command_non_parallel.split()[1]
59
+ if not Path(_task_path).exists():
60
+ raise FileNotFoundError(
61
+ f"Task `{_task.name}` has `command_non_parallel` "
62
+ f"pointing to missing file `{_task_path}`."
63
+ )
64
+ if _task.command_parallel is not None:
65
+ _task_path = _task.command_parallel.split()[1]
66
+ if not Path(_task_path).exists():
67
+ raise FileNotFoundError(
68
+ f"Task `{_task.name}` has `command_parallel` "
69
+ f"pointing to missing file `{_task_path}`."
70
+ )