fractal-server 2.5.1__py3-none-any.whl → 2.6.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/__main__.py +24 -9
  3. fractal_server/app/models/__init__.py +1 -0
  4. fractal_server/app/models/security.py +8 -0
  5. fractal_server/app/models/user_settings.py +38 -0
  6. fractal_server/app/routes/api/v1/_aux_functions.py +6 -1
  7. fractal_server/app/routes/api/v1/project.py +11 -24
  8. fractal_server/app/routes/api/v1/task.py +12 -9
  9. fractal_server/app/routes/api/v2/_aux_functions.py +6 -1
  10. fractal_server/app/routes/api/v2/submit.py +29 -21
  11. fractal_server/app/routes/api/v2/task.py +12 -9
  12. fractal_server/app/routes/api/v2/task_collection.py +17 -2
  13. fractal_server/app/routes/api/v2/task_collection_custom.py +6 -1
  14. fractal_server/app/routes/auth/_aux_auth.py +5 -5
  15. fractal_server/app/routes/auth/current_user.py +41 -0
  16. fractal_server/app/routes/auth/users.py +42 -0
  17. fractal_server/app/routes/aux/validate_user_settings.py +74 -0
  18. fractal_server/app/runner/executors/slurm/ssh/executor.py +24 -4
  19. fractal_server/app/runner/executors/slurm/sudo/executor.py +6 -2
  20. fractal_server/app/runner/v2/__init__.py +5 -7
  21. fractal_server/app/schemas/__init__.py +2 -0
  22. fractal_server/app/schemas/user.py +1 -62
  23. fractal_server/app/schemas/user_settings.py +93 -0
  24. fractal_server/app/security/__init__.py +22 -9
  25. fractal_server/app/user_settings.py +42 -0
  26. fractal_server/config.py +0 -16
  27. fractal_server/data_migrations/2_6_0.py +49 -0
  28. fractal_server/data_migrations/tools.py +17 -0
  29. fractal_server/main.py +12 -10
  30. fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +74 -0
  31. fractal_server/ssh/_fabric.py +179 -34
  32. fractal_server/tasks/v2/background_operations_ssh.py +14 -5
  33. {fractal_server-2.5.1.dist-info → fractal_server-2.6.0a0.dist-info}/METADATA +1 -1
  34. {fractal_server-2.5.1.dist-info → fractal_server-2.6.0a0.dist-info}/RECORD +37 -31
  35. fractal_server/data_migrations/2_4_0.py +0 -61
  36. {fractal_server-2.5.1.dist-info → fractal_server-2.6.0a0.dist-info}/LICENSE +0 -0
  37. {fractal_server-2.5.1.dist-info → fractal_server-2.6.0a0.dist-info}/WHEEL +0 -0
  38. {fractal_server-2.5.1.dist-info → fractal_server-2.6.0a0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,74 @@
1
+ """Add user_settings table
2
+
3
+ Revision ID: 9c5ae74c9b98
4
+ Revises: d9a140db5d42
5
+ Create Date: 2024-09-24 12:01:13.393326
6
+
7
+ """
8
+ import sqlalchemy as sa
9
+ import sqlmodel
10
+ from alembic import op
11
+
12
+
13
+ # revision identifiers, used by Alembic.
14
+ revision = "9c5ae74c9b98"
15
+ down_revision = "d9a140db5d42"
16
+ branch_labels = None
17
+ depends_on = None
18
+
19
+ # Manually define constraint name, see issue #1777
20
+ CONSTRAINT_NAME = "fk_user_oauth_user_settings_id_user_settings"
21
+
22
+
23
+ def upgrade() -> None:
24
+ # ### commands auto generated by Alembic - please adjust! ###
25
+ op.create_table(
26
+ "user_settings",
27
+ sa.Column("id", sa.Integer(), nullable=False),
28
+ sa.Column(
29
+ "slurm_accounts", sa.JSON(), server_default="[]", nullable=False
30
+ ),
31
+ sa.Column(
32
+ "ssh_host", sqlmodel.sql.sqltypes.AutoString(), nullable=True
33
+ ),
34
+ sa.Column(
35
+ "ssh_username", sqlmodel.sql.sqltypes.AutoString(), nullable=True
36
+ ),
37
+ sa.Column(
38
+ "ssh_private_key_path",
39
+ sqlmodel.sql.sqltypes.AutoString(),
40
+ nullable=True,
41
+ ),
42
+ sa.Column(
43
+ "ssh_tasks_dir", sqlmodel.sql.sqltypes.AutoString(), nullable=True
44
+ ),
45
+ sa.Column(
46
+ "ssh_jobs_dir", sqlmodel.sql.sqltypes.AutoString(), nullable=True
47
+ ),
48
+ sa.Column(
49
+ "slurm_user", sqlmodel.sql.sqltypes.AutoString(), nullable=True
50
+ ),
51
+ sa.Column(
52
+ "cache_dir", sqlmodel.sql.sqltypes.AutoString(), nullable=True
53
+ ),
54
+ sa.PrimaryKeyConstraint("id"),
55
+ )
56
+ with op.batch_alter_table("user_oauth", schema=None) as batch_op:
57
+ batch_op.add_column(
58
+ sa.Column("user_settings_id", sa.Integer(), nullable=True)
59
+ )
60
+ batch_op.create_foreign_key(
61
+ CONSTRAINT_NAME, "user_settings", ["user_settings_id"], ["id"]
62
+ )
63
+
64
+ # ### end Alembic commands ###
65
+
66
+
67
+ def downgrade() -> None:
68
+ # ### commands auto generated by Alembic - please adjust! ###
69
+ with op.batch_alter_table("user_oauth", schema=None) as batch_op:
70
+ batch_op.drop_constraint(CONSTRAINT_NAME, type_="foreignkey")
71
+ batch_op.drop_column("user_settings_id")
72
+
73
+ op.drop_table("user_settings")
74
+ # ### end Alembic commands ###
@@ -16,20 +16,21 @@ from paramiko.ssh_exception import NoValidConnectionsError
16
16
 
17
17
  from ..logger import get_logger
18
18
  from ..logger import set_logger
19
- from fractal_server.config import get_settings
20
19
  from fractal_server.string_tools import validate_cmd
21
- from fractal_server.syringe import Inject
22
20
 
23
21
 
24
22
  class FractalSSHTimeoutError(RuntimeError):
25
23
  pass
26
24
 
27
25
 
26
+ class FractalSSHListTimeoutError(RuntimeError):
27
+ pass
28
+
29
+
28
30
  logger = set_logger(__name__)
29
31
 
30
32
 
31
33
  class FractalSSH(object):
32
-
33
34
  """
34
35
  FIXME SSH: Fix docstring
35
36
 
@@ -111,7 +112,6 @@ class FractalSSH(object):
111
112
  def run(
112
113
  self, *args, lock_timeout: Optional[float] = None, **kwargs
113
114
  ) -> Any:
114
-
115
115
  actual_lock_timeout = self.default_lock_timeout
116
116
  if lock_timeout is not None:
117
117
  actual_lock_timeout = lock_timeout
@@ -138,7 +138,19 @@ class FractalSSH(object):
138
138
  )
139
139
 
140
140
  def close(self) -> None:
141
- return self._connection.close()
141
+ """
142
+ Aggressively close `self._connection`.
143
+
144
+ When `Connection.is_connected` is `False`, `Connection.close()` does
145
+ not call `Connection.client.close()`. Thus we do this explicitly here,
146
+ because we observed cases where `is_connected=False` but the underlying
147
+ `Transport` object was not closed.
148
+ """
149
+
150
+ self._connection.close()
151
+
152
+ if self._connection.client is not None:
153
+ self._connection.client.close()
142
154
 
143
155
  def run_command(
144
156
  self,
@@ -335,36 +347,169 @@ class FractalSSH(object):
335
347
  f.write(content)
336
348
 
337
349
 
338
- def get_ssh_connection(
339
- *,
340
- host: Optional[str] = None,
341
- user: Optional[str] = None,
342
- key_filename: Optional[str] = None,
343
- ) -> Connection:
350
+ class FractalSSHList(object):
344
351
  """
345
- Create a `fabric.Connection` object based on fractal-server settings
346
- or explicit arguments.
352
+ Collection of `FractalSSH` objects
347
353
 
348
- Args:
349
- host:
350
- user:
351
- key_filename:
354
+ Attributes are all private, and access to this collection must be
355
+ through methods (mostly the `get` one).
352
356
 
353
- Returns:
354
- Fabric connection object
357
+ Attributes:
358
+ _data:
359
+ Mapping of unique keys (the SSH-credentials tuples) to
360
+ `FractalSSH` objects.
361
+ _lock:
362
+ A `threading.Lock object`, to be acquired when changing `_data`.
363
+ _timeout: Timeout for `_lock` acquisition.
364
+ _logger_name: Logger name.
355
365
  """
356
- settings = Inject(get_settings)
357
- if host is None:
358
- host = settings.FRACTAL_SLURM_SSH_HOST
359
- if user is None:
360
- user = settings.FRACTAL_SLURM_SSH_USER
361
- if key_filename is None:
362
- key_filename = settings.FRACTAL_SLURM_SSH_PRIVATE_KEY_PATH
363
-
364
- connection = Connection(
365
- host=host,
366
- user=user,
367
- forward_agent=False,
368
- connect_kwargs={"key_filename": key_filename},
369
- )
370
- return connection
366
+
367
+ _data: dict[tuple[str, str, str], FractalSSH]
368
+ _lock: Lock
369
+ _timeout: float
370
+ _logger_name: str
371
+
372
+ def __init__(
373
+ self,
374
+ *,
375
+ timeout: float = 5.0,
376
+ logger_name: str = "fractal_server.FractalSSHList",
377
+ ):
378
+ self._lock = Lock()
379
+ self._data = {}
380
+ self._timeout = timeout
381
+ self._logger_name = logger_name
382
+ set_logger(self._logger_name)
383
+
384
+ @property
385
+ def logger(self) -> logging.Logger:
386
+ """
387
+ This property exists so that we never have to propagate the
388
+ `Logger` object.
389
+ """
390
+ return get_logger(self._logger_name)
391
+
392
+ @property
393
+ def size(self) -> int:
394
+ """
395
+ Number of current key-value pairs in `self._data`.
396
+ """
397
+ return len(self._data.values())
398
+
399
+ def get(self, *, host: str, user: str, key_path: str) -> FractalSSH:
400
+ """
401
+ Get the `FractalSSH` for the current credentials, or create one.
402
+
403
+ Note: Changing `_data` requires acquiring `_lock`.
404
+
405
+ Arguments:
406
+ host:
407
+ user:
408
+ key_path:
409
+ """
410
+ key = (host, user, key_path)
411
+ fractal_ssh = self._data.get(key, None)
412
+ if fractal_ssh is not None:
413
+ self.logger.info(
414
+ f"Return existing FractalSSH object for {user}@{host}"
415
+ )
416
+ return fractal_ssh
417
+ else:
418
+ self.logger.info(f"Add new FractalSSH object for {user}@{host}")
419
+ connection = Connection(
420
+ host=host,
421
+ user=user,
422
+ forward_agent=False,
423
+ connect_kwargs={
424
+ "key_filename": key_path,
425
+ "look_for_keys": False,
426
+ },
427
+ )
428
+ with self.acquire_lock_with_timeout():
429
+ self._data[key] = FractalSSH(connection=connection)
430
+ return self._data[key]
431
+
432
+ def contains(
433
+ self,
434
+ *,
435
+ host: str,
436
+ user: str,
437
+ key_path: str,
438
+ ) -> bool:
439
+ """
440
+ Return whether a given key is present in the collection.
441
+
442
+ Arguments:
443
+ host:
444
+ user:
445
+ key_path:
446
+ """
447
+ key = (host, user, key_path)
448
+ return key in self._data.keys()
449
+
450
+ def remove(
451
+ self,
452
+ *,
453
+ host: str,
454
+ user: str,
455
+ key_path: str,
456
+ ) -> None:
457
+ """
458
+ Remove a key from `_data` and close the corresponding connection.
459
+
460
+ Note: Changing `_data` requires acquiring `_lock`.
461
+
462
+ Arguments:
463
+ host:
464
+ user:
465
+ key_path:
466
+ """
467
+ key = (host, user, key_path)
468
+ with self.acquire_lock_with_timeout():
469
+ self.logger.info(
470
+ f"Removing FractalSSH object for {user}@{host} "
471
+ "from collection."
472
+ )
473
+ fractal_ssh_obj = self._data.pop(key)
474
+ self.logger.info(
475
+ f"Closing FractalSSH object for {user}@{host} "
476
+ f"({fractal_ssh_obj.is_connected=})."
477
+ )
478
+ fractal_ssh_obj.close()
479
+
480
+ def close_all(self, *, timeout: float = 5.0):
481
+ """
482
+ Close all `FractalSSH` objects in the collection.
483
+
484
+ Arguments:
485
+ timeout:
486
+ Timeout for `FractalSSH._lock` acquisition, to be obtained
487
+ before closing.
488
+ """
489
+ for key, fractal_ssh_obj in self._data.items():
490
+ host, user, _ = key[:]
491
+ self.logger.info(
492
+ f"Closing FractalSSH object for {user}@{host} "
493
+ f"({fractal_ssh_obj.is_connected=})."
494
+ )
495
+ with fractal_ssh_obj.acquire_timeout(timeout=timeout):
496
+ fractal_ssh_obj.close()
497
+
498
+ @contextmanager
499
+ def acquire_lock_with_timeout(self) -> Generator[Literal[True], Any, None]:
500
+ self.logger.debug(
501
+ f"Trying to acquire lock, with timeout {self._timeout} s"
502
+ )
503
+ result = self._lock.acquire(timeout=self._timeout)
504
+ try:
505
+ if not result:
506
+ self.logger.error("Lock was *NOT* acquired.")
507
+ raise FractalSSHListTimeoutError(
508
+ f"Failed to acquire lock within {self._timeout} ss"
509
+ )
510
+ self.logger.debug("Lock was acquired.")
511
+ yield result
512
+ finally:
513
+ if result:
514
+ self._lock.release()
515
+ self.logger.debug("Lock was released")
@@ -57,6 +57,7 @@ def _customize_and_run_template(
57
57
  tmpdir: str,
58
58
  logger_name: str,
59
59
  fractal_ssh: FractalSSH,
60
+ tasks_base_dir: str,
60
61
  ) -> str:
61
62
  """
62
63
  Customize one of the template bash scripts, transfer it to the remote host
@@ -72,7 +73,6 @@ def _customize_and_run_template(
72
73
  """
73
74
  logger = get_logger(logger_name)
74
75
  logger.debug(f"_customize_and_run_template {script_filename} - START")
75
- settings = Inject(get_settings)
76
76
 
77
77
  # Read template
78
78
  template_path = templates_folder / script_filename
@@ -88,7 +88,7 @@ def _customize_and_run_template(
88
88
 
89
89
  # Transfer script to remote host
90
90
  script_path_remote = os.path.join(
91
- settings.FRACTAL_SLURM_SSH_WORKING_BASE_DIR,
91
+ tasks_base_dir,
92
92
  f"script_{abs(hash(tmpdir))}{script_filename}",
93
93
  )
94
94
  logger.debug(f"Now transfer {script_path_local=} over SSH.")
@@ -111,6 +111,7 @@ def background_collect_pip_ssh(
111
111
  state_id: int,
112
112
  task_pkg: _TaskCollectPip,
113
113
  fractal_ssh: FractalSSH,
114
+ tasks_base_dir: str,
114
115
  ) -> None:
115
116
  """
116
117
  Collect a task package over SSH
@@ -121,6 +122,13 @@ def background_collect_pip_ssh(
121
122
  NOTE: by making this function sync, it will run within a thread - due to
122
123
  starlette/fastapi handling of background tasks (see
123
124
  https://github.com/encode/starlette/blob/master/starlette/background.py).
125
+
126
+
127
+ Arguments:
128
+ state_id:
129
+ task_pkg:
130
+ fractal_ssh:
131
+ tasks_base_dir:
124
132
  """
125
133
 
126
134
  # Work within a temporary folder, where also logs will be placed
@@ -140,7 +148,6 @@ def background_collect_pip_ssh(
140
148
  with next(get_sync_db()) as db:
141
149
  try:
142
150
  # Prepare replacements for task-collection scripts
143
- settings = Inject(get_settings)
144
151
  python_bin = get_python_interpreter_v2(
145
152
  python_version=task_pkg.python_version
146
153
  )
@@ -163,11 +170,12 @@ def background_collect_pip_ssh(
163
170
  f"{install_string}=={task_pkg.package_version}"
164
171
  )
165
172
  package_env_dir = (
166
- Path(settings.FRACTAL_SLURM_SSH_WORKING_BASE_DIR)
173
+ Path(tasks_base_dir)
167
174
  / ".fractal"
168
175
  / f"{task_pkg.package_name}{package_version}"
169
176
  ).as_posix()
170
177
  logger.debug(f"{package_env_dir=}")
178
+ settings = Inject(get_settings)
171
179
  replacements = [
172
180
  ("__PACKAGE_NAME__", task_pkg.package_name),
173
181
  ("__PACKAGE_ENV_DIR__", package_env_dir),
@@ -186,6 +194,7 @@ def background_collect_pip_ssh(
186
194
  tmpdir=tmpdir,
187
195
  logger_name=LOGGER_NAME,
188
196
  fractal_ssh=fractal_ssh,
197
+ tasks_base_dir=tasks_base_dir,
189
198
  )
190
199
 
191
200
  fractal_ssh.check_connection()
@@ -332,7 +341,7 @@ def background_collect_pip_ssh(
332
341
  )
333
342
  fractal_ssh.remove_folder(
334
343
  folder=package_env_dir,
335
- safe_root=settings.FRACTAL_SLURM_SSH_WORKING_BASE_DIR, # noqa: E501
344
+ safe_root=tasks_base_dir,
336
345
  )
337
346
  logger.info(
338
347
  f"Deleted remoted folder {package_env_dir}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fractal-server
3
- Version: 2.5.1
3
+ Version: 2.6.0a0
4
4
  Summary: Server component of the Fractal analytics platform
5
5
  Home-page: https://github.com/fractal-analytics-platform/fractal-server
6
6
  License: BSD-3-Clause
@@ -1,12 +1,13 @@
1
- fractal_server/__init__.py,sha256=8LAfKcNqeSASwVPDsGBZzXPzRTZGKfeNUwe56FocjrA,22
2
- fractal_server/__main__.py,sha256=upYBkGYrkBnkS1rp4D_nb_1LS37QT4j-wxGX1ZMvR4A,5704
1
+ fractal_server/__init__.py,sha256=lk_fIGL_HoswrWAxf9d6JXNZnZqpaYWUlhLAW5EmVQE,24
2
+ fractal_server/__main__.py,sha256=WcBAkmVE9aH5mDI6wGkVmPAql2N5Vyk0A-7zuUl8WX0,6122
3
3
  fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
4
4
  fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  fractal_server/app/db/__init__.py,sha256=81rK9w1__Z6PJ5cEcChPVc-wI9YOK4fN--_5Opry0MQ,4119
6
- fractal_server/app/models/__init__.py,sha256=zt0Tiv91DWLg0daT8bkENz-LusihOJJX1h09UfHlAns,452
6
+ fractal_server/app/models/__init__.py,sha256=aG7mf1zZbsgzDSp7GHEcZhdjHfW3TGPOLCI8MrvYhPw,500
7
7
  fractal_server/app/models/linkusergroup.py,sha256=ufthlbLFAWMU_dJmsVZzVlQa_D9C9SmgydxypQ2Xq1U,309
8
8
  fractal_server/app/models/linkuserproject.py,sha256=eQaourbGRshvlMVlKzLYJKHEjfsW1CbWws9yW4eHXhA,567
9
- fractal_server/app/models/security.py,sha256=JGC3NNakIbJWhwksSIgJq0Jawo7m_fhsWX9L-uKpWJc,3551
9
+ fractal_server/app/models/security.py,sha256=DY1JGS11pdlFXTValt86hNcL6a6kLRZ5xkOhhZJ8c1U,3831
10
+ fractal_server/app/models/user_settings.py,sha256=0YXCAwoAVGqI2irRLdXgr9-JS0STtHhSaoFENigAnrk,1312
10
11
  fractal_server/app/models/v1/__init__.py,sha256=hUI7dEbPaiZGN0IbHW4RSmSicyvtn_xeuevoX7zvUwI,466
11
12
  fractal_server/app/models/v1/dataset.py,sha256=99GDgt7njx8yYQApkImqp_7bHA5HH3ElvbR6Oyj9kVI,2017
12
13
  fractal_server/app/models/v1/job.py,sha256=QLGXcWdVRHaUHQNDapYYlLpEfw4K7QyD8TmcwhrWw2o,3304
@@ -28,40 +29,41 @@ fractal_server/app/routes/admin/v1.py,sha256=GIpZlwAwwwLGDWkBqywhtmp9TGsKLhGmZAd
28
29
  fractal_server/app/routes/admin/v2.py,sha256=hoEbH_sRJ-MaKMwhFp8c7SNObP0-Kmtgw1zbs_Z3nLY,12971
29
30
  fractal_server/app/routes/api/__init__.py,sha256=2IDheFi0OFdsUg7nbUiyahqybvpgXqeHUXIL2QtWrQQ,641
30
31
  fractal_server/app/routes/api/v1/__init__.py,sha256=Y2HQdG197J0a7DyQEE2jn53IfxD0EHGhzK1I2JZuEck,958
31
- fractal_server/app/routes/api/v1/_aux_functions.py,sha256=1YZdLch-Q1c44hQ_1ZEiijgWhLW6H3QEL5y5SHw5Ijk,13023
32
+ fractal_server/app/routes/api/v1/_aux_functions.py,sha256=P9Q48thGH95w0h5cacYoibxqgiiLW4oqZ8rNJ2LIISY,13219
32
33
  fractal_server/app/routes/api/v1/dataset.py,sha256=KVfKdp-bT8eB14kCjTSmpji4a2IPIHxGID8L10h3Wac,17282
33
34
  fractal_server/app/routes/api/v1/job.py,sha256=0jGxvu0xNQnWuov2qnoo9yE7Oat37XbcVn4Ute-UsiE,5370
34
- fractal_server/app/routes/api/v1/project.py,sha256=mFDqhkd_zR3wqxW5zadCCrxIX-jgL3lYF3CtfbV4pPs,16373
35
- fractal_server/app/routes/api/v1/task.py,sha256=OLASM6M4yfHvQgHQOuR5810jR2s0_W1HQAmhGQkg0so,6356
35
+ fractal_server/app/routes/api/v1/project.py,sha256=V-oeLiLs3vhD6STKiI2_mOyeB7FDUAcEXevHZbCWQ10,15956
36
+ fractal_server/app/routes/api/v1/task.py,sha256=eW89nMCjpD4G6tHXDo2qGBKqWaPirjH6M3hpdJQhfa0,6528
36
37
  fractal_server/app/routes/api/v1/task_collection.py,sha256=VYxhtd_idBppgJM7-FCHikI2OKMAIz05fhV_TsJpWI8,9060
37
38
  fractal_server/app/routes/api/v1/workflow.py,sha256=2T93DuEnSshaDCue-JPmjuvGCtbk6lt9pFMuPt783t8,11217
38
39
  fractal_server/app/routes/api/v1/workflowtask.py,sha256=OYYConwJbmNULDw5I3T-UbSJKrbbBiAHbbBeVcpoFKQ,5785
39
40
  fractal_server/app/routes/api/v2/__init__.py,sha256=301enf_GsL27_CnG6lSbMIeoz9-rrb3R2iDSs5pk4q8,1650
40
- fractal_server/app/routes/api/v2/_aux_functions.py,sha256=OLDwaZpkCr6q2heebmceGY5YvuKQy0-mVkkfcCp6kEc,13550
41
+ fractal_server/app/routes/api/v2/_aux_functions.py,sha256=mAsJs3QeCrIYKmkXo5aqhrGCbyvbPg_fqZWQNJ-vI8o,13746
41
42
  fractal_server/app/routes/api/v2/dataset.py,sha256=Eilf_BAGjicIhqUiVwI86jlW45ineA5sVzxXW4b2GoQ,8329
42
43
  fractal_server/app/routes/api/v2/images.py,sha256=JR1rR6qEs81nacjriOXAOBQjAbCXF4Ew7M7mkWdxBU0,7920
43
44
  fractal_server/app/routes/api/v2/job.py,sha256=Bga2Kz1OjvDIdxZObWaaXVhNIhC_5JKhKRjEH2_ayEE,5157
44
45
  fractal_server/app/routes/api/v2/project.py,sha256=eWYFJ7F2ZYQcpi-_n-rhPF-Q4gJhzYBsVGYFhHZZXAE,6653
45
46
  fractal_server/app/routes/api/v2/status.py,sha256=6N9DSZ4iFqbZImorWfEAPoyoFUgEruo4Hweqo0x0xXU,6435
46
- fractal_server/app/routes/api/v2/submit.py,sha256=iTGCYbxiZNszHQa8r3gmAR4QcF6QhVrb8ktzste2Ovc,8775
47
- fractal_server/app/routes/api/v2/task.py,sha256=XgRnGBvSoI9VNJHtWZQ2Ide99f6elo7a2FN3GQkf0dU,8376
48
- fractal_server/app/routes/api/v2/task_collection.py,sha256=wEwP8VfsxhKPZ6K3v1Bnput_Zw0Cjhlaal0-e50feIQ,12337
49
- fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=CbeC7xYYF8K9JVOOunL3Y_3wXBEGGGoiJcoPa2hEftI,6127
47
+ fractal_server/app/routes/api/v2/submit.py,sha256=SVTV9wGC_mrKWHHxWtjvsdtiRzOeSRlw2PlDYLk66Ew,9006
48
+ fractal_server/app/routes/api/v2/task.py,sha256=XDKNmin-gyLpA6eVgh89OdrNq92Vkrtxjr8VI-PIV2E,8548
49
+ fractal_server/app/routes/api/v2/task_collection.py,sha256=3ugtkrlrFWvLSHXomF0oOg2Ayg2ige1gr5F51BCQEL4,12950
50
+ fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=Q9vVicfY_VJKLu7yBox2KnBSiPBDZxAnoxykWmwD8X0,6291
50
51
  fractal_server/app/routes/api/v2/workflow.py,sha256=rMCcclz9aJAMSVLncUdSDGrgkKbn4KOCZTqZtqs2HDY,10428
51
52
  fractal_server/app/routes/api/v2/workflowtask.py,sha256=-3-c8DDnxGjMwWbX_h5V5OLaC_iCLXYzwWKBUaL-5wE,7060
52
53
  fractal_server/app/routes/auth/__init__.py,sha256=fao6CS0WiAjHDTvBzgBVV_bSXFpEAeDBF6Z6q7rRkPc,1658
53
- fractal_server/app/routes/auth/_aux_auth.py,sha256=G0-VwAq2UKlvKc5erCU8vhMQWA6gUgsRig9GmexEy74,3189
54
- fractal_server/app/routes/auth/current_user.py,sha256=E6fDWw8xGxgE816S9Mriow1OMOaxw8DIKAFcrGpiaIU,2106
54
+ fractal_server/app/routes/auth/_aux_auth.py,sha256=a3DCj6_tekf4Bfu8Kax9uxVGbTuVsONgki7E6AJUN_8,3269
55
+ fractal_server/app/routes/auth/current_user.py,sha256=kJk6bONS8bwPoJh40mpmVGM2bb5qRrJ6Rf_p1_flvgI,3480
55
56
  fractal_server/app/routes/auth/group.py,sha256=az8kRJJU5rA0L8GCX5kvRNuQhrsoGWPuvQ26z7iFQ3E,5388
56
57
  fractal_server/app/routes/auth/group_names.py,sha256=zvYDfhxKlDmbSr-oLXYy6WUVkPPTvzH6ZJtuoNdGZbE,960
57
58
  fractal_server/app/routes/auth/login.py,sha256=tSu6OBLOieoBtMZB4JkBAdEgH2Y8KqPGSbwy7NIypIo,566
58
59
  fractal_server/app/routes/auth/oauth.py,sha256=AnFHbjqL2AgBX3eksI931xD6RTtmbciHBEuGf9YJLjU,1895
59
60
  fractal_server/app/routes/auth/register.py,sha256=DlHq79iOvGd_gt2v9uwtsqIKeO6i_GKaW59VIkllPqY,587
60
61
  fractal_server/app/routes/auth/router.py,sha256=zWoZWiO69U48QFQf5tLRYQDWu8PUCj7GacnaFeW1n_I,618
61
- fractal_server/app/routes/auth/users.py,sha256=lMfcob_Bxz1j2EyddKeAoQPqMZTP40aOkiuk7Oeqo0E,6987
62
+ fractal_server/app/routes/auth/users.py,sha256=63gOBjGaQpUfakVmqb9RzBcKdIafiFlmaN_ctUOA0fg,8356
62
63
  fractal_server/app/routes/aux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
64
  fractal_server/app/routes/aux/_job.py,sha256=q-RCiW17yXnZKAC_0La52RLvhqhxuvbgQJ2MlGXOj8A,702
64
65
  fractal_server/app/routes/aux/_runner.py,sha256=FdCVla5DxGAZ__aB7Z8dEJzD_RIeh5tftjrPyqkr8N8,895
66
+ fractal_server/app/routes/aux/validate_user_settings.py,sha256=Y8eubau0julkwVYB5nA83nDtxh_7RU9Iq0zAhb_dXLA,2351
65
67
  fractal_server/app/runner/.gitignore,sha256=ytzN_oyHWXrGU7iFAtoHSTUbM6Rn6kG0Zkddg0xZk6s,16
66
68
  fractal_server/app/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
69
  fractal_server/app/runner/async_wrap.py,sha256=_O6f8jftKYXG_DozkmlrDBhoiK9QhE9MablOyECq2_M,829
@@ -76,12 +78,12 @@ fractal_server/app/runner/executors/slurm/remote.py,sha256=wLziIsGdSMiO-jIXM8x77
76
78
  fractal_server/app/runner/executors/slurm/ssh/__init__.py,sha256=Cjn1rYvljddi96tAwS-qqGkNfOcfPzjChdaEZEObCcM,65
77
79
  fractal_server/app/runner/executors/slurm/ssh/_executor_wait_thread.py,sha256=bKo5Ja0IGxJWpPWyh9dN0AG-PwzTDZzD5LyaEHB3YU4,3742
78
80
  fractal_server/app/runner/executors/slurm/ssh/_slurm_job.py,sha256=rwlqZzoGo4SAb4nSlFjsQJdaCgfM1J6YGcjb8yYxlqc,4506
79
- fractal_server/app/runner/executors/slurm/ssh/executor.py,sha256=oCc5cLZoNmJ3ENV0VaYRiIKayVClKDoEnjgZjHU864Y,57052
81
+ fractal_server/app/runner/executors/slurm/ssh/executor.py,sha256=K1lKsn40PqQb-GZKwJkzeJk2Q8OGqy6YR-IxcV0E0Pw,57705
80
82
  fractal_server/app/runner/executors/slurm/sudo/__init__.py,sha256=Cjn1rYvljddi96tAwS-qqGkNfOcfPzjChdaEZEObCcM,65
81
83
  fractal_server/app/runner/executors/slurm/sudo/_check_jobs_status.py,sha256=wAgwpVcr6JIslKHOuS0FhRa_6T1KCManyRJqA-fifzw,1909
82
84
  fractal_server/app/runner/executors/slurm/sudo/_executor_wait_thread.py,sha256=z5LlhaiqAb8pHsF1WwdzXN39C5anQmwjo1rSQgtRAYE,4422
83
85
  fractal_server/app/runner/executors/slurm/sudo/_subprocess_run_as_user.py,sha256=g8wqUjSicN17UZVXlfaMomYZ-xOIbBu1oE7HdJTzfvw,5218
84
- fractal_server/app/runner/executors/slurm/sudo/executor.py,sha256=FXf9I-12C3bnP20OMTdxwnBVpniluEf4V6V2Y3QVStk,48594
86
+ fractal_server/app/runner/executors/slurm/sudo/executor.py,sha256=6OPe9t70gLyuC2JhWt2o1f0e7zhQPBtrbMHQkDd6RAQ,48725
85
87
  fractal_server/app/runner/extract_archive.py,sha256=tLpjDrX47OjTNhhoWvm6iNukg8KoieWyTb7ZfvE9eWU,2483
86
88
  fractal_server/app/runner/filenames.py,sha256=9lwu3yB4C67yiijYw8XIKaLFn3mJUt6_TCyVFM_aZUQ,206
87
89
  fractal_server/app/runner/run_subprocess.py,sha256=c3JbYXq3hX2aaflQU19qJ5Xs6J6oXGNvnTEoAfv2bxc,959
@@ -99,7 +101,7 @@ fractal_server/app/runner/v1/_slurm/_submit_setup.py,sha256=KO9c694d318adoPQh9UG
99
101
  fractal_server/app/runner/v1/_slurm/get_slurm_config.py,sha256=6pQNNx997bLIfLp0guF09t_O0ZYRXnbEGLktSAcKnic,5999
100
102
  fractal_server/app/runner/v1/common.py,sha256=_L-vjLnWato80VdlB_BFN4G8P4jSM07u-5cnl1T3S34,3294
101
103
  fractal_server/app/runner/v1/handle_failed_job.py,sha256=bHzScC_aIlU3q-bQxGW6rfWV4xbZ2tho_sktjsAs1no,4684
102
- fractal_server/app/runner/v2/__init__.py,sha256=L9fiDphG3qa5w_zpBAaOeUqTezwSt8VRb6XXtkKrD58,17042
104
+ fractal_server/app/runner/v2/__init__.py,sha256=BkmaVbhh6XMK_Y2Suzz3bXm3Ff2l0JKbHqs8zp0hi8A,16965
103
105
  fractal_server/app/runner/v2/_local/__init__.py,sha256=KTj14K6jH8fXGUi5P7u5_RqEE1zF4aXtgPxCKzw46iw,5971
104
106
  fractal_server/app/runner/v2/_local/_local_config.py,sha256=9oi209Dlp35ANfxb_DISqmMKKc6DPaMsmYVWbZLseME,3630
105
107
  fractal_server/app/runner/v2/_local/_submit_setup.py,sha256=MucNOo8Er0F5ZIwH7CnTeXgnFMc6d3pKPkv563QNVi0,1630
@@ -122,10 +124,11 @@ fractal_server/app/runner/v2/runner_functions.py,sha256=BLREIcQaE6FSc2AEJyZuiYk6
122
124
  fractal_server/app/runner/v2/runner_functions_low_level.py,sha256=1fWvQ6YZUUnDhO_mipXC5hnaT-zK-GHxg8ayoxZX82k,3648
123
125
  fractal_server/app/runner/v2/task_interface.py,sha256=myS-kT0DsJ8xIJZBVEzgD8g54VbiwL6i7Im3e1zcVHQ,1866
124
126
  fractal_server/app/runner/versions.py,sha256=dSaPRWqmFPHjg20kTCHmi_dmGNcCETflDtDLronNanU,852
125
- fractal_server/app/schemas/__init__.py,sha256=jiIf54owztXupv3PO6Ilh0qcrkh2RUzKq4bcEFqEfc4,40
127
+ fractal_server/app/schemas/__init__.py,sha256=stURAU_t3AOBaH0HSUbV-GKhlPKngnnIMoqWc3orFyI,135
126
128
  fractal_server/app/schemas/_validators.py,sha256=1dTOYr1IZykrxuQSV2-zuEMZbKe_nGwrfS7iUrsh-sE,3461
127
- fractal_server/app/schemas/user.py,sha256=OJutfwMR1JPEmdFzqA4vHMZO-mhB4Mb9Yyx_G24XTCM,4081
129
+ fractal_server/app/schemas/user.py,sha256=VNnAPnAVK6X0PZlw7XehocAshVNuUHdDwiZVWCCor6Y,2156
128
130
  fractal_server/app/schemas/user_group.py,sha256=2f9XQ6kIar6NMY4UCN0yOnve6ZDHUVZaHv1dna1Vfjg,1446
131
+ fractal_server/app/schemas/user_settings.py,sha256=wC_UbAjUgQI61aiX71Y-PWSPGtyOVwUVobjCLz__k9k,2840
129
132
  fractal_server/app/schemas/v1/__init__.py,sha256=CrBGgBhoemCvmZ70ZUchM-jfVAICnoa7AjZBAtL2UB0,1852
130
133
  fractal_server/app/schemas/v1/applyworkflow.py,sha256=uuIh7fHlHEL4yLqL-dePI6-nfCsqgBYATmht7w_KITw,4302
131
134
  fractal_server/app/schemas/v1/dataset.py,sha256=n71lNUO3JLy2K3IM9BZM2Fk1EnKQOTU7pm2s2rJ1FGY,3444
@@ -147,16 +150,18 @@ fractal_server/app/schemas/v2/task.py,sha256=XsN8w1Szs8BrxxRtKyWCHKjN4Od-Kmlhi76
147
150
  fractal_server/app/schemas/v2/task_collection.py,sha256=8PG1bOqkfQqORMN0brWf6mHDmijt0bBW-mZsF7cSxUs,6129
148
151
  fractal_server/app/schemas/v2/workflow.py,sha256=Zzx3e-qgkH8le0FUmAx9UrV5PWd7bj14PPXUh_zgZXM,1827
149
152
  fractal_server/app/schemas/v2/workflowtask.py,sha256=TN-mdkuE_EWet9Wk-xFrUwIt_tXYcw88WOKMnUcchKk,5665
150
- fractal_server/app/security/__init__.py,sha256=vuAE0sg2er0I2PAf7xCUHcxbMgxV1d8y6oJjO98n86o,11858
151
- fractal_server/config.py,sha256=R0VezSe2PEDjQjHEX2V29A1jMdoomdyECBjWNY15v_0,25049
152
- fractal_server/data_migrations/2_4_0.py,sha256=T1HRRWp9ZuXeVfBY6NRGxQ8aNIHVSftOMnB-CMrfvi8,2117
153
+ fractal_server/app/security/__init__.py,sha256=V1NOWlmaFZHMR6SrkMl62jyAuqYONyo8lyGvR6UZesM,12312
154
+ fractal_server/app/user_settings.py,sha256=aZgQ3i0JkHfgwLGW1ee6Gzr1ae3IioFfJKKSsSS8Svk,1312
155
+ fractal_server/config.py,sha256=NucdVswA4MJpgeePDqSsU01I893Bn_hqWUrxrax83Ls,24257
156
+ fractal_server/data_migrations/2_6_0.py,sha256=Vl17mFiOF5jQsktOnog5vnaXXcUXOJRa-ljas9kUX0E,1863
153
157
  fractal_server/data_migrations/README.md,sha256=_3AEFvDg9YkybDqCLlFPdDmGJvr6Tw7HRI14aZ3LOIw,398
158
+ fractal_server/data_migrations/tools.py,sha256=LeMeASwYGtEqd-3wOLle6WARdTGAimoyMmRbbJl-hAM,572
154
159
  fractal_server/gunicorn_fractal.py,sha256=u6U01TLGlXgq1v8QmEpLih3QnsInZD7CqphgJ_GrGzc,1230
155
160
  fractal_server/images/__init__.py,sha256=xO6jTLE4EZKO6cTDdJsBmK9cdeh9hFTaSbSuWgQg7y4,196
156
161
  fractal_server/images/models.py,sha256=9ipU5h4N6ogBChoB-2vHoqtL0TXOHCv6kRR-fER3mkM,4167
157
162
  fractal_server/images/tools.py,sha256=gxeniYy4Z-cp_ToK2LHPJUTVVUUrdpogYdcBUvBuLiY,2209
158
163
  fractal_server/logger.py,sha256=56wfka6fHaa3Rx5qO009nEs_y8gx5wZ2NUNZZ1I-uvc,5130
159
- fractal_server/main.py,sha256=NUvMd8C8kosulAcQ8pCFLnOGdLw7j-6RzcHxoNvSB7k,5003
164
+ fractal_server/main.py,sha256=68rVybnviF28yFgRhfHZXwnf6LyzkcmeYYZZppboU4M,4925
160
165
  fractal_server/migrations/README,sha256=4rQvyDfqodGhpJw74VYijRmgFP49ji5chyEemWGHsuw,59
161
166
  fractal_server/migrations/env.py,sha256=mEiX0TRa_8KAYBrUGJTx1cFJ5YAq_oNHHsFCp1raegk,2543
162
167
  fractal_server/migrations/naming_convention.py,sha256=htbKrVdetx3pklowb_9Cdo5RqeF0fJ740DNecY5de_M,265
@@ -173,6 +178,7 @@ fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py,sh
173
178
  fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py,sha256=6pgODDtyAxevZvAJBj9IJ41inhV1RpwbpZr_qfPPu1A,1115
174
179
  fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py,sha256=eKTZm3EgUgapXBxO0RuHkEfTKic-TZG3ADaMpGLuc0k,1057
175
180
  fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py,sha256=0im6TxDr53sKKcjiPgeH4ftVRGnRXZSh2lPbRQ1Ir9w,883
181
+ fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py,sha256=syONdZNf4-OnAcWIsbzXpYwpXPsXZ4SsmjwVvmVG0PU,2256
176
182
  fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py,sha256=4l1AHGUsa0ONoJVZlr3fTXw_xbbQ8O7wlD92Az2aRfM,1849
177
183
  fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py,sha256=ekDUML7ILpmdoqEclKbEUdyLi4uw9HSG_sTjG2hp_JE,867
178
184
  fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py,sha256=6cHEZFuTXiQg9yu32Y3RH1XAl71av141WQ6UMbiITIg,949
@@ -181,7 +187,7 @@ fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py
181
187
  fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py,sha256=9BwqUS9Gf7UW_KjrzHbtViC880qhD452KAytkHWWZyk,746
182
188
  fractal_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
183
189
  fractal_server/ssh/__init__.py,sha256=sVUmzxf7_DuXG1xoLQ1_00fo5NPhi2LJipSmU5EAkPs,124
184
- fractal_server/ssh/_fabric.py,sha256=wJFgdBZ_-Zs1FbHJ7sqqkx--1BVJhZIMEk-s_CKPY20,11591
190
+ fractal_server/ssh/_fabric.py,sha256=B9C7Cj9ibrT1_OGlu38Jz94elNofLvkP1pxf0Tv8Eic,16140
185
191
  fractal_server/string_tools.py,sha256=YyopB2ZZ8iL9JLDXUA8PI0hahivqLiohir2HsAlEzqE,2170
186
192
  fractal_server/syringe.py,sha256=3qSMW3YaMKKnLdgnooAINOPxnCOxP7y2jeAQYB21Gdo,2786
187
193
  fractal_server/tasks/__init__.py,sha256=kadmVUoIghl8s190_Tt-8f-WBqMi8u8oU4Pvw39NHE8,23
@@ -196,7 +202,7 @@ fractal_server/tasks/v2/_TaskCollectPip.py,sha256=kWQNMNZ8OEddkYhmhsk3E6ArcaD7qe
196
202
  fractal_server/tasks/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
203
  fractal_server/tasks/v2/_venv_pip.py,sha256=6NCItfeWgO9BDnlfhoCfiUG5UCGGz_SJz4Mfn4Jg_nk,6489
198
204
  fractal_server/tasks/v2/background_operations.py,sha256=CQwQon5RKAXrjsN255Okh5dcT0R45axgqoPW3EB-v_Q,11527
199
- fractal_server/tasks/v2/background_operations_ssh.py,sha256=wVnE6bubKsFqxsBFdyCcvW8nRr4kTGUiyt2OKQFIwrU,14050
205
+ fractal_server/tasks/v2/background_operations_ssh.py,sha256=K2_MLmHaYBIyT9PfeLsA5JpNH6V1SHczNdQI6hH71GM,14112
200
206
  fractal_server/tasks/v2/endpoint_operations.py,sha256=gT38pl5TEH6WNWOtg4Itegt2lTJJI6YRa7fEj9Y4x2s,4226
201
207
  fractal_server/tasks/v2/templates/_1_create_venv.sh,sha256=5uW0ETYxl5xiQEXP107zgq8V_-vf3k5NzMMj1hSLjas,1015
202
208
  fractal_server/tasks/v2/templates/_2_upgrade_pip.sh,sha256=ca5Yng6JgJYu-a4QrsIsatwUmrLdRWBKw7_VJrY7WLY,555
@@ -207,8 +213,8 @@ fractal_server/tasks/v2/utils.py,sha256=JOyCacb6MNvrwfLNTyLwcz8y79J29YuJeJ2MK5kq
207
213
  fractal_server/urls.py,sha256=5o_qq7PzKKbwq12NHSQZDmDitn5RAOeQ4xufu-2v9Zk,448
208
214
  fractal_server/utils.py,sha256=b7WwFdcFZ8unyT65mloFToYuEDXpQoHRcmRNqrhd_dQ,2115
209
215
  fractal_server/zip_tools.py,sha256=xYpzBshysD2nmxkD5WLYqMzPYUcCRM3kYy-7n9bJL-U,4426
210
- fractal_server-2.5.1.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
211
- fractal_server-2.5.1.dist-info/METADATA,sha256=PERWmLEehrxcMRZM1CCRADi950e6Pa-ofw7tnwgyqXw,4628
212
- fractal_server-2.5.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
213
- fractal_server-2.5.1.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
214
- fractal_server-2.5.1.dist-info/RECORD,,
216
+ fractal_server-2.6.0a0.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
217
+ fractal_server-2.6.0a0.dist-info/METADATA,sha256=9N03OeHxGpun6VcE0goQQIFPG5WNhOy-r5bR5vuZxb0,4630
218
+ fractal_server-2.6.0a0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
219
+ fractal_server-2.6.0a0.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
220
+ fractal_server-2.6.0a0.dist-info/RECORD,,
@@ -1,61 +0,0 @@
1
- import logging
2
-
3
- from packaging.version import parse
4
- from sqlalchemy import select
5
-
6
- import fractal_server
7
- from fractal_server.app.db import get_sync_db
8
- from fractal_server.app.models import LinkUserGroup
9
- from fractal_server.app.models import UserGroup
10
- from fractal_server.app.models import UserOAuth
11
- from fractal_server.app.security import FRACTAL_DEFAULT_GROUP_NAME
12
-
13
-
14
- def _check_current_version(*, expected_version: str):
15
- # Check that this module matches with the current version
16
- module_version = parse(expected_version)
17
- current_version = parse(fractal_server.__VERSION__)
18
- if (
19
- current_version.major != module_version.major
20
- or current_version.minor != module_version.minor
21
- or current_version.micro != module_version.micro
22
- ):
23
- raise RuntimeError(
24
- f"{fractal_server.__VERSION__=} not matching with {__file__=}"
25
- )
26
-
27
-
28
- def fix_db():
29
- logger = logging.getLogger("fix_db")
30
- logger.warning("START execution of fix_db function")
31
- _check_current_version(expected_version="2.4.0")
32
-
33
- with next(get_sync_db()) as db:
34
- # Find default group
35
- stm = select(UserGroup).where(
36
- UserGroup.name == FRACTAL_DEFAULT_GROUP_NAME
37
- )
38
- res = db.execute(stm)
39
- default_group = res.scalar_one_or_none()
40
- if default_group is None:
41
- raise RuntimeError("Default group not found, exit.")
42
- logger.warning(
43
- "Default user group exists: "
44
- f"{default_group.id=}, {default_group.name=}."
45
- )
46
-
47
- # Find
48
- stm = select(UserOAuth)
49
- users = db.execute(stm).scalars().unique().all()
50
- for user in sorted(users, key=lambda x: x.id):
51
- logger.warning(
52
- f"START adding {user.id=} ({user.email=}) to default group."
53
- )
54
- link = LinkUserGroup(user_id=user.id, group_id=default_group.id)
55
- db.add(link)
56
- db.commit()
57
- logger.warning(
58
- f"END adding {user.id=} ({user.email=}) to default group."
59
- )
60
-
61
- logger.warning("END of execution of fix_db function")