rucio 37.1.0.post1__py3-none-any.whl → 37.3.0__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.

Potentially problematic release.


This version of rucio might be problematic. Click here for more details.

Files changed (106) hide show
  1. rucio/common/plugins.py +1 -1
  2. rucio/common/utils.py +17 -10
  3. rucio/core/did.py +32 -4
  4. rucio/core/did_meta_plugins/did_column_meta.py +1 -1
  5. rucio/core/replica.py +1 -1
  6. rucio/db/sqla/util.py +1 -1
  7. rucio/gateway/authentication.py +58 -88
  8. rucio/gateway/config.py +63 -75
  9. rucio/gateway/credential.py +11 -17
  10. rucio/gateway/did.py +245 -329
  11. rucio/gateway/dirac.py +33 -34
  12. rucio/gateway/exporter.py +27 -30
  13. rucio/gateway/heartbeat.py +15 -19
  14. rucio/gateway/importer.py +12 -14
  15. rucio/gateway/lifetime_exception.py +16 -24
  16. rucio/gateway/lock.py +27 -40
  17. rucio/gateway/meta_conventions.py +19 -28
  18. rucio/gateway/quarantined_replica.py +24 -27
  19. rucio/gateway/replica.py +223 -226
  20. rucio/gateway/rse.py +191 -218
  21. rucio/gateway/rule.py +115 -146
  22. rucio/gateway/scope.py +18 -25
  23. rucio/gateway/trace.py +48 -0
  24. rucio/gateway/vo.py +32 -37
  25. rucio/vcsversion.py +3 -3
  26. rucio/web/rest/flaskapi/v1/accounts.py +2 -2
  27. rucio/web/rest/flaskapi/v1/auth.py +15 -0
  28. rucio/web/rest/flaskapi/v1/common.py +20 -0
  29. rucio/web/rest/flaskapi/v1/config.py +7 -7
  30. rucio/web/rest/flaskapi/v1/credentials.py +20 -13
  31. rucio/web/rest/flaskapi/v1/dids.py +55 -55
  32. rucio/web/rest/flaskapi/v1/dirac.py +2 -2
  33. rucio/web/rest/flaskapi/v1/export.py +1 -1
  34. rucio/web/rest/flaskapi/v1/heartbeats.py +3 -3
  35. rucio/web/rest/flaskapi/v1/import.py +1 -1
  36. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +5 -5
  37. rucio/web/rest/flaskapi/v1/locks.py +4 -4
  38. rucio/web/rest/flaskapi/v1/main.py +17 -10
  39. rucio/web/rest/flaskapi/v1/meta_conventions.py +3 -3
  40. rucio/web/rest/flaskapi/v1/replicas.py +31 -30
  41. rucio/web/rest/flaskapi/v1/rses.py +37 -37
  42. rucio/web/rest/flaskapi/v1/rules.py +15 -15
  43. rucio/web/rest/flaskapi/v1/scopes.py +3 -3
  44. rucio/web/rest/flaskapi/v1/traces.py +75 -77
  45. rucio/web/rest/flaskapi/v1/vos.py +5 -7
  46. {rucio-37.1.0.post1.dist-info → rucio-37.3.0.dist-info}/METADATA +1 -2
  47. {rucio-37.1.0.post1.dist-info → rucio-37.3.0.dist-info}/RECORD +106 -105
  48. {rucio-37.1.0.post1.dist-info → rucio-37.3.0.dist-info}/WHEEL +1 -1
  49. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/alembic.ini.template +0 -0
  50. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
  51. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
  52. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
  53. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  54. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  55. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  56. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  57. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  58. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  59. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  60. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
  61. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
  62. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
  63. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/requirements.server.txt +0 -0
  64. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/tools/bootstrap.py +0 -0
  65. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
  66. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/data/rucio/tools/reset_database.py +0 -0
  67. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio +0 -0
  68. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-abacus-account +0 -0
  69. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-abacus-collection-replica +0 -0
  70. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-abacus-rse +0 -0
  71. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-admin +0 -0
  72. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-atropos +0 -0
  73. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-auditor +0 -0
  74. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-automatix +0 -0
  75. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-bb8 +0 -0
  76. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-cache-client +0 -0
  77. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-cache-consumer +0 -0
  78. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-conveyor-finisher +0 -0
  79. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-conveyor-poller +0 -0
  80. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-conveyor-preparer +0 -0
  81. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-conveyor-receiver +0 -0
  82. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-conveyor-stager +0 -0
  83. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-conveyor-submitter +0 -0
  84. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-conveyor-throttler +0 -0
  85. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-dark-reaper +0 -0
  86. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-dumper +0 -0
  87. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-follower +0 -0
  88. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-hermes +0 -0
  89. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-judge-cleaner +0 -0
  90. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-judge-evaluator +0 -0
  91. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-judge-injector +0 -0
  92. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-judge-repairer +0 -0
  93. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-kronos +0 -0
  94. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-minos +0 -0
  95. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-minos-temporary-expiration +0 -0
  96. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-necromancer +0 -0
  97. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-oauth-manager +0 -0
  98. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-reaper +0 -0
  99. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-replica-recoverer +0 -0
  100. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-rse-decommissioner +0 -0
  101. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-storage-consistency-actions +0 -0
  102. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-transmogrifier +0 -0
  103. {rucio-37.1.0.post1.data → rucio-37.3.0.data}/scripts/rucio-undertaker +0 -0
  104. {rucio-37.1.0.post1.dist-info → rucio-37.3.0.dist-info}/licenses/AUTHORS.rst +0 -0
  105. {rucio-37.1.0.post1.dist-info → rucio-37.3.0.dist-info}/licenses/LICENSE +0 -0
  106. {rucio-37.1.0.post1.dist-info → rucio-37.3.0.dist-info}/top_level.txt +0 -0
rucio/gateway/dirac.py CHANGED
@@ -15,28 +15,25 @@
15
15
  from typing import TYPE_CHECKING, Any, Optional
16
16
 
17
17
  from rucio.common.exception import AccessDenied
18
+ from rucio.common.types import InternalScope
18
19
  from rucio.common.utils import extract_scope
19
20
  from rucio.core import dirac
20
21
  from rucio.core.rse import get_rse_id
21
- from rucio.db.sqla.session import transactional_session
22
+ from rucio.core.scope import list_scopes
23
+ from rucio.db.sqla.constants import DatabaseOperationType
24
+ from rucio.db.sqla.session import db_session
22
25
  from rucio.gateway.permission import has_permission
23
- from rucio.gateway.scope import list_scopes
24
26
 
25
27
  if TYPE_CHECKING:
26
28
  from collections.abc import Iterable
27
29
 
28
- from sqlalchemy.orm import Session
29
30
 
30
-
31
- @transactional_session
32
31
  def add_files(
33
32
  lfns: "Iterable[dict[str, Any]]",
34
33
  issuer: str,
35
34
  ignore_availability: bool,
36
35
  parents_metadata: Optional[dict[str, Any]] = None,
37
36
  vo: str = 'def',
38
- *,
39
- session: "Session"
40
37
  ) -> None:
41
38
  """
42
39
  Bulk add files :
@@ -49,35 +46,37 @@ def add_files(
49
46
  :param ignore_availability: A boolean to ignore blocked sites.
50
47
  :param parents_metadata: Metadata for selected hierarchy DIDs. (dictionary {'lpn': {key : value}}). Default=None
51
48
  :param vo: The VO to act on.
52
- :param session: The database session in use.
53
49
 
54
50
  """
55
- scopes = list_scopes(vo=vo, session=session)
56
- dids = []
57
- rses = {}
58
- for lfn in lfns:
59
- scope, name = extract_scope(lfn['lfn'], scopes)
60
- dids.append({'scope': scope, 'name': name})
61
- rse = lfn['rse']
62
- if rse not in rses:
63
- rse_id = get_rse_id(rse=rse, vo=vo, session=session)
64
- rses[rse] = rse_id
65
- lfn['rse_id'] = rses[rse]
66
51
 
67
- # Check if the issuer can add dids and use skip_availabitlity
68
- for rse in rses:
69
- rse_id = rses[rse]
70
- kwargs = {'rse': rse, 'rse_id': rse_id}
71
- auth_result = has_permission(issuer=issuer, action='add_replicas', kwargs=kwargs, vo=vo, session=session)
72
- if not auth_result.allowed:
73
- raise AccessDenied('Account %s can not add file replicas on %s for VO %s. %s' % (issuer, rse, vo, auth_result.message))
74
- if not has_permission(issuer=issuer, action='skip_availability_check', kwargs=kwargs, vo=vo, session=session):
75
- ignore_availability = False
52
+ with db_session(DatabaseOperationType.WRITE) as session:
53
+ filter_ = {'scope': InternalScope(scope='*', vo=vo)}
54
+ scopes = [scope.external for scope in list_scopes(filter_=filter_, session=session)]
55
+ dids = []
56
+ rses = {}
57
+ for lfn in lfns:
58
+ scope, name = extract_scope(lfn['lfn'], scopes)
59
+ dids.append({'scope': scope, 'name': name})
60
+ rse = lfn['rse']
61
+ if rse not in rses:
62
+ rse_id = get_rse_id(rse=rse, vo=vo, session=session)
63
+ rses[rse] = rse_id
64
+ lfn['rse_id'] = rses[rse]
76
65
 
77
- # Check if the issuer can add the files
78
- kwargs = {'issuer': issuer, 'dids': dids}
79
- auth_result = has_permission(issuer=issuer, action='add_dids', kwargs=kwargs, vo=vo, session=session)
80
- if not auth_result.allowed:
81
- raise AccessDenied('Account %s can not bulk add data identifier for VO %s. %s' % (issuer, vo, auth_result.message))
66
+ # Check if the issuer can add dids and use skip_availabitlity
67
+ for rse in rses:
68
+ rse_id = rses[rse]
69
+ kwargs = {'rse': rse, 'rse_id': rse_id}
70
+ auth_result = has_permission(issuer=issuer, action='add_replicas', kwargs=kwargs, vo=vo, session=session)
71
+ if not auth_result.allowed:
72
+ raise AccessDenied('Account %s can not add file replicas on %s for VO %s. %s' % (issuer, rse, vo, auth_result.message))
73
+ if not has_permission(issuer=issuer, action='skip_availability_check', kwargs=kwargs, vo=vo, session=session):
74
+ ignore_availability = False
75
+
76
+ # Check if the issuer can add the files
77
+ kwargs = {'issuer': issuer, 'dids': dids}
78
+ auth_result = has_permission(issuer=issuer, action='add_dids', kwargs=kwargs, vo=vo, session=session)
79
+ if not auth_result.allowed:
80
+ raise AccessDenied('Account %s can not bulk add data identifier for VO %s. %s' % (issuer, vo, auth_result.message))
82
81
 
83
- dirac.add_files(lfns=lfns, account=issuer, ignore_availability=ignore_availability, parents_metadata=parents_metadata, vo=vo, session=session)
82
+ dirac.add_files(lfns=lfns, account=issuer, ignore_availability=ignore_availability, parents_metadata=parents_metadata, vo=vo, session=session)
rucio/gateway/exporter.py CHANGED
@@ -12,49 +12,46 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from typing import TYPE_CHECKING, Any
15
+ from typing import Any
16
16
 
17
17
  from rucio.common import exception
18
18
  from rucio.core import exporter
19
19
  from rucio.core.rse import get_rse_name
20
- from rucio.db.sqla.session import read_session
20
+ from rucio.db.sqla.constants import DatabaseOperationType
21
+ from rucio.db.sqla.session import db_session
21
22
  from rucio.gateway import permission
22
23
 
23
- if TYPE_CHECKING:
24
- from sqlalchemy.orm import Session
25
24
 
26
-
27
- @read_session
28
- def export_data(issuer: str, distance: bool = True, vo: str = 'def', *, session: "Session") -> dict[str, Any]:
25
+ def export_data(issuer: str, distance: bool = True, vo: str = 'def') -> dict[str, Any]:
29
26
  """
30
27
  Export data from Rucio.
31
28
 
32
29
  :param issuer: the issuer.
33
30
  :param distance: To enable the reporting of distance.
34
31
  :param vo: the VO of the issuer.
35
- :param session: The database session in use.
36
32
  """
37
33
  kwargs = {'issuer': issuer}
38
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='export', kwargs=kwargs, session=session)
39
- if not auth_result.allowed:
40
- raise exception.AccessDenied('Account %s can not export data. %s' % (issuer, auth_result.message))
41
-
42
- data = exporter.export_data(distance=distance, vo=vo, session=session)
43
- rses = {}
44
- distances = {}
45
-
46
- for rse_id in data['rses']:
47
- rse = data['rses'][rse_id]
48
- rses[get_rse_name(rse_id=rse_id, session=session)] = rse
49
- data['rses'] = rses
50
-
51
- if distance:
52
- for src_id in data['distances']:
53
- dests = data['distances'][src_id]
54
- src = get_rse_name(rse_id=src_id, session=session)
55
- distances[src] = {}
56
- for dest_id in dests:
57
- dest = get_rse_name(rse_id=dest_id, session=session)
58
- distances[src][dest] = dests[dest_id]
59
- data['distances'] = distances
34
+ with db_session(DatabaseOperationType.READ) as session:
35
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='export', kwargs=kwargs, session=session)
36
+ if not auth_result.allowed:
37
+ raise exception.AccessDenied('Account %s can not export data. %s' % (issuer, auth_result.message))
38
+
39
+ data = exporter.export_data(distance=distance, vo=vo, session=session)
40
+ rses = {}
41
+ distances = {}
42
+
43
+ for rse_id in data['rses']:
44
+ rse = data['rses'][rse_id]
45
+ rses[get_rse_name(rse_id=rse_id, session=session)] = rse
46
+ data['rses'] = rses
47
+
48
+ if distance:
49
+ for src_id in data['distances']:
50
+ dests = data['distances'][src_id]
51
+ src = get_rse_name(rse_id=src_id, session=session)
52
+ distances[src] = {}
53
+ for dest_id in dests:
54
+ dest = get_rse_name(rse_id=dest_id, session=session)
55
+ distances[src][dest] = dests[dest_id]
56
+ data['distances'] = distances
60
57
  return data
@@ -16,45 +16,40 @@ from typing import TYPE_CHECKING, Optional
16
16
 
17
17
  from rucio.common import exception
18
18
  from rucio.core import heartbeat
19
- from rucio.db.sqla.session import read_session, transactional_session
19
+ from rucio.db.sqla.constants import DatabaseOperationType
20
+ from rucio.db.sqla.session import db_session
20
21
  from rucio.gateway import permission
21
22
 
22
23
  if TYPE_CHECKING:
23
24
  from threading import Thread
24
25
 
25
- from sqlalchemy.orm import Session
26
26
 
27
-
28
- @read_session
29
- def list_heartbeats(issuer: Optional[str] = None, vo: str = 'def', *, session: "Session") -> list["heartbeat.HeartbeatDict"]:
27
+ def list_heartbeats(issuer: str, vo: str = 'def') -> list["heartbeat.HeartbeatDict"]:
30
28
  """
31
29
  Return a list of tuples of all heartbeats.
32
30
 
33
31
  :param issuer: The issuer account.
34
32
  :param vo: the VO for the issuer.
35
- :param session: The database session in use.
36
33
  :returns: List of tuples [('Executable', 'Hostname', ...), ...]
37
34
  """
38
35
 
39
36
  kwargs = {'issuer': issuer}
40
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='list_heartbeats', kwargs=kwargs, session=session)
41
- if not auth_result.allowed:
42
- raise exception.AccessDenied('%s cannot list heartbeats. %s' % (issuer, auth_result.message))
43
- return heartbeat.list_heartbeats(session=session)
37
+ with db_session(DatabaseOperationType.READ) as session:
38
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='list_heartbeats', kwargs=kwargs, session=session)
39
+ if not auth_result.allowed:
40
+ raise exception.AccessDenied('%s cannot list heartbeats. %s' % (issuer, auth_result.message))
41
+ return heartbeat.list_heartbeats(session=session)
44
42
 
45
43
 
46
- @transactional_session
47
44
  def create_heartbeat(
48
45
  executable: str,
49
46
  hostname: str,
50
47
  pid: int,
51
48
  older_than: int,
52
49
  payload: Optional[str],
50
+ issuer: str,
53
51
  thread: Optional["Thread"] = None,
54
- issuer: Optional[str] = None,
55
52
  vo: str = 'def',
56
- *,
57
- session: "Session"
58
53
  ) -> None:
59
54
  """
60
55
  Creates a heartbeat.
@@ -66,11 +61,12 @@ def create_heartbeat(
66
61
  :param thread: Python Thread Object.
67
62
  :param older_than: Ignore specified heartbeats older than specified nr of seconds.
68
63
  :param payload: Payload identifier which can be further used to identify the work a certain thread is executing.
69
- :param session: The database session in use.
70
64
 
71
65
  """
72
66
  kwargs = {'issuer': issuer}
73
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='send_heartbeats', kwargs=kwargs, session=session)
74
- if not auth_result.allowed:
75
- raise exception.AccessDenied('%s cannot send heartbeats. %s' % (issuer, auth_result.message))
76
- heartbeat.live(executable=executable, hostname=hostname, pid=pid, thread=thread, older_than=older_than, payload=payload, session=session)
67
+
68
+ with db_session(DatabaseOperationType.WRITE) as session:
69
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='send_heartbeats', kwargs=kwargs, session=session)
70
+ if not auth_result.allowed:
71
+ raise exception.AccessDenied('%s cannot send heartbeats. %s' % (issuer, auth_result.message))
72
+ heartbeat.live(executable=executable, hostname=hostname, pid=pid, thread=thread, older_than=older_than, payload=payload, session=session)
rucio/gateway/importer.py CHANGED
@@ -12,35 +12,33 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from typing import TYPE_CHECKING, Any
15
+ from typing import Any
16
16
 
17
17
  from rucio.common import exception
18
18
  from rucio.common.schema import validate_schema
19
19
  from rucio.common.types import InternalAccount
20
20
  from rucio.core import importer
21
- from rucio.db.sqla.session import transactional_session
21
+ from rucio.db.sqla.constants import DatabaseOperationType
22
+ from rucio.db.sqla.session import db_session
22
23
  from rucio.gateway import permission
23
24
 
24
- if TYPE_CHECKING:
25
- from sqlalchemy.orm import Session
26
25
 
27
-
28
- @transactional_session
29
- def import_data(data: dict[str, Any], issuer: str, vo: str = 'def', *, session: "Session") -> None:
26
+ def import_data(data: dict[str, Any], issuer: str, vo: str = 'def') -> None:
30
27
  """
31
28
  Import data to add/update/delete records in Rucio.
32
29
 
33
30
  :param data: data to be imported.
34
31
  :param issuer: the issuer.
35
32
  :param vo: the VO of the issuer.
36
- :param session: The database session in use.
37
33
  """
38
34
  kwargs = {'issuer': issuer}
39
35
  validate_schema(name='import', obj=data, vo=vo)
40
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='import', kwargs=kwargs, session=session)
41
- if not auth_result.allowed:
42
- raise exception.AccessDenied('Account %s can not import data. %s' % (issuer, auth_result.message))
43
36
 
44
- for account in data.get('accounts', []):
45
- account['account'] = InternalAccount(account['account'], vo=vo)
46
- return importer.import_data(data, vo=vo, session=session)
37
+ with db_session(DatabaseOperationType.WRITE) as session:
38
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='import', kwargs=kwargs, session=session)
39
+ if not auth_result.allowed:
40
+ raise exception.AccessDenied('Account %s can not import data. %s' % (issuer, auth_result.message))
41
+
42
+ for account in data.get('accounts', []):
43
+ account['account'] = InternalAccount(account['account'], vo=vo)
44
+ return importer.import_data(data, vo=vo, session=session)
@@ -18,24 +18,20 @@ from rucio.common import exception
18
18
  from rucio.common.types import InternalAccount, InternalScope
19
19
  from rucio.common.utils import gateway_update_return_dict
20
20
  from rucio.core import lifetime_exception
21
- from rucio.db.sqla.session import stream_session, transactional_session
21
+ from rucio.db.sqla.constants import DatabaseOperationType
22
+ from rucio.db.sqla.session import db_session
22
23
  from rucio.gateway import permission
23
24
 
24
25
  if TYPE_CHECKING:
25
26
  from collections.abc import Iterable, Iterator
26
27
 
27
- from sqlalchemy.orm import Session
28
-
29
28
  from rucio.db.sqla.constants import LifetimeExceptionsState
30
29
 
31
30
 
32
- @stream_session
33
31
  def list_exceptions(
34
32
  exception_id: Optional[str] = None,
35
33
  states: Optional["Iterable[LifetimeExceptionsState]"] = None,
36
34
  vo: str = 'def',
37
- *,
38
- session: "Session"
39
35
  ) -> 'Iterator[dict[str, Any]]':
40
36
  """
41
37
  List exceptions to Lifetime Model.
@@ -43,16 +39,15 @@ def list_exceptions(
43
39
  :param id: The id of the exception
44
40
  :param states: The states to filter
45
41
  :param vo: The VO to act on
46
- :param session: The database session in use.
47
42
  """
48
43
 
49
- exceptions = lifetime_exception.list_exceptions(exception_id=exception_id, states=states, session=session)
50
- for e in exceptions:
51
- if vo == e['scope'].vo:
52
- yield gateway_update_return_dict(e, session=session)
44
+ with db_session(DatabaseOperationType.READ) as session:
45
+ exceptions = lifetime_exception.list_exceptions(exception_id=exception_id, states=states, session=session)
46
+ for e in exceptions:
47
+ if vo == e['scope'].vo:
48
+ yield gateway_update_return_dict(e, session=session)
53
49
 
54
50
 
55
- @transactional_session
56
51
  def add_exception(
57
52
  dids: "Iterable[dict[str, Any]]",
58
53
  account: str,
@@ -60,8 +55,6 @@ def add_exception(
60
55
  comments: str,
61
56
  expires_at: str,
62
57
  vo: str = 'def',
63
- *,
64
- session: "Session"
65
58
  ) -> dict[str, Any]:
66
59
  """
67
60
  Add exceptions to Lifetime Model.
@@ -72,7 +65,6 @@ def add_exception(
72
65
  :param comments: The comments associated to the exception.
73
66
  :param expires_at: The expiration date of the exception.
74
67
  :param vo: The VO to act on.
75
- :param session: The database session in use.
76
68
 
77
69
  returns: The id of the exception.
78
70
  """
@@ -80,7 +72,9 @@ def add_exception(
80
72
  internal_account = InternalAccount(account, vo=vo)
81
73
  for did in dids:
82
74
  did['scope'] = InternalScope(did['scope'], vo=vo)
83
- exceptions = lifetime_exception.add_exception(dids=dids, account=internal_account, pattern=pattern, comments=comments, expires_at=expires_at, session=session)
75
+
76
+ with db_session(DatabaseOperationType.WRITE) as session:
77
+ exceptions = lifetime_exception.add_exception(dids=dids, account=internal_account, pattern=pattern, comments=comments, expires_at=expires_at, session=session)
84
78
 
85
79
  for key in exceptions:
86
80
  if key == 'exceptions':
@@ -96,14 +90,11 @@ def add_exception(
96
90
  return exceptions
97
91
 
98
92
 
99
- @transactional_session
100
93
  def update_exception(
101
94
  exception_id: str,
102
95
  state: 'LifetimeExceptionsState',
103
96
  issuer: str,
104
97
  vo: str = 'def',
105
- *,
106
- session: "Session"
107
98
  ) -> None:
108
99
  """
109
100
  Update exceptions state to Lifetime Model.
@@ -112,10 +103,11 @@ def update_exception(
112
103
  :param state: The states to filter.
113
104
  :param issuer: The issuer account.
114
105
  :param vo: The VO to act on.
115
- :param session: The database session in use.
116
106
  """
117
107
  kwargs = {'exception_id': exception_id, 'vo': vo}
118
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='update_lifetime_exceptions', kwargs=kwargs, session=session)
119
- if not auth_result.allowed:
120
- raise exception.AccessDenied('Account %s can not update lifetime exceptions. %s' % (issuer, auth_result.message))
121
- return lifetime_exception.update_exception(exception_id=exception_id, state=state, session=session)
108
+
109
+ with db_session(DatabaseOperationType.WRITE) as session:
110
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='update_lifetime_exceptions', kwargs=kwargs, session=session)
111
+ if not auth_result.allowed:
112
+ raise exception.AccessDenied('Account %s can not update lifetime exceptions. %s' % (issuer, auth_result.message))
113
+ return lifetime_exception.update_exception(exception_id=exception_id, state=state, session=session)
rucio/gateway/lock.py CHANGED
@@ -19,26 +19,21 @@ from rucio.common.types import InternalScope
19
19
  from rucio.common.utils import gateway_update_return_dict
20
20
  from rucio.core import lock
21
21
  from rucio.core.rse import get_rse_id
22
- from rucio.db.sqla.constants import DIDType
23
- from rucio.db.sqla.session import stream_session
22
+ from rucio.db.sqla.constants import DatabaseOperationType, DIDType
23
+ from rucio.db.sqla.session import db_session
24
24
 
25
25
  if TYPE_CHECKING:
26
26
  from collections.abc import Iterable, Iterator
27
27
 
28
- from sqlalchemy.orm import Session
29
-
30
28
 
31
29
  LOGGER = logging.getLogger('lock')
32
30
  LOGGER.setLevel(logging.DEBUG)
33
31
 
34
32
 
35
- @stream_session
36
33
  def get_dataset_locks(
37
34
  scope: str,
38
35
  name: str,
39
36
  vo: str = 'def',
40
- *,
41
- session: "Session"
42
37
  ) -> 'Iterator[dict[str, Any]]':
43
38
  """
44
39
  Get the dataset locks of a dataset.
@@ -46,24 +41,21 @@ def get_dataset_locks(
46
41
  :param scope: Scope of the dataset.
47
42
  :param name: Name of the dataset.
48
43
  :param vo: The VO to act on.
49
- :param session: The database session in use.
50
44
  :return: List of dicts {'rse_id': ..., 'state': ...}
51
45
  """
52
46
 
53
47
  internal_scope = InternalScope(scope, vo=vo)
54
48
 
55
- locks = lock.get_dataset_locks(scope=internal_scope, name=name, session=session)
49
+ with db_session(DatabaseOperationType.READ) as session:
50
+ locks = lock.get_dataset_locks(scope=internal_scope, name=name, session=session)
56
51
 
57
- for lock_object in locks:
58
- yield gateway_update_return_dict(lock_object, session=session)
52
+ for lock_object in locks:
53
+ yield gateway_update_return_dict(lock_object, session=session)
59
54
 
60
55
 
61
- @stream_session
62
56
  def get_dataset_locks_bulk(
63
57
  dids: 'Iterable[dict[str, Any]]',
64
58
  vo: str = 'def',
65
- *,
66
- session: "Session"
67
59
  ) -> 'Iterator[dict[str, Any]]':
68
60
  """
69
61
  Get the dataset locks for multiple datasets or containers.
@@ -72,7 +64,6 @@ def get_dataset_locks_bulk(
72
64
  "type" is optional. If present, will be either DIDType.DATASET or DIDType.CONTAINER,
73
65
  or string "dataset" or "container"
74
66
  :param vo: The VO to act on.
75
- :param session: The database session in use.
76
67
  :return: Generator of dicts describing found locks {'rse_id': ..., 'state': ...}. Duplicates are removed
77
68
  """
78
69
 
@@ -96,58 +87,54 @@ def get_dataset_locks_bulk(
96
87
  dids_converted.append(did)
97
88
 
98
89
  seen = set()
99
- for lock_info in lock.get_dataset_locks_bulk(dids_converted, session=session):
100
- # filter duplicates - same scope, name, rse_id, rule_id
101
- scope_str = str(lock_info["scope"])
102
- key = (scope_str, lock_info["name"], lock_info["rse_id"], lock_info["rule_id"])
103
- if key not in seen:
104
- seen.add(key)
105
- yield lock_info
90
+
91
+ with db_session(DatabaseOperationType.READ) as session:
92
+ for lock_info in lock.get_dataset_locks_bulk(dids_converted, session=session):
93
+ # filter duplicates - same scope, name, rse_id, rule_id
94
+ scope_str = str(lock_info["scope"])
95
+ key = (scope_str, lock_info["name"], lock_info["rse_id"], lock_info["rule_id"])
96
+ if key not in seen:
97
+ seen.add(key)
98
+ yield lock_info
106
99
 
107
100
 
108
- @stream_session
109
101
  def get_dataset_locks_by_rse(
110
102
  rse: str,
111
103
  vo: str = 'def',
112
- *,
113
- session: "Session"
114
104
  ) -> 'Iterator[dict[str, Any]]':
115
105
  """
116
106
  Get the dataset locks of an RSE.
117
107
 
118
108
  :param rse: RSE name.
119
109
  :param vo: The VO to act on.
120
- :param session: The database session in use.
121
110
  :return: List of dicts {'rse_id': ..., 'state': ...}
122
111
  """
123
112
 
124
- rse_id = get_rse_id(rse=rse, vo=vo, session=session)
125
- locks = lock.get_dataset_locks_by_rse_id(rse_id=rse_id, session=session)
113
+ with db_session(DatabaseOperationType.READ) as session:
114
+ rse_id = get_rse_id(rse=rse, vo=vo, session=session)
115
+ locks = lock.get_dataset_locks_by_rse_id(rse_id=rse_id, session=session)
126
116
 
127
- for lock_object in locks:
128
- yield gateway_update_return_dict(lock_object, session=session)
117
+ for lock_object in locks:
118
+ yield gateway_update_return_dict(lock_object, session=session)
129
119
 
130
120
 
131
- @stream_session
132
121
  def get_replica_locks_for_rule_id(
133
122
  rule_id: str,
134
123
  vo: str = 'def',
135
- *,
136
- session: "Session"
137
124
  ) -> 'Iterator[dict[str, Any]]':
138
125
  """
139
126
  Get the replica locks for a rule_id.
140
127
 
141
128
  :param rule_id: Rule ID.
142
129
  :param vo: The VO to act on.
143
- :param session: The database session in use.
144
130
  :return: List of dicts.
145
131
  """
146
132
 
147
- locks = lock.get_replica_locks_for_rule_id(rule_id=rule_id, session=session)
133
+ with db_session(DatabaseOperationType.READ) as session:
134
+ locks = lock.get_replica_locks_for_rule_id(rule_id=rule_id, session=session)
148
135
 
149
- for lock_object in locks:
150
- if lock_object['scope'].vo != vo: # rule is on a different VO, so don't return any locks
151
- LOGGER.debug('rule id %s is not present on VO %s' % (rule_id, vo))
152
- break
153
- yield gateway_update_return_dict(lock_object, session=session)
136
+ for lock_object in locks:
137
+ if lock_object['scope'].vo != vo: # rule is on a different VO, so don't return any locks
138
+ LOGGER.debug('rule id %s is not present on VO %s' % (rule_id, vo))
139
+ break
140
+ yield gateway_update_return_dict(lock_object, session=session)
@@ -16,43 +16,37 @@ from typing import TYPE_CHECKING, Optional, Union
16
16
 
17
17
  from rucio.common.exception import AccessDenied
18
18
  from rucio.core import meta_conventions
19
- from rucio.db.sqla.session import read_session, transactional_session
19
+ from rucio.db.sqla.constants import DatabaseOperationType
20
+ from rucio.db.sqla.session import db_session
20
21
  from rucio.gateway.permission import has_permission
21
22
 
22
23
  if TYPE_CHECKING:
23
- from sqlalchemy.orm import Session
24
-
25
24
  from rucio.common.types import InternalAccount
26
25
  from rucio.db.sqla.constants import KeyType
27
26
 
28
27
 
29
- @read_session
30
- def list_keys(*, session: "Session") -> list[str]:
28
+ def list_keys() -> list[str]:
31
29
  """
32
30
  Lists all keys for DID Metadata Conventions.
33
31
 
34
- :param session: The database session in use.
35
-
36
32
  :returns: A list containing all keys.
37
33
  """
38
- return meta_conventions.list_keys(session=session)
34
+ with db_session(DatabaseOperationType.READ) as session:
35
+ return meta_conventions.list_keys(session=session)
39
36
 
40
37
 
41
- @read_session
42
- def list_values(key: str, *, session: "Session") -> list[str]:
38
+ def list_values(key: str) -> list[str]:
43
39
  """
44
40
  Lists all allowed values for a DID key (all values for a key in DID Metadata Conventions).
45
41
 
46
42
  :param key: the name for the key.
47
- :param session: The database session in use.
48
-
49
43
 
50
44
  :returns: A list containing all values.
51
45
  """
52
- return meta_conventions.list_values(key=key, session=session)
46
+ with db_session(DatabaseOperationType.READ) as session:
47
+ return meta_conventions.list_values(key=key, session=session)
53
48
 
54
49
 
55
- @transactional_session
56
50
  def add_key(
57
51
  key: str,
58
52
  key_type: Union["KeyType", str],
@@ -60,8 +54,6 @@ def add_key(
60
54
  value_type: Optional[str] = None,
61
55
  value_regexp: Optional[str] = None,
62
56
  vo: str = 'def',
63
- *,
64
- session: "Session"
65
57
  ) -> None:
66
58
  """
67
59
  Add an allowed key for DID metadata (update the DID Metadata Conventions table with a new key).
@@ -72,27 +64,26 @@ def add_key(
72
64
  :param value_type: the type of the value, if defined.
73
65
  :param value_regexp: the regular expression that values should match, if defined.
74
66
  :param vo: The vo to act on
75
- :param session: The database session in use.
76
67
  """
77
68
  kwargs = {'key': key, 'key_type': key_type, 'value_type': value_type, 'value_regexp': value_regexp}
78
- auth_result = has_permission(issuer=issuer, vo=vo, action='add_key', kwargs=kwargs, session=session)
79
- if not auth_result.allowed:
80
- raise AccessDenied('Account %s can not add key. %s' % (issuer, auth_result.message))
81
- return meta_conventions.add_key(key=key, key_type=key_type, value_type=value_type, value_regexp=value_regexp, session=session)
69
+ with db_session(DatabaseOperationType.WRITE) as session:
70
+ auth_result = has_permission(issuer=issuer, vo=vo, action='add_key', kwargs=kwargs, session=session)
71
+ if not auth_result.allowed:
72
+ raise AccessDenied('Account %s can not add key. %s' % (issuer, auth_result.message))
73
+ return meta_conventions.add_key(key=key, key_type=key_type, value_type=value_type, value_regexp=value_regexp, session=session)
82
74
 
83
75
 
84
- @transactional_session
85
- def add_value(key: str, value: str, issuer: "InternalAccount", vo: str = 'def', *, session: "Session") -> None:
76
+ def add_value(key: str, value: str, issuer: "InternalAccount", vo: str = 'def') -> None:
86
77
  """
87
78
  Add an allowed value for DID metadata (update a key in DID Metadata Conventions table).
88
79
 
89
80
  :param key: the name for the key.
90
81
  :param value: the value.
91
82
  :param vo: the vo to act on.
92
- :param session: The database session in use.
93
83
  """
94
84
  kwargs = {'key': key, 'value': value}
95
- auth_result = has_permission(issuer=issuer, vo=vo, action='add_value', kwargs=kwargs, session=session)
96
- if not auth_result.allowed:
97
- raise AccessDenied('Account %s can not add value %s to key %s. %s' % (issuer, value, key, auth_result.message))
98
- return meta_conventions.add_value(key=key, value=value, session=session)
85
+ with db_session(DatabaseOperationType.WRITE) as session:
86
+ auth_result = has_permission(issuer=issuer, vo=vo, action='add_value', kwargs=kwargs, session=session)
87
+ if not auth_result.allowed:
88
+ raise AccessDenied('Account %s can not add value %s to key %s. %s' % (issuer, value, key, auth_result.message))
89
+ return meta_conventions.add_value(key=key, value=value, session=session)