fractal-server 2.14.0a22__tar.gz → 2.14.0a24__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.
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/PKG-INFO +1 -1
- fractal_server-2.14.0a24/fractal_server/__init__.py +1 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/compress_folder.py +26 -16
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/base_slurm_runner.py +44 -16
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/slurm_job_task_models.py +48 -16
- fractal_server-2.14.0a24/fractal_server/app/runner/executors/slurm_ssh/runner.py +208 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_sudo/runner.py +29 -9
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/extract_archive.py +1 -3
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/task_files.py +18 -6
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/ssh/_fabric.py +4 -2
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/pyproject.toml +2 -2
- fractal_server-2.14.0a22/fractal_server/__init__.py +0 -1
- fractal_server-2.14.0a22/fractal_server/app/runner/executors/slurm_ssh/runner.py +0 -172
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/LICENSE +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/README.md +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/__main__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/alembic.ini +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/db/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/history/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/linkusergroup.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/linkuserproject.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/security.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/user_settings.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/accounting.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/dataset.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/history.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/job.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/project.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/task.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/task_group.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/workflow.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/models/v2/workflowtask.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/job.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/project.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/task.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/dataset.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/history.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/images.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/job.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/project.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/submit.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/task.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/task_group.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/verify_image_types.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/workflow.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/current_user.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/group.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/login.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/oauth.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/register.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/router.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/auth/users.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/aux/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/aux/_job.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/aux/_runner.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/aux/validate_user_settings.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/routes/pagination.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/components.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/exceptions.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/base_runner.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/local/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/local/get_local_config.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/local/runner.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/_batching.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/_job_states.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/_slurm_config.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/get_slurm_config.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/remote.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_common/utils_executors.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_ssh/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_sudo/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/filenames.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/run_subprocess.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/set_start_and_last_task_index.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/shutdown.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/_local.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/_slurm_ssh.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/_slurm_sudo.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/db_tools.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/deduplicate_list.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/merge_outputs.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/runner.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/runner_functions.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/runner_functions_low_level.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/submit_workflow.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/v2/task_interface.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/versions.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/_filter_validators.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/_validators.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/user.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/user_group.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/user_settings.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/accounting.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/dataset.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/dumps.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/history.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/job.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/manifest.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/project.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/task.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/task_collection.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/task_group.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/workflow.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/security/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/security/signup_email.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/user_settings.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/config.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/data_migrations/README.md +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/data_migrations/tools.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/gunicorn_fractal.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/images/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/images/models.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/images/tools.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/logger.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/main.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/env.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/naming_convention.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/py.typed +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/ssh/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/string_tools.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/syringe.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/utils.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/local/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/local/_utils.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/local/collect.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/local/deactivate.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/local/reactivate.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/ssh/collect.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/utils_background.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/utils_database.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/utils_package_names.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/tasks/v2/utils_templates.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/urls.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/utils.py +0 -0
- {fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/zip_tools.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__VERSION__ = "2.14.0a24"
|
{fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/compress_folder.py
RENAMED
@@ -35,24 +35,27 @@ def _create_tar_archive(
|
|
35
35
|
tarfile_path: str,
|
36
36
|
subfolder_path_tmp_copy: Path,
|
37
37
|
logger_name: str,
|
38
|
-
|
38
|
+
filelist_path: str | None,
|
39
39
|
):
|
40
40
|
logger = get_logger(logger_name)
|
41
41
|
logger.debug(f"[_create_tar_archive] START ({tarfile_path})")
|
42
42
|
t_start = time.perf_counter()
|
43
43
|
|
44
|
-
if
|
45
|
-
|
44
|
+
if filelist_path is None:
|
45
|
+
cmd_tar = (
|
46
|
+
f"tar -c -z -f {tarfile_path} "
|
47
|
+
f"--directory={subfolder_path_tmp_copy.as_posix()} "
|
48
|
+
"."
|
49
|
+
)
|
46
50
|
else:
|
47
|
-
|
51
|
+
cmd_tar = (
|
52
|
+
f"tar -c -z -f {tarfile_path} "
|
53
|
+
f"--directory={subfolder_path_tmp_copy.as_posix()} "
|
54
|
+
f"--files-from={filelist_path} --ignore-failed-read"
|
55
|
+
)
|
48
56
|
|
49
|
-
cmd_tar = (
|
50
|
-
f"tar czf {tarfile_path} "
|
51
|
-
f"{exclude_options} "
|
52
|
-
f"--directory={subfolder_path_tmp_copy.as_posix()} "
|
53
|
-
"."
|
54
|
-
)
|
55
57
|
logger.debug(f"cmd tar:\n{cmd_tar}")
|
58
|
+
|
56
59
|
run_subprocess(cmd=cmd_tar, logger_name=logger_name, allow_char="*")
|
57
60
|
elapsed = time.perf_counter() - t_start
|
58
61
|
logger.debug(f"[_create_tar_archive] END {elapsed=} s ({tarfile_path})")
|
@@ -75,7 +78,8 @@ def _remove_temp_subfolder(subfolder_path_tmp_copy: Path, logger_name: str):
|
|
75
78
|
|
76
79
|
|
77
80
|
def compress_folder(
|
78
|
-
subfolder_path: Path,
|
81
|
+
subfolder_path: Path,
|
82
|
+
filelist_path: str | None,
|
79
83
|
) -> str:
|
80
84
|
"""
|
81
85
|
Compress e.g. `/path/archive` into `/path/archive.tar.gz`
|
@@ -114,7 +118,7 @@ def compress_folder(
|
|
114
118
|
tarfile_path,
|
115
119
|
subfolder_path_tmp_copy,
|
116
120
|
logger_name=logger_name,
|
117
|
-
|
121
|
+
filelist_path=filelist_path,
|
118
122
|
)
|
119
123
|
return tarfile_path
|
120
124
|
|
@@ -133,15 +137,21 @@ def main(sys_argv: list[str]):
|
|
133
137
|
help_msg = (
|
134
138
|
"Expected use:\n"
|
135
139
|
"python -m fractal_server.app.runner.compress_folder "
|
136
|
-
"path/to/folder [--
|
140
|
+
"path/to/folder [--filelist /path/to/filelist]\n"
|
137
141
|
)
|
138
142
|
num_args = len(sys_argv[1:])
|
139
143
|
if num_args == 0:
|
140
144
|
sys.exit(f"Invalid argument.\n{help_msg}\nProvided: {sys_argv[1:]=}")
|
141
145
|
elif num_args == 1:
|
142
|
-
compress_folder(
|
143
|
-
|
144
|
-
|
146
|
+
compress_folder(
|
147
|
+
subfolder_path=Path(sys_argv[1]),
|
148
|
+
filelist_path=None,
|
149
|
+
)
|
150
|
+
elif num_args == 3 and sys_argv[2] == "--filelist":
|
151
|
+
compress_folder(
|
152
|
+
subfolder_path=Path(sys_argv[1]),
|
153
|
+
filelist_path=sys_argv[3],
|
154
|
+
)
|
145
155
|
else:
|
146
156
|
sys.exit(f"Invalid argument.\n{help_msg}\nProvided: {sys_argv[1:]=}")
|
147
157
|
|
@@ -60,6 +60,7 @@ class BaseSlurmRunner(BaseRunner):
|
|
60
60
|
root_dir_local: Path,
|
61
61
|
root_dir_remote: Path,
|
62
62
|
slurm_runner_type: Literal["ssh", "sudo"],
|
63
|
+
python_worker_interpreter: str,
|
63
64
|
common_script_lines: Optional[list[str]] = None,
|
64
65
|
user_cache_dir: Optional[str] = None,
|
65
66
|
poll_interval: Optional[int] = None,
|
@@ -70,6 +71,7 @@ class BaseSlurmRunner(BaseRunner):
|
|
70
71
|
self.common_script_lines = common_script_lines or []
|
71
72
|
self._check_slurm_account()
|
72
73
|
self.user_cache_dir = user_cache_dir
|
74
|
+
self.python_worker_interpreter = python_worker_interpreter
|
73
75
|
|
74
76
|
settings = Inject(get_settings)
|
75
77
|
|
@@ -327,9 +329,9 @@ class BaseSlurmRunner(BaseRunner):
|
|
327
329
|
)
|
328
330
|
logger.info("[_submit_single_sbatch] END")
|
329
331
|
|
330
|
-
def
|
332
|
+
def _fetch_artifacts(
|
331
333
|
self,
|
332
|
-
|
334
|
+
finished_slurm_jobs: list[SlurmJob],
|
333
335
|
) -> None:
|
334
336
|
raise NotImplementedError("Implement in child class.")
|
335
337
|
|
@@ -530,14 +532,14 @@ class BaseSlurmRunner(BaseRunner):
|
|
530
532
|
# Look for finished jobs
|
531
533
|
finished_job_ids = self._get_finished_jobs(job_ids=self.job_ids)
|
532
534
|
logger.debug(f"[submit] {finished_job_ids=}")
|
533
|
-
|
535
|
+
finished_jobs = [
|
536
|
+
self.jobs[_slurm_job_id] for _slurm_job_id in finished_job_ids
|
537
|
+
]
|
538
|
+
self._fetch_artifacts(finished_jobs)
|
534
539
|
with next(get_sync_db()) as db:
|
535
540
|
for slurm_job_id in finished_job_ids:
|
536
541
|
logger.debug(f"[submit] Now process {slurm_job_id=}")
|
537
542
|
slurm_job = self.jobs.pop(slurm_job_id)
|
538
|
-
self._copy_files_from_remote_to_local(
|
539
|
-
slurm_job
|
540
|
-
) # FIXME: add prefix # noqa
|
541
543
|
was_job_scancelled = slurm_job_id in scancelled_job_ids
|
542
544
|
result, exception = self._postprocess_single_task(
|
543
545
|
task=slurm_job.tasks[0],
|
@@ -653,7 +655,9 @@ class BaseSlurmRunner(BaseRunner):
|
|
653
655
|
if len(args_batches) != math.ceil(tot_tasks / tasks_per_job):
|
654
656
|
raise RuntimeError("Something wrong here while batching tasks")
|
655
657
|
|
656
|
-
|
658
|
+
# Part 1/3: Iterate over chunks, prepare SlurmJob objects
|
659
|
+
logger.info("[multisubmit] Prepare `SlurmJob`s.")
|
660
|
+
jobs_to_submit = []
|
657
661
|
for ind_batch, chunk in enumerate(args_batches):
|
658
662
|
prefix = f"{MULTISUBMIT_PREFIX}-{ind_batch:06d}"
|
659
663
|
tasks = []
|
@@ -673,17 +677,26 @@ class BaseSlurmRunner(BaseRunner):
|
|
673
677
|
),
|
674
678
|
)
|
675
679
|
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
680
|
+
jobs_to_submit.append(
|
681
|
+
SlurmJob(
|
682
|
+
prefix=prefix,
|
683
|
+
workdir_local=workdir_local,
|
684
|
+
workdir_remote=workdir_remote,
|
685
|
+
tasks=tasks,
|
686
|
+
)
|
681
687
|
)
|
688
|
+
|
689
|
+
# FIXME: split parts 2 and 3
|
690
|
+
# Part 2/3. Transfer all relevant input files (for SSH)
|
691
|
+
# Part 3/3. Run all `sbatch`es and update `self.jobs`
|
692
|
+
logger.info("[multisubmit] Transfer files and submit jobs.")
|
693
|
+
for slurm_job in jobs_to_submit:
|
682
694
|
self._submit_single_sbatch(
|
683
695
|
func,
|
684
696
|
slurm_job=slurm_job,
|
685
697
|
slurm_config=config,
|
686
698
|
)
|
699
|
+
|
687
700
|
if task_type == "parallel":
|
688
701
|
# FIXME: replace loop with a `bulk_update_history_unit` function
|
689
702
|
for ind, task_files in enumerate(list_task_files):
|
@@ -711,20 +724,21 @@ class BaseSlurmRunner(BaseRunner):
|
|
711
724
|
|
712
725
|
# Retrieval phase
|
713
726
|
logger.info("[multisubmit] START retrieval phase")
|
727
|
+
scancelled_job_ids = []
|
714
728
|
while len(self.jobs) > 0:
|
715
729
|
|
716
730
|
# Look for finished jobs
|
717
731
|
finished_job_ids = self._get_finished_jobs(job_ids=self.job_ids)
|
718
732
|
logger.debug(f"[multisubmit] {finished_job_ids=}")
|
733
|
+
finished_jobs = [
|
734
|
+
self.jobs[_slurm_job_id] for _slurm_job_id in finished_job_ids
|
735
|
+
]
|
736
|
+
self._fetch_artifacts(finished_jobs)
|
719
737
|
|
720
|
-
scancelled_job_ids = []
|
721
738
|
with next(get_sync_db()) as db:
|
722
739
|
for slurm_job_id in finished_job_ids:
|
723
740
|
logger.info(f"[multisubmit] Now process {slurm_job_id=}")
|
724
741
|
slurm_job = self.jobs.pop(slurm_job_id)
|
725
|
-
self._copy_files_from_remote_to_local(
|
726
|
-
slurm_job
|
727
|
-
) # FIXME: add prefix # noqa
|
728
742
|
for task in slurm_job.tasks:
|
729
743
|
logger.info(f"[multisubmit] Now process {task.index=}")
|
730
744
|
was_job_scancelled = slurm_job_id in scancelled_job_ids
|
@@ -810,3 +824,17 @@ class BaseSlurmRunner(BaseRunner):
|
|
810
824
|
)
|
811
825
|
logger.info("[scancel_jobs] END")
|
812
826
|
return scancelled_job_ids
|
827
|
+
|
828
|
+
def validate_slurm_jobs_workdirs(
|
829
|
+
self,
|
830
|
+
slurm_jobs: list[SlurmJob],
|
831
|
+
) -> None:
|
832
|
+
"""
|
833
|
+
Check that a list of `SlurmJob`s have homogeneous working folders.
|
834
|
+
"""
|
835
|
+
set_workdir_local = set(_job.workdir_local for _job in slurm_jobs)
|
836
|
+
set_workdir_remote = set(_job.workdir_remote for _job in slurm_jobs)
|
837
|
+
if len(set_workdir_local) > 1:
|
838
|
+
raise ValueError(f"Non-unique values in {set_workdir_local=}.")
|
839
|
+
if len(set_workdir_remote) > 1:
|
840
|
+
raise ValueError(f"Non-unique values in {set_workdir_remote=}.")
|
@@ -20,31 +20,47 @@ class SlurmTask(BaseModel):
|
|
20
20
|
index: int
|
21
21
|
|
22
22
|
@property
|
23
|
-
def
|
23
|
+
def input_pickle_file_local_path(self) -> Path:
|
24
24
|
return (
|
25
25
|
self.workdir_local / f"{self.prefix}-{self.component}-input.pickle"
|
26
|
-
)
|
26
|
+
)
|
27
27
|
|
28
28
|
@property
|
29
|
-
def
|
29
|
+
def input_pickle_file_remote_path(self) -> Path:
|
30
30
|
return (
|
31
31
|
self.workdir_remote
|
32
32
|
/ f"{self.prefix}-{self.component}-input.pickle"
|
33
|
-
)
|
33
|
+
)
|
34
34
|
|
35
35
|
@property
|
36
|
-
def
|
36
|
+
def output_pickle_file_local_path(self) -> Path:
|
37
37
|
return (
|
38
38
|
self.workdir_local
|
39
39
|
/ f"{self.prefix}-{self.component}-output.pickle"
|
40
|
-
)
|
40
|
+
)
|
41
41
|
|
42
42
|
@property
|
43
|
-
def
|
43
|
+
def output_pickle_file_remote_path(self) -> Path:
|
44
44
|
return (
|
45
45
|
self.workdir_remote
|
46
46
|
/ f"{self.prefix}-{self.component}-output.pickle"
|
47
|
-
)
|
47
|
+
)
|
48
|
+
|
49
|
+
@property
|
50
|
+
def input_pickle_file_local(self) -> str:
|
51
|
+
return self.input_pickle_file_local_path.as_posix()
|
52
|
+
|
53
|
+
@property
|
54
|
+
def input_pickle_file_remote(self) -> str:
|
55
|
+
return self.input_pickle_file_remote_path.as_posix()
|
56
|
+
|
57
|
+
@property
|
58
|
+
def output_pickle_file_local(self) -> str:
|
59
|
+
return self.output_pickle_file_local_path.as_posix()
|
60
|
+
|
61
|
+
@property
|
62
|
+
def output_pickle_file_remote(self) -> str:
|
63
|
+
return self.output_pickle_file_remote_path.as_posix()
|
48
64
|
|
49
65
|
|
50
66
|
class SlurmJob(BaseModel):
|
@@ -74,29 +90,45 @@ class SlurmJob(BaseModel):
|
|
74
90
|
return "%j"
|
75
91
|
|
76
92
|
@property
|
77
|
-
def
|
93
|
+
def slurm_stdout_remote_path(self) -> Path:
|
78
94
|
return (
|
79
95
|
self.workdir_remote
|
80
96
|
/ f"{self.prefix}-slurm-{self.slurm_job_id_placeholder}.out"
|
81
|
-
)
|
97
|
+
)
|
82
98
|
|
83
99
|
@property
|
84
|
-
def
|
100
|
+
def slurm_stdout_remote(self) -> str:
|
101
|
+
return self.slurm_stdout_remote_path.as_posix()
|
102
|
+
|
103
|
+
@property
|
104
|
+
def slurm_stderr_remote_path(self) -> Path:
|
85
105
|
return (
|
86
106
|
self.workdir_remote
|
87
107
|
/ f"{self.prefix}-slurm-{self.slurm_job_id_placeholder}.err"
|
88
|
-
)
|
108
|
+
)
|
89
109
|
|
90
110
|
@property
|
91
|
-
def
|
111
|
+
def slurm_stderr_remote(self) -> str:
|
112
|
+
return self.slurm_stderr_remote_path.as_posix()
|
113
|
+
|
114
|
+
@property
|
115
|
+
def slurm_stdout_local_path(self) -> str:
|
92
116
|
return (
|
93
117
|
self.workdir_local
|
94
118
|
/ f"{self.prefix}-slurm-{self.slurm_job_id_placeholder}.out"
|
95
|
-
)
|
119
|
+
)
|
96
120
|
|
97
121
|
@property
|
98
|
-
def
|
122
|
+
def slurm_stdout_local(self) -> str:
|
123
|
+
return self.slurm_stdout_local_path.as_posix()
|
124
|
+
|
125
|
+
@property
|
126
|
+
def slurm_stderr_local_path(self) -> Path:
|
99
127
|
return (
|
100
128
|
self.workdir_local
|
101
129
|
/ f"{self.prefix}-slurm-{self.slurm_job_id_placeholder}.err"
|
102
|
-
)
|
130
|
+
)
|
131
|
+
|
132
|
+
@property
|
133
|
+
def slurm_stderr_local(self) -> str:
|
134
|
+
return self.slurm_stderr_local_path.as_posix()
|
@@ -0,0 +1,208 @@
|
|
1
|
+
import time
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
from ..slurm_common.base_slurm_runner import BaseSlurmRunner
|
6
|
+
from ..slurm_common.slurm_job_task_models import SlurmJob
|
7
|
+
from fractal_server.app.runner.compress_folder import compress_folder
|
8
|
+
from fractal_server.app.runner.extract_archive import extract_archive
|
9
|
+
from fractal_server.config import get_settings
|
10
|
+
from fractal_server.logger import set_logger
|
11
|
+
from fractal_server.ssh._fabric import FractalSSH
|
12
|
+
from fractal_server.syringe import Inject
|
13
|
+
|
14
|
+
|
15
|
+
logger = set_logger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
class SlurmSSHRunner(BaseSlurmRunner):
|
19
|
+
fractal_ssh: FractalSSH
|
20
|
+
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
*,
|
24
|
+
# Common
|
25
|
+
root_dir_local: Path,
|
26
|
+
root_dir_remote: Path,
|
27
|
+
common_script_lines: Optional[list[str]] = None,
|
28
|
+
user_cache_dir: Optional[str] = None,
|
29
|
+
poll_interval: Optional[int] = None,
|
30
|
+
# Specific
|
31
|
+
fractal_ssh: FractalSSH,
|
32
|
+
) -> None:
|
33
|
+
"""
|
34
|
+
Set parameters that are the same for different Fractal tasks and for
|
35
|
+
different SLURM jobs/tasks.
|
36
|
+
"""
|
37
|
+
self.fractal_ssh = fractal_ssh
|
38
|
+
logger.warning(self.fractal_ssh)
|
39
|
+
|
40
|
+
settings = Inject(get_settings)
|
41
|
+
|
42
|
+
super().__init__(
|
43
|
+
slurm_runner_type="ssh",
|
44
|
+
root_dir_local=root_dir_local,
|
45
|
+
root_dir_remote=root_dir_remote,
|
46
|
+
common_script_lines=common_script_lines,
|
47
|
+
user_cache_dir=user_cache_dir,
|
48
|
+
poll_interval=poll_interval,
|
49
|
+
python_worker_interpreter=settings.FRACTAL_SLURM_WORKER_PYTHON,
|
50
|
+
)
|
51
|
+
|
52
|
+
def _mkdir_local_folder(self, folder: str) -> None:
|
53
|
+
Path(folder).mkdir(parents=True)
|
54
|
+
|
55
|
+
def _mkdir_remote_folder(self, folder: str):
|
56
|
+
self.fractal_ssh.mkdir(
|
57
|
+
folder=folder,
|
58
|
+
parents=True,
|
59
|
+
)
|
60
|
+
|
61
|
+
def _fetch_artifacts(
|
62
|
+
self,
|
63
|
+
finished_slurm_jobs: list[SlurmJob],
|
64
|
+
) -> None:
|
65
|
+
"""
|
66
|
+
Fetch artifacts for a list of SLURM jobs.
|
67
|
+
"""
|
68
|
+
|
69
|
+
# Check length
|
70
|
+
if len(finished_slurm_jobs) == 0:
|
71
|
+
logger.debug(f"[_fetch_artifacts] EXIT ({finished_slurm_jobs=}).")
|
72
|
+
return None
|
73
|
+
|
74
|
+
t_0 = time.perf_counter()
|
75
|
+
logger.debug(
|
76
|
+
f"[_fetch_artifacts] START ({len(finished_slurm_jobs)=})."
|
77
|
+
)
|
78
|
+
|
79
|
+
# Extract `workdir_remote` and `workdir_local`
|
80
|
+
self.validate_slurm_jobs_workdirs(finished_slurm_jobs)
|
81
|
+
workdir_local = finished_slurm_jobs[0].workdir_local
|
82
|
+
workdir_remote = finished_slurm_jobs[0].workdir_remote
|
83
|
+
|
84
|
+
# Define local/remote tarfile paths
|
85
|
+
tarfile_path_local = (
|
86
|
+
workdir_local.parent / f"{workdir_local.name}.tar.gz"
|
87
|
+
).as_posix()
|
88
|
+
tarfile_path_remote = (
|
89
|
+
workdir_remote.parent / f"{workdir_remote.name}.tar.gz"
|
90
|
+
).as_posix()
|
91
|
+
|
92
|
+
# Create file list
|
93
|
+
# # FIXME can we make this more efficient with iterators?
|
94
|
+
filelist = []
|
95
|
+
for _slurm_job in finished_slurm_jobs:
|
96
|
+
_single_job_filelist = [
|
97
|
+
_slurm_job.slurm_stdout_remote_path.name,
|
98
|
+
_slurm_job.slurm_stderr_remote_path.name,
|
99
|
+
]
|
100
|
+
for task in _slurm_job.tasks:
|
101
|
+
_single_job_filelist.extend(
|
102
|
+
[
|
103
|
+
task.output_pickle_file_remote_path.name,
|
104
|
+
task.task_files.log_file_remote_path.name,
|
105
|
+
task.task_files.args_file_remote_path.name,
|
106
|
+
task.task_files.metadiff_file_remote_path.name,
|
107
|
+
]
|
108
|
+
)
|
109
|
+
filelist.extend(_single_job_filelist)
|
110
|
+
filelist_string = "\n".join(filelist)
|
111
|
+
elapsed = time.perf_counter() - t_0
|
112
|
+
logger.debug(
|
113
|
+
"[_fetch_artifacts] Created filelist "
|
114
|
+
f"({len(filelist)=}, from start: {elapsed:.3f} s)."
|
115
|
+
)
|
116
|
+
|
117
|
+
# Write filelist to file remotely
|
118
|
+
tmp_filelist_path = workdir_remote / f"filelist_{time.time()}.txt"
|
119
|
+
self.fractal_ssh.write_remote_file(
|
120
|
+
path=tmp_filelist_path.as_posix(),
|
121
|
+
content=f"{filelist_string}\n",
|
122
|
+
)
|
123
|
+
elapsed = time.perf_counter() - t_0
|
124
|
+
logger.debug(
|
125
|
+
f"[_fetch_artifacts] File list written to {tmp_filelist_path} "
|
126
|
+
f"(from start: {elapsed:.3f} s)."
|
127
|
+
)
|
128
|
+
|
129
|
+
# Create remote tarfile
|
130
|
+
t_0_tar = time.perf_counter()
|
131
|
+
tar_command = (
|
132
|
+
f"{self.python_worker_interpreter} "
|
133
|
+
"-m fractal_server.app.runner.compress_folder "
|
134
|
+
f"{workdir_remote.as_posix()} "
|
135
|
+
f"--filelist {tmp_filelist_path}"
|
136
|
+
)
|
137
|
+
self.fractal_ssh.run_command(cmd=tar_command)
|
138
|
+
t_1_tar = time.perf_counter()
|
139
|
+
logger.info(
|
140
|
+
f"Remote archive {tarfile_path_remote} created"
|
141
|
+
f" - elapsed: {t_1_tar - t_0_tar:.3f} s"
|
142
|
+
)
|
143
|
+
|
144
|
+
# Fetch tarfile
|
145
|
+
t_0_get = time.perf_counter()
|
146
|
+
self.fractal_ssh.fetch_file(
|
147
|
+
remote=tarfile_path_remote,
|
148
|
+
local=tarfile_path_local,
|
149
|
+
)
|
150
|
+
t_1_get = time.perf_counter()
|
151
|
+
logger.info(
|
152
|
+
f"Subfolder archive transferred back to {tarfile_path_local}"
|
153
|
+
f" - elapsed: {t_1_get - t_0_get:.3f} s"
|
154
|
+
)
|
155
|
+
|
156
|
+
# Extract tarfile locally
|
157
|
+
extract_archive(Path(tarfile_path_local))
|
158
|
+
|
159
|
+
# Remove local tarfile
|
160
|
+
Path(tarfile_path_local).unlink(missing_ok=True)
|
161
|
+
|
162
|
+
t_1 = time.perf_counter()
|
163
|
+
logger.info(f"[_get_subfolder_sftp] End - elapsed: {t_1 - t_0:.3f} s")
|
164
|
+
|
165
|
+
def _send_inputs(self, jobs: list[SlurmJob]) -> None:
|
166
|
+
"""
|
167
|
+
Transfer the jobs subfolder to the remote host.
|
168
|
+
"""
|
169
|
+
for job in jobs:
|
170
|
+
|
171
|
+
# Create local archive
|
172
|
+
tarfile_path_local = compress_folder(
|
173
|
+
job.workdir_local,
|
174
|
+
filelist_path=None,
|
175
|
+
)
|
176
|
+
tarfile_name = Path(tarfile_path_local).name
|
177
|
+
logger.info(f"Subfolder archive created at {tarfile_path_local}")
|
178
|
+
|
179
|
+
# Transfer archive
|
180
|
+
tarfile_path_remote = (
|
181
|
+
job.workdir_remote.parent / tarfile_name
|
182
|
+
).as_posix()
|
183
|
+
t_0_put = time.perf_counter()
|
184
|
+
self.fractal_ssh.send_file(
|
185
|
+
local=tarfile_path_local,
|
186
|
+
remote=tarfile_path_remote,
|
187
|
+
)
|
188
|
+
t_1_put = time.perf_counter()
|
189
|
+
logger.info(
|
190
|
+
f"Subfolder archive transferred to {tarfile_path_remote}"
|
191
|
+
f" - elapsed: {t_1_put - t_0_put:.3f} s"
|
192
|
+
)
|
193
|
+
|
194
|
+
# Remove local archive
|
195
|
+
Path(tarfile_path_local).unlink()
|
196
|
+
logger.debug(f"Local archive {tarfile_path_local} removed")
|
197
|
+
|
198
|
+
# Uncompress remote archive
|
199
|
+
tar_command = (
|
200
|
+
f"{self.python_worker_interpreter} -m "
|
201
|
+
"fractal_server.app.runner.extract_archive "
|
202
|
+
f"{tarfile_path_remote}"
|
203
|
+
)
|
204
|
+
self.fractal_ssh.run_command(cmd=tar_command)
|
205
|
+
|
206
|
+
def _run_remote_cmd(self, cmd: str) -> str:
|
207
|
+
stdout = self.fractal_ssh.run_command(cmd=cmd)
|
208
|
+
return stdout
|
@@ -3,6 +3,7 @@ import os
|
|
3
3
|
import shlex
|
4
4
|
import subprocess # nosec
|
5
5
|
import sys
|
6
|
+
from concurrent.futures import ThreadPoolExecutor
|
6
7
|
from pathlib import Path
|
7
8
|
from typing import Optional
|
8
9
|
|
@@ -15,7 +16,6 @@ from fractal_server.config import get_settings
|
|
15
16
|
from fractal_server.logger import set_logger
|
16
17
|
from fractal_server.syringe import Inject
|
17
18
|
|
18
|
-
|
19
19
|
logger = set_logger(__name__)
|
20
20
|
|
21
21
|
|
@@ -67,10 +67,6 @@ class SudoSlurmRunner(BaseSlurmRunner):
|
|
67
67
|
self.slurm_account = slurm_account
|
68
68
|
settings = Inject(get_settings)
|
69
69
|
|
70
|
-
self.python_worker_interpreter = (
|
71
|
-
settings.FRACTAL_SLURM_WORKER_PYTHON or sys.executable
|
72
|
-
)
|
73
|
-
|
74
70
|
super().__init__(
|
75
71
|
slurm_runner_type="sudo",
|
76
72
|
root_dir_local=root_dir_local,
|
@@ -78,6 +74,9 @@ class SudoSlurmRunner(BaseSlurmRunner):
|
|
78
74
|
common_script_lines=common_script_lines,
|
79
75
|
user_cache_dir=user_cache_dir,
|
80
76
|
poll_interval=poll_interval,
|
77
|
+
python_worker_interpreter=(
|
78
|
+
settings.FRACTAL_SLURM_WORKER_PYTHON or sys.executable
|
79
|
+
),
|
81
80
|
)
|
82
81
|
|
83
82
|
def _mkdir_local_folder(self, folder: str) -> None:
|
@@ -88,12 +87,12 @@ class SudoSlurmRunner(BaseSlurmRunner):
|
|
88
87
|
def _mkdir_remote_folder(self, folder: str) -> None:
|
89
88
|
_mkdir_as_user(folder=folder, user=self.slurm_user)
|
90
89
|
|
91
|
-
def
|
90
|
+
def _fetch_artifacts_single_job(self, job: SlurmJob) -> None:
|
92
91
|
"""
|
93
|
-
|
92
|
+
Fetch artifacts for a single SLURM jobs.
|
94
93
|
"""
|
95
94
|
logger.debug(
|
96
|
-
f"[
|
95
|
+
f"[_fetch_artifacts_single_job] {job.slurm_job_id=} START"
|
97
96
|
)
|
98
97
|
source_target_list = [
|
99
98
|
(job.slurm_stdout_remote, job.slurm_stdout_local),
|
@@ -140,9 +139,30 @@ class SudoSlurmRunner(BaseSlurmRunner):
|
|
140
139
|
f"SKIP copy {source} into {target}. "
|
141
140
|
f"Original error: {str(e)}"
|
142
141
|
)
|
142
|
+
logger.debug(f"[_fetch_artifacts_single_job] {job.slurm_job_id=} END")
|
143
|
+
|
144
|
+
def _fetch_artifacts(
|
145
|
+
self,
|
146
|
+
finished_slurm_jobs: list[SlurmJob],
|
147
|
+
) -> None:
|
148
|
+
"""
|
149
|
+
Fetch artifacts for a list of SLURM jobs.
|
150
|
+
"""
|
151
|
+
MAX_NUM_THREADS = 4
|
152
|
+
THREAD_NAME_PREFIX = "fetch_artifacts"
|
143
153
|
logger.debug(
|
144
|
-
|
154
|
+
"[_fetch_artifacts] START "
|
155
|
+
f"({MAX_NUM_THREADS=}, {len(finished_slurm_jobs)=})."
|
145
156
|
)
|
157
|
+
with ThreadPoolExecutor(
|
158
|
+
max_workers=MAX_NUM_THREADS,
|
159
|
+
thread_name_prefix=THREAD_NAME_PREFIX,
|
160
|
+
) as executor:
|
161
|
+
executor.map(
|
162
|
+
self._fetch_artifacts_single_job,
|
163
|
+
finished_slurm_jobs,
|
164
|
+
)
|
165
|
+
logger.debug("[_fetch_artifacts] END.")
|
146
166
|
|
147
167
|
def _run_remote_cmd(self, cmd: str) -> str:
|
148
168
|
res = _run_command_as_user(
|
{fractal_server-2.14.0a22 → fractal_server-2.14.0a24}/fractal_server/app/runner/extract_archive.py
RENAMED
@@ -57,9 +57,7 @@ def extract_archive(archive_path: Path):
|
|
57
57
|
|
58
58
|
# Run tar command
|
59
59
|
cmd_tar = (
|
60
|
-
f"tar -xzvf {archive_path} "
|
61
|
-
f"--directory={subfolder_path.as_posix()} "
|
62
|
-
"."
|
60
|
+
f"tar -xzvf {archive_path} --directory={subfolder_path.as_posix()}"
|
63
61
|
)
|
64
62
|
logger.debug(f"{cmd_tar=}")
|
65
63
|
run_subprocess(cmd=cmd_tar, logger_name=logger_name)
|