fractal-server 2.17.1__tar.gz → 2.17.1a0__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 (266) hide show
  1. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/PKG-INFO +1 -1
  2. fractal_server-2.17.1a0/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/__init__.py +1 -0
  4. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/security.py +14 -1
  5. fractal_server-2.17.1a0/fractal_server/app/models/user_settings.py +37 -0
  6. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/project.py +4 -1
  7. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/task_group.py +4 -1
  8. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/shutdown.py +19 -23
  9. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/config/_main.py +1 -1
  10. fractal_server-2.17.1a0/fractal_server/data_migrations/2_17_0.py +339 -0
  11. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/pyproject.toml +3 -3
  12. fractal_server-2.17.1/fractal_server/__init__.py +0 -1
  13. fractal_server-2.17.1/fractal_server/migrations/versions/45fbb391d7af_make_resource_id_fk_non_nullable.py +0 -46
  14. fractal_server-2.17.1/fractal_server/migrations/versions/49d0856e9569_drop_table.py +0 -63
  15. fractal_server-2.17.1/fractal_server/migrations/versions/7673fe18c05d_remove_project_dir_server_default.py +0 -29
  16. fractal_server-2.17.1/fractal_server/migrations/versions/caba9fb1ea5e_drop_useroauth_user_settings_id.py +0 -49
  17. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/LICENSE +0 -0
  18. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/README.md +0 -0
  19. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/__main__.py +0 -0
  20. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/alembic.ini +0 -0
  21. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/__init__.py +0 -0
  22. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/db/__init__.py +0 -0
  23. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/linkusergroup.py +0 -0
  24. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/linkuserproject.py +0 -0
  25. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/__init__.py +0 -0
  26. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/accounting.py +0 -0
  27. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/dataset.py +0 -0
  28. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/history.py +0 -0
  29. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/job.py +0 -0
  30. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/profile.py +0 -0
  31. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/resource.py +0 -0
  32. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/task.py +0 -0
  33. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/workflow.py +0 -0
  34. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/models/v2/workflowtask.py +0 -0
  35. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/__init__.py +0 -0
  36. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/__init__.py +0 -0
  37. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  38. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/_aux_functions.py +0 -0
  39. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  40. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  41. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/job.py +0 -0
  42. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/profile.py +0 -0
  43. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/project.py +0 -0
  44. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/resource.py +0 -0
  45. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/task.py +0 -0
  46. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  47. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
  48. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/__init__.py +0 -0
  49. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  50. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  51. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
  52. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
  53. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
  54. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
  55. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
  56. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  57. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/history.py +0 -0
  58. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/images.py +0 -0
  59. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/job.py +0 -0
  60. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
  61. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/project.py +0 -0
  62. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
  63. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/submit.py +0 -0
  64. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/task.py +0 -0
  65. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
  66. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  67. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/task_collection_pixi.py +0 -0
  68. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  69. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
  70. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/task_version_update.py +0 -0
  71. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  72. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  73. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  74. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/__init__.py +0 -0
  75. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  76. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/current_user.py +0 -0
  77. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/group.py +0 -0
  78. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/login.py +0 -0
  79. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/oauth.py +0 -0
  80. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/register.py +0 -0
  81. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/router.py +0 -0
  82. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/auth/users.py +0 -0
  83. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/aux/__init__.py +0 -0
  84. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/aux/_job.py +0 -0
  85. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/aux/_runner.py +0 -0
  86. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/aux/validate_user_profile.py +0 -0
  87. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/routes/pagination.py +0 -0
  88. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/__init__.py +0 -0
  89. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/user.py +0 -0
  90. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/user_group.py +0 -0
  91. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/__init__.py +0 -0
  92. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/accounting.py +0 -0
  93. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/dataset.py +0 -0
  94. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/dumps.py +0 -0
  95. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/history.py +0 -0
  96. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/job.py +0 -0
  97. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/manifest.py +0 -0
  98. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/profile.py +0 -0
  99. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/project.py +0 -0
  100. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/resource.py +0 -0
  101. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  102. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/task.py +0 -0
  103. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  104. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/task_group.py +0 -0
  105. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/workflow.py +0 -0
  106. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  107. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/security/__init__.py +0 -0
  108. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/app/security/signup_email.py +0 -0
  109. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/config/__init__.py +0 -0
  110. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/config/_data.py +0 -0
  111. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/config/_database.py +0 -0
  112. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/config/_email.py +0 -0
  113. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/config/_oauth.py +0 -0
  114. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/config/_settings_config.py +0 -0
  115. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/data_migrations/README.md +0 -0
  116. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/data_migrations/tools.py +0 -0
  117. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/exceptions.py +0 -0
  118. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/gunicorn_fractal.py +0 -0
  119. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/images/__init__.py +0 -0
  120. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/images/models.py +0 -0
  121. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/images/status_tools.py +0 -0
  122. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/images/tools.py +0 -0
  123. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/logger.py +0 -0
  124. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/main.py +0 -0
  125. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/env.py +0 -0
  126. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/naming_convention.py +0 -0
  127. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  128. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  129. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +0 -0
  130. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  131. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/1a83a5260664_rename.py +0 -0
  132. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  133. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  134. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  135. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  136. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  137. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  138. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  139. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  140. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  141. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  142. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
  143. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +0 -0
  144. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  145. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  146. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  147. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  148. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
  149. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  150. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +0 -0
  151. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  152. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  153. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  154. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  155. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  156. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  157. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  158. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
  159. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +0 -0
  160. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
  161. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  162. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  163. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  164. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  165. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  166. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  167. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  168. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
  169. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  170. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  171. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/py.typed +0 -0
  172. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/__init__.py +0 -0
  173. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/components.py +0 -0
  174. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/config/__init__.py +0 -0
  175. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/config/_local.py +0 -0
  176. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/config/_slurm.py +0 -0
  177. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/config/slurm_mem_to_MB.py +0 -0
  178. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/exceptions.py +0 -0
  179. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/__init__.py +0 -0
  180. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/base_runner.py +0 -0
  181. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/call_command_wrapper.py +0 -0
  182. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/local/__init__.py +0 -0
  183. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/local/get_local_config.py +0 -0
  184. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/local/runner.py +0 -0
  185. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/__init__.py +0 -0
  186. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/_batching.py +0 -0
  187. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/_job_states.py +0 -0
  188. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/base_slurm_runner.py +0 -0
  189. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/get_slurm_config.py +0 -0
  190. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/remote.py +0 -0
  191. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/slurm_config.py +0 -0
  192. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
  193. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_ssh/__init__.py +0 -0
  194. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_ssh/run_subprocess.py +0 -0
  195. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_ssh/runner.py +0 -0
  196. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_ssh/tar_commands.py +0 -0
  197. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_sudo/__init__.py +0 -0
  198. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  199. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/executors/slurm_sudo/runner.py +0 -0
  200. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/filenames.py +0 -0
  201. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/set_start_and_last_task_index.py +0 -0
  202. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/task_files.py +0 -0
  203. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/__init__.py +0 -0
  204. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/_local.py +0 -0
  205. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/_slurm_ssh.py +0 -0
  206. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/_slurm_sudo.py +0 -0
  207. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/db_tools.py +0 -0
  208. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/deduplicate_list.py +0 -0
  209. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/merge_outputs.py +0 -0
  210. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/runner.py +0 -0
  211. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/runner_functions.py +0 -0
  212. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/submit_workflow.py +0 -0
  213. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/v2/task_interface.py +0 -0
  214. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/runner/versions.py +0 -0
  215. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/ssh/__init__.py +0 -0
  216. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/ssh/_fabric.py +0 -0
  217. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/string_tools.py +0 -0
  218. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/syringe.py +0 -0
  219. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/__init__.py +0 -0
  220. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/config/__init__.py +0 -0
  221. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/config/_pixi.py +0 -0
  222. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/config/_python.py +0 -0
  223. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/utils.py +0 -0
  224. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/__init__.py +0 -0
  225. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/__init__.py +0 -0
  226. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/_utils.py +0 -0
  227. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/collect.py +0 -0
  228. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/collect_pixi.py +0 -0
  229. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  230. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
  231. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/delete.py +0 -0
  232. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  233. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/local/reactivate_pixi.py +0 -0
  234. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  235. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py +0 -0
  236. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  237. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  238. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/collect_pixi.py +0 -0
  239. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  240. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
  241. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/delete.py +0 -0
  242. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  243. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +0 -0
  244. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  245. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  246. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  247. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  248. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  249. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  250. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +0 -0
  251. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/pixi_2_install.sh +0 -0
  252. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +0 -0
  253. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/utils_background.py +0 -0
  254. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/utils_database.py +0 -0
  255. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  256. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/utils_pixi.py +0 -0
  257. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  258. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/tasks/v2/utils_templates.py +0 -0
  259. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/types/__init__.py +0 -0
  260. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/types/validators/__init__.py +0 -0
  261. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/types/validators/_common_validators.py +0 -0
  262. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/types/validators/_filter_validators.py +0 -0
  263. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
  264. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/urls.py +0 -0
  265. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/utils.py +0 -0
  266. {fractal_server-2.17.1 → fractal_server-2.17.1a0}/fractal_server/zip_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fractal-server
3
- Version: 2.17.1
3
+ Version: 2.17.1a0
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.17.1a0"
@@ -6,4 +6,5 @@ will not be picked up by alembic.
6
6
  from .linkusergroup import LinkUserGroup # noqa: F401
7
7
  from .linkuserproject import LinkUserProjectV2 # noqa: F401
8
8
  from .security import * # noqa
9
+ from .user_settings import UserSettings # noqa
9
10
  from .v2 import * # noqa
@@ -95,11 +95,24 @@ class UserOAuth(SQLModel, table=True):
95
95
  ondelete="RESTRICT",
96
96
  )
97
97
 
98
- project_dir: str
98
+ # TODO-2.17.1: update to `project_dir: str`
99
+ project_dir: str = Field(
100
+ sa_column=Column(
101
+ String,
102
+ server_default="/PLACEHOLDER",
103
+ nullable=False,
104
+ )
105
+ )
99
106
  slurm_accounts: list[str] = Field(
100
107
  sa_column=Column(ARRAY(String), server_default="{}"),
101
108
  )
102
109
 
110
+ # TODO-2.17.1: remove
111
+ user_settings_id: int | None = Field(
112
+ foreign_key="user_settings.id",
113
+ default=None,
114
+ )
115
+
103
116
 
104
117
  class UserGroup(SQLModel, table=True):
105
118
  """
@@ -0,0 +1,37 @@
1
+ from sqlalchemy import Column
2
+ from sqlalchemy.dialects.postgresql import JSONB
3
+ from sqlmodel import Field
4
+ from sqlmodel import SQLModel
5
+
6
+
7
+ # TODO-2.17.1: Drop `UserSettings`
8
+ class UserSettings(SQLModel, table=True):
9
+ """
10
+ Comprehensive list of user settings.
11
+
12
+ Attributes:
13
+ id: ID of database object
14
+ slurm_accounts:
15
+ List of SLURM accounts, to be used upon Fractal job submission.
16
+ ssh_host: SSH-reachable host where a SLURM client is available.
17
+ ssh_username: User on `ssh_host`.
18
+ ssh_private_key_path: Path of private SSH key for `ssh_username`.
19
+ slurm_user: Local user, to be impersonated via `sudo -u`
20
+ project_dir: Folder where `slurm_user` can write.
21
+ """
22
+
23
+ __tablename__ = "user_settings"
24
+
25
+ id: int | None = Field(default=None, primary_key=True)
26
+ slurm_accounts: list[str] = Field(
27
+ sa_column=Column(JSONB, server_default="[]", nullable=False)
28
+ )
29
+ ssh_host: str | None = None
30
+ ssh_username: str | None = None
31
+ ssh_private_key_path: str | None = None
32
+
33
+ slurm_user: str | None = None
34
+ project_dir: str | None = None
35
+
36
+ ssh_tasks_dir: str | None = None
37
+ ssh_jobs_dir: str | None = None
@@ -15,7 +15,10 @@ class ProjectV2(SQLModel, table=True):
15
15
  id: int | None = Field(default=None, primary_key=True)
16
16
  name: str
17
17
 
18
- resource_id: int = Field(foreign_key="resource.id", ondelete="RESTRICT")
18
+ # TODO-2.17.1: make `resource_id` not nullable
19
+ resource_id: int | None = Field(
20
+ foreign_key="resource.id", default=None, ondelete="RESTRICT"
21
+ )
19
22
  timestamp_created: datetime = Field(
20
23
  default_factory=get_timestamp,
21
24
  sa_column=Column(DateTime(timezone=True), nullable=False),
@@ -42,7 +42,10 @@ class TaskGroupV2(SQLModel, table=True):
42
42
  user_group_id: int | None = Field(
43
43
  foreign_key="usergroup.id", default=None, ondelete="SET NULL"
44
44
  )
45
- resource_id: int = Field(foreign_key="resource.id", ondelete="RESTRICT")
45
+ # TODO-2.17.1: make `resource_id` not nullable
46
+ resource_id: int | None = Field(
47
+ foreign_key="resource.id", default=None, ondelete="RESTRICT"
48
+ )
46
49
 
47
50
  origin: str
48
51
  pkg_name: str
@@ -12,48 +12,44 @@ from fractal_server.syringe import Inject
12
12
 
13
13
 
14
14
  async def cleanup_after_shutdown(*, jobsV2: list[int], logger_name: str):
15
- settings = Inject(get_settings)
16
15
  logger = get_logger(logger_name)
17
16
  logger.info("Cleanup function after shutdown")
18
- stm_objects = (
17
+ stm_v2 = (
19
18
  select(JobV2)
20
19
  .where(JobV2.id.in_(jobsV2))
21
20
  .where(JobV2.status == JobStatusTypeV2.SUBMITTED)
22
21
  )
23
- stm_ids = (
24
- select(JobV2.id)
25
- .where(JobV2.id.in_(jobsV2))
26
- .where(JobV2.status == JobStatusTypeV2.SUBMITTED)
27
- )
28
22
 
29
23
  async for session in get_async_db():
30
- # Write shutdown file for all jobs
31
- jobs = (await session.execute(stm_objects)).scalars().all()
32
- for job in jobs:
24
+ jobsV2_db = (await session.execute(stm_v2)).scalars().all()
25
+
26
+ for job in jobsV2_db:
33
27
  _write_shutdown_file(job=job)
34
28
 
35
- # Wait for completion of all job - with a timeout
36
- interval = settings.FRACTAL_GRACEFUL_SHUTDOWN_TIME / 20
29
+ settings = Inject(get_settings)
30
+
37
31
  t_start = time.perf_counter()
38
32
  while (
39
33
  time.perf_counter() - t_start
40
- ) <= settings.FRACTAL_GRACEFUL_SHUTDOWN_TIME:
41
- job_ids = (await session.execute(stm_ids)).scalars().all()
42
- if len(job_ids) == 0:
43
- logger.info("All jobs are either done or failed. Exit.")
34
+ ) < settings.FRACTAL_GRACEFUL_SHUTDOWN_TIME: # 30 seconds
35
+ logger.info("Waiting 3 seconds before checking")
36
+ time.sleep(3)
37
+ jobsV2_db = (await session.execute(stm_v2)).scalars().all()
38
+
39
+ if len(jobsV2_db) == 0:
40
+ logger.info(
41
+ "All jobs associated to this app are "
42
+ "either done or failed. Exit."
43
+ )
44
44
  return
45
45
  else:
46
- logger.info(f"Some jobs are still 'submitted': {job_ids=}")
47
- logger.info(f"Wait {interval:.4f} seconds before next check.")
48
- time.sleep(interval)
46
+ logger.info(f"Some jobs are still 'submitted' {jobsV2_db=}")
49
47
  logger.info(
50
48
  "Graceful shutdown reached its maximum time, "
51
- "but some jobs are still submitted."
49
+ "but some jobs are still submitted"
52
50
  )
53
51
 
54
- # Mark jobs as failed and update their logs.
55
- jobs = (await session.execute(stm_objects)).scalars().all()
56
- for job in jobs:
52
+ for job in jobsV2_db:
57
53
  job.status = "failed"
58
54
  job.log = (job.log or "") + "\nJob stopped due to app shutdown\n"
59
55
  session.add(job)
@@ -57,7 +57,7 @@ class Settings(BaseSettings):
57
57
  `app.state`.
58
58
  """
59
59
 
60
- FRACTAL_GRACEFUL_SHUTDOWN_TIME: float = 30.0
60
+ FRACTAL_GRACEFUL_SHUTDOWN_TIME: int = 30
61
61
  """
62
62
  Waiting time for the shutdown phase of executors
63
63
  """
@@ -0,0 +1,339 @@
1
+ import json
2
+ import logging
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from dotenv.main import DotEnv
8
+ from pydantic import BaseModel
9
+ from sqlalchemy.orm import Session
10
+ from sqlalchemy.sql.operators import is_
11
+ from sqlalchemy.sql.operators import is_not
12
+ from sqlmodel import select
13
+
14
+ from fractal_server.app.db import get_sync_db
15
+ from fractal_server.app.models import Profile
16
+ from fractal_server.app.models import ProjectV2
17
+ from fractal_server.app.models import Resource
18
+ from fractal_server.app.models import TaskGroupV2
19
+ from fractal_server.app.models import UserOAuth
20
+ from fractal_server.app.models import UserSettings
21
+ from fractal_server.app.schemas.v2.profile import cast_serialize_profile
22
+ from fractal_server.app.schemas.v2.resource import cast_serialize_resource
23
+ from fractal_server.config import get_settings
24
+ from fractal_server.runner.config import JobRunnerConfigLocal
25
+ from fractal_server.runner.config import JobRunnerConfigSLURM
26
+ from fractal_server.tasks.config import TasksPixiSettings
27
+ from fractal_server.tasks.config import TasksPythonSettings
28
+ from fractal_server.types import AbsolutePathStr
29
+ from fractal_server.types import ListUniqueNonEmptyString
30
+ from fractal_server.urls import normalize_url
31
+
32
+ logging.basicConfig(level=logging.INFO)
33
+
34
+
35
+ class UserUpdateInfo(BaseModel):
36
+ user_id: int
37
+ project_dir: AbsolutePathStr
38
+ slurm_accounts: ListUniqueNonEmptyString
39
+
40
+
41
+ class ProfileUsersUpdateInfo(BaseModel):
42
+ data: dict[str, Any]
43
+ user_updates: list[UserUpdateInfo]
44
+
45
+
46
+ def _get_user_settings(user: UserOAuth, db: Session) -> UserSettings:
47
+ if user.user_settings_id is None:
48
+ sys.exit(f"User {user.email} is active but {user.user_settings_id=}.")
49
+ user_settings = db.get(UserSettings, user.user_settings_id)
50
+ return user_settings
51
+
52
+
53
+ def assert_user_setting_key(
54
+ user: UserOAuth,
55
+ user_settings: UserSettings,
56
+ keys: list[str],
57
+ ) -> None:
58
+ for key in keys:
59
+ if getattr(user_settings, key) is None:
60
+ sys.exit(
61
+ f"User {user.email} is active and verified but their "
62
+ f"user settings have {key}=None."
63
+ )
64
+
65
+
66
+ def prepare_profile_and_user_updates() -> dict[str, ProfileUsersUpdateInfo]:
67
+ settings = get_settings()
68
+ profiles_and_users: dict[str, ProfileUsersUpdateInfo] = {}
69
+ with next(get_sync_db()) as db:
70
+ # Get active&verified users
71
+ res = db.execute(
72
+ select(UserOAuth)
73
+ .where(is_(UserOAuth.is_active, True))
74
+ .where(is_(UserOAuth.is_verified, True))
75
+ .order_by(UserOAuth.id)
76
+ )
77
+ for user in res.unique().scalars().all():
78
+ # Get user settings
79
+ user_settings = _get_user_settings(user=user, db=db)
80
+ assert_user_setting_key(user, user_settings, ["project_dir"])
81
+
82
+ # Prepare profile data and user update
83
+ new_profile_data = dict()
84
+ if settings.FRACTAL_RUNNER_BACKEND == "local":
85
+ username = None
86
+ if settings.FRACTAL_RUNNER_BACKEND == "slurm_sudo":
87
+ assert_user_setting_key(user, user_settings, ["slurm_user"])
88
+ username = user_settings.slurm_user
89
+ elif settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
90
+ assert_user_setting_key(
91
+ user,
92
+ user_settings,
93
+ [
94
+ "ssh_username",
95
+ "ssh_private_key_path",
96
+ "ssh_tasks_dir",
97
+ "ssh_jobs_dir",
98
+ ],
99
+ )
100
+ username = user_settings.ssh_username
101
+ new_profile_data.update(
102
+ ssh_key_path=user_settings.ssh_private_key_path,
103
+ tasks_remote_dir=normalize_url(
104
+ user_settings.ssh_tasks_dir
105
+ ),
106
+ jobs_remote_dir=normalize_url(user_settings.ssh_jobs_dir),
107
+ )
108
+
109
+ new_profile_data.update(
110
+ name=f"Profile {username}",
111
+ username=username,
112
+ resource_type=settings.FRACTAL_RUNNER_BACKEND,
113
+ )
114
+ cast_serialize_profile(new_profile_data)
115
+
116
+ user_update_info = UserUpdateInfo(
117
+ user_id=user.id,
118
+ project_dir=normalize_url(user_settings.project_dir),
119
+ slurm_accounts=user_settings.slurm_accounts or [],
120
+ )
121
+
122
+ if username in profiles_and_users.keys():
123
+ if profiles_and_users[username].data != new_profile_data:
124
+ error_msg = (
125
+ "Profile data mismatch.\n"
126
+ f"{profiles_and_users[username].data=}\n"
127
+ f"{new_profile_data=}"
128
+ )
129
+ logging.error(error_msg)
130
+ sys.exit(error_msg)
131
+ profiles_and_users[username].user_updates.append(
132
+ user_update_info
133
+ )
134
+ else:
135
+ profiles_and_users[username] = ProfileUsersUpdateInfo(
136
+ data=new_profile_data,
137
+ user_updates=[user_update_info],
138
+ )
139
+
140
+ return profiles_and_users
141
+
142
+
143
+ def get_old_dotenv_variables() -> dict[str, str | None]:
144
+ """
145
+ See
146
+ https://github.com/fractal-analytics-platform/fractal-server/blob/2.16.x/fractal_server/config.py
147
+ """
148
+ OLD_DOTENV_FILE = ".fractal_server.env.old"
149
+ return dict(
150
+ **DotEnv(
151
+ dotenv_path=OLD_DOTENV_FILE,
152
+ override=False,
153
+ ).dict()
154
+ )
155
+
156
+
157
+ def get_TasksPythonSettings(
158
+ old_config: dict[str, str | None]
159
+ ) -> dict[str, Any]:
160
+ versions = {}
161
+ for version_underscore in ["3_9", "3_10", "3_11", "3_12"]:
162
+ key = f"FRACTAL_TASKS_PYTHON_{version_underscore}"
163
+ version_dot = version_underscore.replace("_", ".")
164
+ value = old_config.get(key, None)
165
+ if value is not None:
166
+ versions[version_dot] = value
167
+ obj = TasksPythonSettings(
168
+ default_version=old_config["FRACTAL_TASKS_PYTHON_DEFAULT_VERSION"],
169
+ versions=versions,
170
+ pip_cache_dir=old_config.get("FRACTAL_PIP_CACHE_DIR", None),
171
+ )
172
+ return obj.model_dump()
173
+
174
+
175
+ def get_TasksPixiSettings(old_config: dict[str, str | None]) -> dict[str, Any]:
176
+ pixi_file = old_config.get("FRACTAL_PIXI_CONFIG_FILE", None)
177
+ if pixi_file is None:
178
+ return {}
179
+ with open(pixi_file) as f:
180
+ old_pixi_config = json.load(f)
181
+ TasksPixiSettings(**old_pixi_config)
182
+ return old_pixi_config
183
+
184
+
185
+ def get_JobRunnerConfigSLURM(
186
+ old_config: dict[str, str | None]
187
+ ) -> dict[str, Any]:
188
+ slurm_file = old_config["FRACTAL_SLURM_CONFIG_FILE"]
189
+ with open(slurm_file) as f:
190
+ old_slurm_config = json.load(f)
191
+ JobRunnerConfigSLURM(**old_slurm_config)
192
+ return old_slurm_config
193
+
194
+
195
+ def get_JobRunnerConfigLocal(
196
+ old_config: dict[str, str | None]
197
+ ) -> dict[str, Any]:
198
+ local_file = old_config.get("FRACTAL_LOCAL_CONFIG_FILE", None)
199
+ if local_file is None or not Path(local_file).exists():
200
+ return JobRunnerConfigLocal().model_dump()
201
+ else:
202
+ with open(local_file) as f:
203
+ old_local_config = json.load(f)
204
+ JobRunnerConfigLocal(**old_local_config)
205
+ return old_local_config
206
+
207
+
208
+ def get_ssh_host() -> str:
209
+ with next(get_sync_db()) as db:
210
+ res = db.execute(
211
+ select(UserSettings.ssh_host).where(
212
+ is_not(UserSettings.ssh_host, None)
213
+ )
214
+ )
215
+ hosts = res.scalars().all()
216
+ if len(set(hosts)) > 1:
217
+ host = max(set(hosts), key=hosts.count)
218
+ print(f"MOST FREQUENT HOST: {host}")
219
+ else:
220
+ host = hosts[0]
221
+ return host
222
+
223
+
224
+ def prepare_resource_data(old_config: dict[str, str | None]) -> dict[str, Any]:
225
+ settings = get_settings()
226
+
227
+ resource_data = dict(
228
+ type=settings.FRACTAL_RUNNER_BACKEND,
229
+ name="Resource Name",
230
+ tasks_python_config=get_TasksPythonSettings(old_config),
231
+ tasks_pixi_config=get_TasksPixiSettings(old_config),
232
+ tasks_local_dir=old_config["FRACTAL_TASKS_DIR"],
233
+ jobs_local_dir=old_config["FRACTAL_RUNNER_WORKING_BASE_DIR"],
234
+ jobs_poll_interval=int(
235
+ old_config.get("FRACTAL_SLURM_POLL_INTERVAL", 15)
236
+ ),
237
+ )
238
+ if settings.FRACTAL_RUNNER_BACKEND == "local":
239
+ resource_data["jobs_runner_config"] = get_JobRunnerConfigLocal(
240
+ old_config
241
+ )
242
+ elif settings.FRACTAL_RUNNER_BACKEND == "slurm_sudo":
243
+ resource_data["jobs_slurm_python_worker"] = old_config[
244
+ "FRACTAL_SLURM_WORKER_PYTHON"
245
+ ]
246
+ resource_data["jobs_runner_config"] = get_JobRunnerConfigSLURM(
247
+ old_config
248
+ )
249
+ else:
250
+ resource_data["jobs_slurm_python_worker"] = old_config[
251
+ "FRACTAL_SLURM_WORKER_PYTHON"
252
+ ]
253
+ resource_data["jobs_runner_config"] = get_JobRunnerConfigSLURM(
254
+ old_config
255
+ )
256
+ resource_data["host"] = get_ssh_host()
257
+
258
+ resource_data = cast_serialize_resource(resource_data)
259
+
260
+ return resource_data
261
+
262
+
263
+ def fix_db():
264
+ logging.info("START preliminary checks.")
265
+
266
+ # Read old env file
267
+ old_config = get_old_dotenv_variables()
268
+
269
+ # Prepare resource data
270
+ logging.info("START prepare_resource_data")
271
+ resource_data = prepare_resource_data(old_config)
272
+ logging.info("END prepare_resource_data")
273
+
274
+ # Prepare profile/users data
275
+ logging.info("START prepare_profile_and_user_updates")
276
+ profile_and_user_updates = prepare_profile_and_user_updates()
277
+ logging.info("END prepare_profile_and_user_updates")
278
+
279
+ logging.info("END preliminary checks.")
280
+ print()
281
+
282
+ with next(get_sync_db()) as db:
283
+ # Create new resource
284
+ resource = Resource(**resource_data)
285
+ db.add(resource)
286
+ db.commit()
287
+ db.refresh(resource)
288
+ db.expunge(resource)
289
+ resource_id = resource.id
290
+ logging.info(f"Created resource with {resource_id=}.")
291
+
292
+ # Update task groups
293
+ res = db.execute(select(TaskGroupV2).order_by(TaskGroupV2.id))
294
+ for taskgroup in res.scalars().all():
295
+ taskgroup.resource_id = resource_id
296
+ db.add(taskgroup)
297
+ db.commit()
298
+ logging.info(f"Set {resource_id=} foreign key for all task groups.")
299
+
300
+ # Update projects
301
+ res = db.execute(select(ProjectV2).order_by(ProjectV2.id))
302
+ for project in res.scalars().all():
303
+ project.resource_id = resource_id
304
+ db.add(project)
305
+ db.commit()
306
+ logging.info(f"Set {resource_id=} foreign key for all projects.")
307
+ print()
308
+
309
+ db.expunge_all()
310
+
311
+ for _, info in profile_and_user_updates.items():
312
+ # Create profile
313
+ profile_data = info.data
314
+ profile_data["resource_id"] = resource_id
315
+ profile = Profile(**profile_data)
316
+ db.add(profile)
317
+ db.commit()
318
+ db.refresh(profile)
319
+ db.expunge(profile)
320
+ profile_id = profile.id
321
+ logging.info(
322
+ f"Created profile '{profile.name}', with {profile.id=}."
323
+ )
324
+
325
+ # Update users
326
+ for user_update in info.user_updates:
327
+ user = db.get(UserOAuth, user_update.user_id)
328
+ user.profile_id = profile_id
329
+ user.project_dir = user_update.project_dir
330
+ user.slurm_accounts = user_update.slurm_accounts
331
+ db.add(user)
332
+ logging.info(f"Updated {user.email} with {user.project_dir=}.")
333
+ logging.info(
334
+ f"Associated {user.email} to profile {profile.name}."
335
+ )
336
+ print()
337
+ db.commit()
338
+
339
+ logging.info("END - all ok.")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fractal-server"
3
- version = "2.17.1"
3
+ version = "2.17.1a0"
4
4
  description = "Backend component of the Fractal analytics platform"
5
5
  authors = [
6
6
  { name="Tommaso Comparin", email="tommaso.comparin@exact-lab.it" },
@@ -94,7 +94,7 @@ filterwarnings = [
94
94
  markers = ["container", "ssh", "fails_on_macos", "oauth"]
95
95
 
96
96
  [tool.bumpver]
97
- current_version = "2.17.1"
97
+ current_version = "2.17.1a0"
98
98
  version_pattern = "MAJOR.MINOR.PATCH[PYTAGNUM]"
99
99
  commit_message = "bump version {old_version} -> {new_version}"
100
100
  commit = true
@@ -130,5 +130,5 @@ POSTGRES_USER="postgres"
130
130
  POSTGRES_PASSWORD="postgres"
131
131
  POSTGRES_DB="fractal_test"
132
132
  FRACTAL_API_MAX_JOB_LIST_LENGTH=1
133
- FRACTAL_GRACEFUL_SHUTDOWN_TIME=0.05
133
+ FRACTAL_GRACEFUL_SHUTDOWN_TIME=1
134
134
  FRACTAL_DEFAULT_GROUP_NAME="All"
@@ -1 +0,0 @@
1
- __VERSION__ = "2.17.1"
@@ -1,46 +0,0 @@
1
- """Make resource_id FK non-nullable
2
-
3
- Revision ID: 45fbb391d7af
4
- Revises: caba9fb1ea5e
5
- Create Date: 2025-11-11 16:39:12.813766
6
-
7
- """
8
- import sqlalchemy as sa
9
- from alembic import op
10
-
11
-
12
- # revision identifiers, used by Alembic.
13
- revision = "45fbb391d7af"
14
- down_revision = "caba9fb1ea5e"
15
- branch_labels = None
16
- depends_on = None
17
-
18
-
19
- def upgrade() -> None:
20
- # ### commands auto generated by Alembic - please adjust! ###
21
- with op.batch_alter_table("projectv2", schema=None) as batch_op:
22
- batch_op.alter_column(
23
- "resource_id", existing_type=sa.INTEGER(), nullable=False
24
- )
25
-
26
- with op.batch_alter_table("taskgroupv2", schema=None) as batch_op:
27
- batch_op.alter_column(
28
- "resource_id", existing_type=sa.INTEGER(), nullable=False
29
- )
30
-
31
- # ### end Alembic commands ###
32
-
33
-
34
- def downgrade() -> None:
35
- # ### commands auto generated by Alembic - please adjust! ###
36
- with op.batch_alter_table("taskgroupv2", schema=None) as batch_op:
37
- batch_op.alter_column(
38
- "resource_id", existing_type=sa.INTEGER(), nullable=True
39
- )
40
-
41
- with op.batch_alter_table("projectv2", schema=None) as batch_op:
42
- batch_op.alter_column(
43
- "resource_id", existing_type=sa.INTEGER(), nullable=True
44
- )
45
-
46
- # ### end Alembic commands ###
@@ -1,63 +0,0 @@
1
- """Drop table
2
-
3
- Revision ID: 49d0856e9569
4
- Revises: 45fbb391d7af
5
- Create Date: 2025-11-11 16:39:41.497832
6
-
7
- """
8
- import sqlalchemy as sa
9
- from alembic import op
10
- from sqlalchemy.dialects import postgresql
11
-
12
- # revision identifiers, used by Alembic.
13
- revision = "49d0856e9569"
14
- down_revision = "45fbb391d7af"
15
- branch_labels = None
16
- depends_on = None
17
-
18
-
19
- def upgrade() -> None:
20
- # ### commands auto generated by Alembic - please adjust! ###
21
- op.drop_table("user_settings")
22
- # ### end Alembic commands ###
23
-
24
-
25
- def downgrade() -> None:
26
- # ### commands auto generated by Alembic - please adjust! ###
27
- op.create_table(
28
- "user_settings",
29
- sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
30
- sa.Column(
31
- "slurm_accounts",
32
- postgresql.JSONB(astext_type=sa.Text()),
33
- server_default=sa.text("'[]'::json"),
34
- autoincrement=False,
35
- nullable=False,
36
- ),
37
- sa.Column(
38
- "ssh_host", sa.VARCHAR(), autoincrement=False, nullable=True
39
- ),
40
- sa.Column(
41
- "ssh_username", sa.VARCHAR(), autoincrement=False, nullable=True
42
- ),
43
- sa.Column(
44
- "ssh_private_key_path",
45
- sa.VARCHAR(),
46
- autoincrement=False,
47
- nullable=True,
48
- ),
49
- sa.Column(
50
- "ssh_tasks_dir", sa.VARCHAR(), autoincrement=False, nullable=True
51
- ),
52
- sa.Column(
53
- "ssh_jobs_dir", sa.VARCHAR(), autoincrement=False, nullable=True
54
- ),
55
- sa.Column(
56
- "slurm_user", sa.VARCHAR(), autoincrement=False, nullable=True
57
- ),
58
- sa.Column(
59
- "project_dir", sa.VARCHAR(), autoincrement=False, nullable=True
60
- ),
61
- sa.PrimaryKeyConstraint("id", name=op.f("pk_user_settings")),
62
- )
63
- # ### end Alembic commands ###