fractal-server 2.12.0a0__py3-none-any.whl → 2.12.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fractal_server/__init__.py +1 -1
- fractal_server/__main__.py +17 -63
- fractal_server/app/routes/api/v2/images.py +0 -12
- fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py +0 -1
- fractal_server/app/runner/executors/slurm/ssh/executor.py +23 -29
- fractal_server/app/runner/executors/slurm/sudo/executor.py +51 -20
- fractal_server/app/schemas/_validators.py +0 -19
- fractal_server/app/security/__init__.py +6 -3
- fractal_server/app/security/signup_email.py +21 -12
- fractal_server/config.py +92 -51
- fractal_server/main.py +12 -9
- fractal_server/migrations/env.py +16 -63
- fractal_server/tasks/utils.py +0 -4
- fractal_server/tasks/v2/local/collect.py +9 -8
- fractal_server/tasks/v2/local/deactivate.py +3 -0
- fractal_server/tasks/v2/local/reactivate.py +3 -0
- fractal_server/tasks/v2/ssh/collect.py +8 -8
- fractal_server/tasks/v2/ssh/deactivate.py +3 -0
- fractal_server/tasks/v2/ssh/reactivate.py +9 -6
- {fractal_server-2.12.0a0.dist-info → fractal_server-2.12.1.dist-info}/METADATA +2 -2
- {fractal_server-2.12.0a0.dist-info → fractal_server-2.12.1.dist-info}/RECORD +24 -24
- {fractal_server-2.12.0a0.dist-info → fractal_server-2.12.1.dist-info}/LICENSE +0 -0
- {fractal_server-2.12.0a0.dist-info → fractal_server-2.12.1.dist-info}/WHEEL +0 -0
- {fractal_server-2.12.0a0.dist-info → fractal_server-2.12.1.dist-info}/entry_points.txt +0 -0
fractal_server/config.py
CHANGED
@@ -11,7 +11,6 @@
|
|
11
11
|
# <exact-lab.it> under contract with Liberali Lab from the Friedrich Miescher
|
12
12
|
# Institute for Biomedical Research and Pelkmans Lab from the University of
|
13
13
|
# Zurich.
|
14
|
-
import json
|
15
14
|
import logging
|
16
15
|
import shutil
|
17
16
|
import sys
|
@@ -46,16 +45,19 @@ class MailSettings(BaseModel):
|
|
46
45
|
port: SMTP server port
|
47
46
|
password: Sender password
|
48
47
|
instance_name: Name of SMTP server instance
|
49
|
-
use_starttls:
|
48
|
+
use_starttls: Whether to use the security protocol
|
49
|
+
use_login: Whether to use login
|
50
50
|
"""
|
51
51
|
|
52
52
|
sender: EmailStr
|
53
53
|
recipients: list[EmailStr] = Field(min_items=1)
|
54
54
|
smtp_server: str
|
55
55
|
port: int
|
56
|
-
|
56
|
+
encrypted_password: Optional[str] = None
|
57
|
+
encryption_key: Optional[str] = None
|
57
58
|
instance_name: str
|
58
59
|
use_starttls: bool
|
60
|
+
use_login: bool
|
59
61
|
|
60
62
|
|
61
63
|
class FractalConfigurationError(RuntimeError):
|
@@ -406,7 +408,7 @@ class Settings(BaseSettings):
|
|
406
408
|
"""
|
407
409
|
|
408
410
|
@root_validator(pre=True)
|
409
|
-
def check_tasks_python(cls, values)
|
411
|
+
def check_tasks_python(cls, values):
|
410
412
|
"""
|
411
413
|
Perform multiple checks of the Python-interpreter variables.
|
412
414
|
|
@@ -416,7 +418,6 @@ class Settings(BaseSettings):
|
|
416
418
|
`sys.executable` and set the corresponding
|
417
419
|
`FRACTAL_TASKS_PYTHON_X_Y` (and unset all others).
|
418
420
|
"""
|
419
|
-
|
420
421
|
# `FRACTAL_TASKS_PYTHON_X_Y` variables can only be absolute paths
|
421
422
|
for version in ["3_9", "3_10", "3_11", "3_12"]:
|
422
423
|
key = f"FRACTAL_TASKS_PYTHON_{version}"
|
@@ -575,66 +576,107 @@ class Settings(BaseSettings):
|
|
575
576
|
###########################################################################
|
576
577
|
# SMTP SERVICE
|
577
578
|
###########################################################################
|
578
|
-
|
579
|
+
|
580
|
+
FRACTAL_EMAIL_SENDER: Optional[EmailStr] = None
|
581
|
+
"""
|
582
|
+
Address of the OAuth-signup email sender.
|
579
583
|
"""
|
580
|
-
|
581
|
-
`smtp_server`, `port`, `instance_name`, `use_starttls`.
|
584
|
+
FRACTAL_EMAIL_PASSWORD: Optional[str] = None
|
582
585
|
"""
|
583
|
-
|
586
|
+
Password for the OAuth-signup email sender.
|
587
|
+
"""
|
588
|
+
FRACTAL_EMAIL_PASSWORD_KEY: Optional[str] = None
|
584
589
|
"""
|
585
590
|
Key value for `cryptography.fernet` decrypt
|
586
591
|
"""
|
592
|
+
FRACTAL_EMAIL_SMTP_SERVER: Optional[str] = None
|
593
|
+
"""
|
594
|
+
SMPT server for the OAuth-signup emails.
|
595
|
+
"""
|
596
|
+
FRACTAL_EMAIL_SMTP_PORT: Optional[int] = None
|
597
|
+
"""
|
598
|
+
SMPT server port for the OAuth-signup emails.
|
599
|
+
"""
|
600
|
+
FRACTAL_EMAIL_INSTANCE_NAME: Optional[str] = None
|
601
|
+
"""
|
602
|
+
Fractal instance name, to be included in the OAuth-signup emails.
|
603
|
+
"""
|
587
604
|
FRACTAL_EMAIL_RECIPIENTS: Optional[str] = None
|
588
605
|
"""
|
589
|
-
|
606
|
+
Comma-separated list of recipients of the OAuth-signup emails.
|
607
|
+
"""
|
608
|
+
FRACTAL_EMAIL_USE_STARTTLS: Optional[bool] = True
|
609
|
+
"""
|
610
|
+
Whether to use StartTLS when using the SMTP server.
|
611
|
+
"""
|
612
|
+
FRACTAL_EMAIL_USE_LOGIN: Optional[bool] = True
|
590
613
|
"""
|
614
|
+
Whether to use login when using the SMTP server.
|
615
|
+
"""
|
616
|
+
email_settings: Optional[MailSettings] = None
|
591
617
|
|
592
|
-
@
|
593
|
-
def
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
)
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
)
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
618
|
+
@root_validator(pre=True)
|
619
|
+
def validate_email_settings(cls, values):
|
620
|
+
email_values = {
|
621
|
+
k: v for k, v in values.items() if k.startswith("FRACTAL_EMAIL")
|
622
|
+
}
|
623
|
+
if email_values:
|
624
|
+
|
625
|
+
def assert_key(key: str):
|
626
|
+
if key not in email_values:
|
627
|
+
raise ValueError(f"Missing '{key}'")
|
628
|
+
|
629
|
+
assert_key("FRACTAL_EMAIL_SENDER")
|
630
|
+
assert_key("FRACTAL_EMAIL_SMTP_SERVER")
|
631
|
+
assert_key("FRACTAL_EMAIL_SMTP_PORT")
|
632
|
+
assert_key("FRACTAL_EMAIL_INSTANCE_NAME")
|
633
|
+
assert_key("FRACTAL_EMAIL_RECIPIENTS")
|
634
|
+
|
635
|
+
if email_values.get("FRACTAL_EMAIL_USE_LOGIN", True):
|
636
|
+
if "FRACTAL_EMAIL_PASSWORD" not in email_values:
|
637
|
+
raise ValueError(
|
638
|
+
"'FRACTAL_EMAIL_USE_LOGIN' is True but "
|
639
|
+
"'FRACTAL_EMAIL_PASSWORD' is not provided."
|
640
|
+
)
|
641
|
+
elif "FRACTAL_EMAIL_PASSWORD_KEY" not in email_values:
|
642
|
+
raise ValueError(
|
643
|
+
"'FRACTAL_EMAIL_USE_LOGIN' is True but "
|
644
|
+
"'FRACTAL_EMAIL_PASSWORD_KEY' is not provided."
|
645
|
+
)
|
646
|
+
else:
|
647
|
+
try:
|
648
|
+
(
|
649
|
+
Fernet(email_values["FRACTAL_EMAIL_PASSWORD_KEY"])
|
650
|
+
.decrypt(email_values["FRACTAL_EMAIL_PASSWORD"])
|
651
|
+
.decode("utf-8")
|
652
|
+
)
|
653
|
+
except Exception as e:
|
654
|
+
raise ValueError(
|
655
|
+
"Invalid pair (FRACTAL_EMAIL_PASSWORD, "
|
656
|
+
"FRACTAL_EMAIL_PASSWORD_KEY). "
|
657
|
+
f"Original error: {str(e)}."
|
658
|
+
)
|
659
|
+
|
660
|
+
values["email_settings"] = MailSettings(
|
661
|
+
sender=email_values["FRACTAL_EMAIL_SENDER"],
|
662
|
+
recipients=email_values["FRACTAL_EMAIL_RECIPIENTS"].split(","),
|
663
|
+
smtp_server=email_values["FRACTAL_EMAIL_SMTP_SERVER"],
|
664
|
+
port=email_values["FRACTAL_EMAIL_SMTP_PORT"],
|
665
|
+
encrypted_password=email_values.get("FRACTAL_EMAIL_PASSWORD"),
|
666
|
+
encryption_key=email_values.get("FRACTAL_EMAIL_PASSWORD_KEY"),
|
667
|
+
instance_name=email_values["FRACTAL_EMAIL_INSTANCE_NAME"],
|
668
|
+
use_starttls=email_values.get(
|
669
|
+
"FRACTAL_EMAIL_USE_STARTTLS", True
|
670
|
+
),
|
671
|
+
use_login=email_values.get("FRACTAL_EMAIL_USE_LOGIN", True),
|
621
672
|
)
|
622
673
|
|
674
|
+
return values
|
675
|
+
|
623
676
|
###########################################################################
|
624
677
|
# BUSINESS LOGIC
|
625
678
|
###########################################################################
|
626
679
|
|
627
|
-
def check_fractal_mail_settings(self):
|
628
|
-
"""
|
629
|
-
Checks that the mail settings are properly set.
|
630
|
-
"""
|
631
|
-
try:
|
632
|
-
self.MAIL_SETTINGS
|
633
|
-
except Exception as e:
|
634
|
-
raise FractalConfigurationError(
|
635
|
-
f"Invalid email configuration settings. Original error: {e}"
|
636
|
-
)
|
637
|
-
|
638
680
|
def check_db(self) -> None:
|
639
681
|
"""
|
640
682
|
Checks that db environment variables are properly set.
|
@@ -740,7 +782,6 @@ class Settings(BaseSettings):
|
|
740
782
|
|
741
783
|
self.check_db()
|
742
784
|
self.check_runner()
|
743
|
-
self.check_fractal_mail_settings()
|
744
785
|
|
745
786
|
def get_sanitized(self) -> dict:
|
746
787
|
def _must_be_sanitized(string) -> bool:
|
fractal_server/main.py
CHANGED
@@ -28,6 +28,7 @@ from .logger import get_logger
|
|
28
28
|
from .logger import reset_logger_handlers
|
29
29
|
from .logger import set_logger
|
30
30
|
from .syringe import Inject
|
31
|
+
from fractal_server import __VERSION__
|
31
32
|
|
32
33
|
|
33
34
|
def collect_routers(app: FastAPI) -> None:
|
@@ -67,7 +68,7 @@ def check_settings() -> None:
|
|
67
68
|
logger = set_logger("fractal_server_settings")
|
68
69
|
logger.debug("Fractal Settings:")
|
69
70
|
for key, value in settings.dict().items():
|
70
|
-
if any(s in key.upper() for s in ["PASSWORD", "SECRET"]):
|
71
|
+
if any(s in key.upper() for s in ["PASSWORD", "SECRET", "KEY"]):
|
71
72
|
value = "*****"
|
72
73
|
logger.debug(f" {key}: {value}")
|
73
74
|
reset_logger_handlers(logger)
|
@@ -77,7 +78,7 @@ def check_settings() -> None:
|
|
77
78
|
async def lifespan(app: FastAPI):
|
78
79
|
app.state.jobsV2 = []
|
79
80
|
logger = set_logger("fractal_server.lifespan")
|
80
|
-
logger.info("
|
81
|
+
logger.info(f"[startup] START (fractal-server {__VERSION__})")
|
81
82
|
check_settings()
|
82
83
|
settings = Inject(get_settings)
|
83
84
|
|
@@ -88,31 +89,31 @@ async def lifespan(app: FastAPI):
|
|
88
89
|
app.state.fractal_ssh_list = FractalSSHList()
|
89
90
|
|
90
91
|
logger.info(
|
91
|
-
"Added empty FractalSSHList to app.state "
|
92
|
+
"[startup] Added empty FractalSSHList to app.state "
|
92
93
|
f"(id={id(app.state.fractal_ssh_list)})."
|
93
94
|
)
|
94
95
|
else:
|
95
96
|
app.state.fractal_ssh_list = None
|
96
97
|
|
97
98
|
config_uvicorn_loggers()
|
98
|
-
logger.info("
|
99
|
+
logger.info("[startup] END")
|
99
100
|
reset_logger_handlers(logger)
|
100
101
|
|
101
102
|
yield
|
102
103
|
|
103
104
|
logger = get_logger("fractal_server.lifespan")
|
104
|
-
logger.info("
|
105
|
+
logger.info("[teardown] START")
|
105
106
|
|
106
107
|
if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
|
107
108
|
logger.info(
|
108
|
-
"Close FractalSSH connections "
|
109
|
+
"[teardown] Close FractalSSH connections "
|
109
110
|
f"(current size: {app.state.fractal_ssh_list.size})."
|
110
111
|
)
|
111
112
|
|
112
113
|
app.state.fractal_ssh_list.close_all()
|
113
114
|
|
114
115
|
logger.info(
|
115
|
-
f"Current worker with pid {os.getpid()} is shutting down. "
|
116
|
+
f"[teardown] Current worker with pid {os.getpid()} is shutting down. "
|
116
117
|
f"Current jobs: {app.state.jobsV2=}"
|
117
118
|
)
|
118
119
|
if _backend_supports_shutdown(settings.FRACTAL_RUNNER_BACKEND):
|
@@ -128,9 +129,11 @@ async def lifespan(app: FastAPI):
|
|
128
129
|
f"Original error: {e}"
|
129
130
|
)
|
130
131
|
else:
|
131
|
-
logger.info(
|
132
|
+
logger.info(
|
133
|
+
"[teardown] Shutdown not available for this backend runner."
|
134
|
+
)
|
132
135
|
|
133
|
-
logger.info("
|
136
|
+
logger.info("[teardown] END")
|
134
137
|
reset_logger_handlers(logger)
|
135
138
|
|
136
139
|
|
fractal_server/migrations/env.py
CHANGED
@@ -1,16 +1,11 @@
|
|
1
|
-
import asyncio
|
2
1
|
from logging.config import fileConfig
|
3
2
|
|
4
3
|
from alembic import context
|
5
|
-
from sqlalchemy.engine import Connection
|
6
4
|
from sqlmodel import SQLModel
|
7
5
|
|
8
|
-
from fractal_server.config import get_settings
|
9
6
|
from fractal_server.migrations.naming_convention import NAMING_CONVENTION
|
10
|
-
from fractal_server.syringe import Inject
|
11
7
|
|
12
|
-
#
|
13
|
-
# access to the values within the .ini file in use.
|
8
|
+
# Alembic Config object (provides access to the values within the .ini file)
|
14
9
|
config = context.config
|
15
10
|
|
16
11
|
|
@@ -20,77 +15,35 @@ if config.config_file_name is not None:
|
|
20
15
|
fileConfig(config.config_file_name)
|
21
16
|
|
22
17
|
|
23
|
-
# add your model's MetaData object here
|
24
|
-
# for 'autogenerate' support
|
25
|
-
# from myapp import mymodel
|
26
|
-
# target_metadata = mymodel.Base.metadata
|
27
18
|
target_metadata = SQLModel.metadata
|
28
19
|
target_metadata.naming_convention = NAMING_CONVENTION
|
29
|
-
# Importing `fractal_server.app.models` after defining
|
20
|
+
# Importing `fractal_server.app.models` *after* defining
|
30
21
|
# `SQLModel.metadata.naming_convention` in order to apply the naming convention
|
31
22
|
# when autogenerating migrations (see issue #1819).
|
32
23
|
from fractal_server.app import models # noqa
|
33
24
|
|
34
|
-
# other values from the config, defined by the needs of env.py,
|
35
|
-
# can be acquired:
|
36
|
-
# my_important_option = config.get_main_option("my_important_option")
|
37
|
-
# ... etc.
|
38
|
-
|
39
|
-
|
40
|
-
def run_migrations_offline() -> None:
|
41
|
-
"""Run migrations in 'offline' mode.
|
42
|
-
|
43
|
-
This configures the context with just a URL
|
44
|
-
and not an Engine, though an Engine is acceptable
|
45
|
-
here as well. By skipping the Engine creation
|
46
|
-
we don't even need a DBAPI to be available.
|
47
|
-
|
48
|
-
Calls to context.execute() here emit the given string to the
|
49
|
-
script output.
|
50
25
|
|
26
|
+
def run_migrations_online() -> None:
|
51
27
|
"""
|
52
|
-
|
53
|
-
settings.check_db()
|
54
|
-
context.configure(
|
55
|
-
url=settings.DATABASE_ASYNC_URL,
|
56
|
-
target_metadata=target_metadata,
|
57
|
-
literal_binds=True,
|
58
|
-
dialect_opts={"paramstyle": "named"},
|
59
|
-
render_as_batch=True,
|
60
|
-
)
|
61
|
-
|
62
|
-
with context.begin_transaction():
|
63
|
-
context.run_migrations()
|
64
|
-
|
65
|
-
|
66
|
-
def do_run_migrations(connection: Connection) -> None:
|
67
|
-
context.configure(
|
68
|
-
connection=connection,
|
69
|
-
target_metadata=target_metadata,
|
70
|
-
render_as_batch=True,
|
71
|
-
)
|
72
|
-
|
73
|
-
with context.begin_transaction():
|
74
|
-
context.run_migrations()
|
75
|
-
|
76
|
-
|
77
|
-
async def run_migrations_online() -> None:
|
78
|
-
"""Run migrations in 'online' mode.
|
28
|
+
Run migrations in 'online' mode.
|
79
29
|
|
80
30
|
In this scenario we need to create an Engine
|
81
31
|
and associate a connection with the context.
|
82
|
-
|
83
32
|
"""
|
84
33
|
from fractal_server.app.db import DB
|
85
34
|
|
86
|
-
engine = DB.
|
87
|
-
|
88
|
-
|
35
|
+
engine = DB.engine_sync()
|
36
|
+
with engine.connect() as connection:
|
37
|
+
context.configure(
|
38
|
+
connection=connection,
|
39
|
+
target_metadata=target_metadata,
|
40
|
+
render_as_batch=True,
|
41
|
+
)
|
42
|
+
|
43
|
+
with context.begin_transaction():
|
44
|
+
context.run_migrations()
|
89
45
|
|
90
|
-
|
46
|
+
engine.dispose()
|
91
47
|
|
92
48
|
|
93
|
-
|
94
|
-
run_migrations_offline()
|
95
|
-
else:
|
96
|
-
asyncio.run(run_migrations_online())
|
49
|
+
run_migrations_online()
|
fractal_server/tasks/utils.py
CHANGED
@@ -7,9 +7,5 @@ COLLECTION_FREEZE_FILENAME = "collection_freeze.txt"
|
|
7
7
|
FORBIDDEN_DEPENDENCY_STRINGS = ["github.com"]
|
8
8
|
|
9
9
|
|
10
|
-
def get_collection_path(base: Path) -> Path:
|
11
|
-
return base / COLLECTION_FILENAME
|
12
|
-
|
13
|
-
|
14
10
|
def get_log_path(base: Path) -> Path:
|
15
11
|
return base / COLLECTION_LOG_FILENAME
|
@@ -15,6 +15,7 @@ from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
|
15
15
|
from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
|
16
16
|
from fractal_server.app.schemas.v2 import WheelFile
|
17
17
|
from fractal_server.app.schemas.v2.manifest import ManifestV2
|
18
|
+
from fractal_server.logger import reset_logger_handlers
|
18
19
|
from fractal_server.logger import set_logger
|
19
20
|
from fractal_server.tasks.utils import get_log_path
|
20
21
|
from fractal_server.tasks.v2.local._utils import check_task_files_exist
|
@@ -80,7 +81,7 @@ def collect_local(
|
|
80
81
|
return
|
81
82
|
|
82
83
|
# Log some info
|
83
|
-
logger.
|
84
|
+
logger.info("START")
|
84
85
|
for key, value in task_group.model_dump().items():
|
85
86
|
logger.debug(f"task_group.{key}: {value}")
|
86
87
|
|
@@ -101,7 +102,7 @@ def collect_local(
|
|
101
102
|
try:
|
102
103
|
# Create task_group.path folder
|
103
104
|
Path(task_group.path).mkdir(parents=True)
|
104
|
-
logger.
|
105
|
+
logger.info(f"Created {task_group.path}")
|
105
106
|
|
106
107
|
# Write wheel file and set task_group.wheel_path
|
107
108
|
if wheel_file is not None:
|
@@ -109,9 +110,7 @@ def collect_local(
|
|
109
110
|
wheel_path = (
|
110
111
|
Path(task_group.path) / wheel_file.filename
|
111
112
|
).as_posix()
|
112
|
-
logger.
|
113
|
-
f"Write wheel-file contents into {wheel_path}"
|
114
|
-
)
|
113
|
+
logger.info(f"Write wheel-file contents into {wheel_path}")
|
115
114
|
with open(wheel_path, "wb") as f:
|
116
115
|
f.write(wheel_file.contents)
|
117
116
|
task_group.wheel_path = wheel_path
|
@@ -256,12 +255,14 @@ def collect_local(
|
|
256
255
|
)
|
257
256
|
|
258
257
|
# Finalize (write metadata to DB)
|
259
|
-
logger.
|
258
|
+
logger.info("finalising - START")
|
260
259
|
activity.status = TaskGroupActivityStatusV2.OK
|
261
260
|
activity.timestamp_ended = get_timestamp()
|
262
261
|
activity = add_commit_refresh(obj=activity, db=db)
|
263
|
-
logger.
|
264
|
-
logger.
|
262
|
+
logger.info("finalising - END")
|
263
|
+
logger.info("END")
|
264
|
+
|
265
|
+
reset_logger_handlers(logger)
|
265
266
|
|
266
267
|
except Exception as collection_e:
|
267
268
|
# Delete corrupted package dir
|
@@ -14,6 +14,7 @@ from fractal_server.app.models.v2 import TaskGroupV2
|
|
14
14
|
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
15
15
|
from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
|
16
16
|
from fractal_server.app.schemas.v2.task_group import TaskGroupActivityStatusV2
|
17
|
+
from fractal_server.logger import reset_logger_handlers
|
17
18
|
from fractal_server.logger import set_logger
|
18
19
|
from fractal_server.tasks.utils import FORBIDDEN_DEPENDENCY_STRINGS
|
19
20
|
from fractal_server.tasks.utils import get_log_path
|
@@ -217,6 +218,8 @@ def deactivate_local(
|
|
217
218
|
activity.timestamp_ended = get_timestamp()
|
218
219
|
activity = add_commit_refresh(obj=activity, db=db)
|
219
220
|
|
221
|
+
reset_logger_handlers(logger)
|
222
|
+
|
220
223
|
except Exception as e:
|
221
224
|
fail_and_cleanup(
|
222
225
|
task_group=task_group,
|
@@ -13,6 +13,7 @@ from fractal_server.app.models.v2 import TaskGroupActivityV2
|
|
13
13
|
from fractal_server.app.models.v2 import TaskGroupV2
|
14
14
|
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
15
15
|
from fractal_server.app.schemas.v2.task_group import TaskGroupActivityStatusV2
|
16
|
+
from fractal_server.logger import reset_logger_handlers
|
16
17
|
from fractal_server.logger import set_logger
|
17
18
|
from fractal_server.tasks.utils import get_log_path
|
18
19
|
from fractal_server.tasks.v2.utils_background import get_current_log
|
@@ -134,6 +135,8 @@ def reactivate_local(
|
|
134
135
|
task_group = add_commit_refresh(obj=task_group, db=db)
|
135
136
|
logger.debug("END")
|
136
137
|
|
138
|
+
reset_logger_handlers(logger)
|
139
|
+
|
137
140
|
except Exception as reactivate_e:
|
138
141
|
# Delete corrupted venv_path
|
139
142
|
try:
|
@@ -14,6 +14,7 @@ from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
|
14
14
|
from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
|
15
15
|
from fractal_server.app.schemas.v2 import WheelFile
|
16
16
|
from fractal_server.app.schemas.v2.manifest import ManifestV2
|
17
|
+
from fractal_server.logger import reset_logger_handlers
|
17
18
|
from fractal_server.logger import set_logger
|
18
19
|
from fractal_server.ssh._fabric import FractalSSH
|
19
20
|
from fractal_server.tasks.v2.ssh._utils import _customize_and_run_template
|
@@ -85,7 +86,7 @@ def collect_ssh(
|
|
85
86
|
return
|
86
87
|
|
87
88
|
# Log some info
|
88
|
-
logger.
|
89
|
+
logger.info("START")
|
89
90
|
for key, value in task_group.model_dump().items():
|
90
91
|
logger.debug(f"task_group.{key}: {value}")
|
91
92
|
|
@@ -137,7 +138,7 @@ def collect_ssh(
|
|
137
138
|
Path(task_group.path) / wheel_filename
|
138
139
|
).as_posix()
|
139
140
|
tmp_wheel_path = (Path(tmpdir) / wheel_filename).as_posix()
|
140
|
-
logger.
|
141
|
+
logger.info(
|
141
142
|
f"Write wheel-file contents into {tmp_wheel_path}"
|
142
143
|
)
|
143
144
|
with open(tmp_wheel_path, "wb") as f:
|
@@ -171,7 +172,7 @@ def collect_ssh(
|
|
171
172
|
logger_name=LOGGER_NAME,
|
172
173
|
)
|
173
174
|
|
174
|
-
logger.
|
175
|
+
logger.info("installing - START")
|
175
176
|
|
176
177
|
# Set status to ONGOING and refresh logs
|
177
178
|
activity.status = TaskGroupActivityStatusV2.ONGOING
|
@@ -286,14 +287,13 @@ def collect_ssh(
|
|
286
287
|
)
|
287
288
|
|
288
289
|
# Finalize (write metadata to DB)
|
289
|
-
logger.
|
290
|
+
logger.info("finalising - START")
|
290
291
|
activity.status = TaskGroupActivityStatusV2.OK
|
291
292
|
activity.timestamp_ended = get_timestamp()
|
292
293
|
activity = add_commit_refresh(obj=activity, db=db)
|
293
|
-
logger.
|
294
|
-
logger.
|
295
|
-
|
296
|
-
logger.debug("END")
|
294
|
+
logger.info("finalising - END")
|
295
|
+
logger.info("END")
|
296
|
+
reset_logger_handlers(logger)
|
297
297
|
|
298
298
|
except Exception as collection_e:
|
299
299
|
# Delete corrupted package dir
|
@@ -14,6 +14,7 @@ from fractal_server.app.models.v2 import TaskGroupV2
|
|
14
14
|
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
15
15
|
from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
|
16
16
|
from fractal_server.app.schemas.v2.task_group import TaskGroupActivityStatusV2
|
17
|
+
from fractal_server.logger import reset_logger_handlers
|
17
18
|
from fractal_server.logger import set_logger
|
18
19
|
from fractal_server.ssh._fabric import FractalSSH
|
19
20
|
from fractal_server.tasks.utils import FORBIDDEN_DEPENDENCY_STRINGS
|
@@ -252,6 +253,8 @@ def deactivate_ssh(
|
|
252
253
|
activity.timestamp_ended = get_timestamp()
|
253
254
|
activity = add_commit_refresh(obj=activity, db=db)
|
254
255
|
|
256
|
+
reset_logger_handlers(logger)
|
257
|
+
|
255
258
|
except Exception as e:
|
256
259
|
fail_and_cleanup(
|
257
260
|
task_group=task_group,
|
@@ -12,6 +12,7 @@ from fractal_server.app.models.v2 import TaskGroupActivityV2
|
|
12
12
|
from fractal_server.app.models.v2 import TaskGroupV2
|
13
13
|
from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
|
14
14
|
from fractal_server.app.schemas.v2.task_group import TaskGroupActivityStatusV2
|
15
|
+
from fractal_server.logger import reset_logger_handlers
|
15
16
|
from fractal_server.logger import set_logger
|
16
17
|
from fractal_server.ssh._fabric import FractalSSH
|
17
18
|
from fractal_server.tasks.utils import get_log_path
|
@@ -69,7 +70,7 @@ def reactivate_ssh(
|
|
69
70
|
return
|
70
71
|
|
71
72
|
# Log some info
|
72
|
-
logger.
|
73
|
+
logger.info("START")
|
73
74
|
for key, value in task_group.model_dump().items():
|
74
75
|
logger.debug(f"task_group.{key}: {value}")
|
75
76
|
|
@@ -152,28 +153,30 @@ def reactivate_ssh(
|
|
152
153
|
# Create remote directory for scripts
|
153
154
|
fractal_ssh.mkdir(folder=script_dir_remote)
|
154
155
|
|
155
|
-
logger.
|
156
|
+
logger.info("start - create venv")
|
156
157
|
_customize_and_run_template(
|
157
158
|
template_filename="1_create_venv.sh",
|
158
159
|
**common_args,
|
159
160
|
)
|
160
|
-
logger.
|
161
|
+
logger.info("end - create venv")
|
161
162
|
activity.log = get_current_log(log_file_path)
|
162
163
|
activity = add_commit_refresh(obj=activity, db=db)
|
163
164
|
|
164
|
-
logger.
|
165
|
+
logger.info("start - install from pip freeze")
|
165
166
|
_customize_and_run_template(
|
166
167
|
template_filename="6_pip_install_from_freeze.sh",
|
167
168
|
**common_args,
|
168
169
|
)
|
169
|
-
logger.
|
170
|
+
logger.info("end - install from pip freeze")
|
170
171
|
activity.log = get_current_log(log_file_path)
|
171
172
|
activity.status = TaskGroupActivityStatusV2.OK
|
172
173
|
activity.timestamp_ended = get_timestamp()
|
173
174
|
activity = add_commit_refresh(obj=activity, db=db)
|
174
175
|
task_group.active = True
|
175
176
|
task_group = add_commit_refresh(obj=task_group, db=db)
|
176
|
-
logger.
|
177
|
+
logger.info("END")
|
178
|
+
|
179
|
+
reset_logger_handlers(logger)
|
177
180
|
|
178
181
|
except Exception as reactivate_e:
|
179
182
|
# Delete corrupted venv_path
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: fractal-server
|
3
|
-
Version: 2.12.
|
3
|
+
Version: 2.12.1
|
4
4
|
Summary: Backend component of the Fractal analytics platform
|
5
5
|
Home-page: https://github.com/fractal-analytics-platform/fractal-server
|
6
6
|
License: BSD-3-Clause
|
@@ -27,7 +27,7 @@ Requires-Dist: pydantic (>=1.10.8,<2)
|
|
27
27
|
Requires-Dist: python-dotenv (>=1.0.0,<1.1.0)
|
28
28
|
Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
|
29
29
|
Requires-Dist: sqlmodel (==0.0.21)
|
30
|
-
Requires-Dist: uvicorn (
|
30
|
+
Requires-Dist: uvicorn (>=0.29.0,<0.35.0)
|
31
31
|
Requires-Dist: uvicorn-worker (==0.2.0)
|
32
32
|
Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
|
33
33
|
Project-URL: Repository, https://github.com/fractal-analytics-platform/fractal-server
|