rucio 35.7.0__py3-none-any.whl → 37.0.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 (266) hide show
  1. rucio/alembicrevision.py +1 -1
  2. rucio/{daemons/c3po/collectors → cli}/__init__.py +1 -0
  3. rucio/cli/account.py +216 -0
  4. rucio-35.7.0.data/scripts/rucio → rucio/cli/bin_legacy/rucio.py +769 -486
  5. rucio-35.7.0.data/scripts/rucio-admin → rucio/cli/bin_legacy/rucio_admin.py +476 -423
  6. rucio/cli/command.py +272 -0
  7. rucio/cli/config.py +72 -0
  8. rucio/cli/did.py +191 -0
  9. rucio/cli/download.py +128 -0
  10. rucio/cli/lifetime_exception.py +33 -0
  11. rucio/cli/replica.py +162 -0
  12. rucio/cli/rse.py +293 -0
  13. rucio/cli/rule.py +158 -0
  14. rucio/cli/scope.py +40 -0
  15. rucio/cli/subscription.py +73 -0
  16. rucio/cli/upload.py +60 -0
  17. rucio/cli/utils.py +226 -0
  18. rucio/client/accountclient.py +0 -1
  19. rucio/client/baseclient.py +33 -24
  20. rucio/client/client.py +45 -1
  21. rucio/client/didclient.py +5 -3
  22. rucio/client/downloadclient.py +6 -8
  23. rucio/client/replicaclient.py +0 -2
  24. rucio/client/richclient.py +317 -0
  25. rucio/client/rseclient.py +4 -4
  26. rucio/client/uploadclient.py +26 -12
  27. rucio/common/bittorrent.py +234 -0
  28. rucio/common/cache.py +66 -29
  29. rucio/common/checksum.py +168 -0
  30. rucio/common/client.py +122 -0
  31. rucio/common/config.py +22 -35
  32. rucio/common/constants.py +61 -3
  33. rucio/common/didtype.py +72 -24
  34. rucio/common/dumper/__init__.py +45 -38
  35. rucio/common/dumper/consistency.py +75 -30
  36. rucio/common/dumper/data_models.py +63 -19
  37. rucio/common/dumper/path_parsing.py +19 -8
  38. rucio/common/exception.py +65 -8
  39. rucio/common/extra.py +5 -10
  40. rucio/common/logging.py +13 -13
  41. rucio/common/pcache.py +8 -7
  42. rucio/common/plugins.py +59 -27
  43. rucio/common/policy.py +12 -3
  44. rucio/common/schema/__init__.py +84 -34
  45. rucio/common/schema/generic.py +0 -17
  46. rucio/common/schema/generic_multi_vo.py +0 -17
  47. rucio/common/test_rucio_server.py +12 -6
  48. rucio/common/types.py +132 -52
  49. rucio/common/utils.py +93 -643
  50. rucio/core/account_limit.py +14 -12
  51. rucio/core/authentication.py +2 -2
  52. rucio/core/config.py +23 -42
  53. rucio/core/credential.py +14 -15
  54. rucio/core/did.py +5 -1
  55. rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
  56. rucio/core/did_meta_plugins/filter_engine.py +62 -3
  57. rucio/core/did_meta_plugins/json_meta.py +2 -2
  58. rucio/core/did_meta_plugins/mongo_meta.py +43 -30
  59. rucio/core/did_meta_plugins/postgres_meta.py +75 -39
  60. rucio/core/identity.py +6 -5
  61. rucio/core/importer.py +4 -3
  62. rucio/core/lifetime_exception.py +2 -2
  63. rucio/core/lock.py +8 -7
  64. rucio/core/message.py +6 -0
  65. rucio/core/monitor.py +30 -29
  66. rucio/core/naming_convention.py +2 -2
  67. rucio/core/nongrid_trace.py +2 -2
  68. rucio/core/oidc.py +11 -9
  69. rucio/core/permission/__init__.py +79 -37
  70. rucio/core/permission/generic.py +1 -7
  71. rucio/core/permission/generic_multi_vo.py +1 -7
  72. rucio/core/quarantined_replica.py +4 -3
  73. rucio/core/replica.py +464 -139
  74. rucio/core/replica_sorter.py +55 -59
  75. rucio/core/request.py +34 -32
  76. rucio/core/rse.py +301 -97
  77. rucio/core/rse_counter.py +1 -2
  78. rucio/core/rse_expression_parser.py +7 -7
  79. rucio/core/rse_selector.py +9 -7
  80. rucio/core/rule.py +41 -40
  81. rucio/core/rule_grouping.py +42 -40
  82. rucio/core/scope.py +5 -4
  83. rucio/core/subscription.py +26 -28
  84. rucio/core/topology.py +11 -11
  85. rucio/core/trace.py +2 -2
  86. rucio/core/transfer.py +29 -15
  87. rucio/core/volatile_replica.py +4 -3
  88. rucio/daemons/atropos/atropos.py +1 -1
  89. rucio/daemons/auditor/__init__.py +2 -2
  90. rucio/daemons/auditor/srmdumps.py +6 -6
  91. rucio/daemons/automatix/automatix.py +32 -21
  92. rucio/daemons/badreplicas/necromancer.py +2 -2
  93. rucio/daemons/bb8/nuclei_background_rebalance.py +1 -1
  94. rucio/daemons/bb8/t2_background_rebalance.py +1 -1
  95. rucio/daemons/common.py +15 -25
  96. rucio/daemons/conveyor/finisher.py +2 -2
  97. rucio/daemons/conveyor/poller.py +18 -28
  98. rucio/daemons/conveyor/receiver.py +2 -2
  99. rucio/daemons/conveyor/stager.py +1 -0
  100. rucio/daemons/conveyor/submitter.py +3 -3
  101. rucio/daemons/hermes/hermes.py +91 -30
  102. rucio/daemons/judge/evaluator.py +2 -2
  103. rucio/daemons/oauthmanager/oauthmanager.py +3 -3
  104. rucio/daemons/reaper/dark_reaper.py +7 -3
  105. rucio/daemons/reaper/reaper.py +12 -16
  106. rucio/daemons/rsedecommissioner/config.py +1 -1
  107. rucio/daemons/rsedecommissioner/profiles/generic.py +5 -4
  108. rucio/daemons/rsedecommissioner/profiles/types.py +7 -6
  109. rucio/daemons/rsedecommissioner/rse_decommissioner.py +1 -1
  110. rucio/daemons/storage/consistency/actions.py +8 -6
  111. rucio/daemons/tracer/kronos.py +4 -4
  112. rucio/db/sqla/constants.py +5 -0
  113. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +4 -4
  114. rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
  115. rucio/db/sqla/models.py +157 -154
  116. rucio/db/sqla/session.py +58 -27
  117. rucio/db/sqla/types.py +2 -2
  118. rucio/db/sqla/util.py +2 -2
  119. rucio/gateway/account.py +18 -12
  120. rucio/gateway/account_limit.py +137 -60
  121. rucio/gateway/authentication.py +18 -12
  122. rucio/gateway/config.py +30 -20
  123. rucio/gateway/credential.py +9 -10
  124. rucio/gateway/did.py +70 -53
  125. rucio/gateway/dirac.py +6 -4
  126. rucio/gateway/exporter.py +3 -2
  127. rucio/gateway/heartbeat.py +6 -4
  128. rucio/gateway/identity.py +36 -51
  129. rucio/gateway/importer.py +3 -2
  130. rucio/gateway/lifetime_exception.py +3 -2
  131. rucio/gateway/meta_conventions.py +17 -6
  132. rucio/gateway/permission.py +4 -1
  133. rucio/gateway/quarantined_replica.py +3 -2
  134. rucio/gateway/replica.py +31 -22
  135. rucio/gateway/request.py +27 -18
  136. rucio/gateway/rse.py +69 -37
  137. rucio/gateway/rule.py +46 -26
  138. rucio/gateway/scope.py +3 -2
  139. rucio/gateway/subscription.py +14 -11
  140. rucio/gateway/vo.py +12 -8
  141. rucio/rse/__init__.py +3 -3
  142. rucio/rse/protocols/bittorrent.py +11 -1
  143. rucio/rse/protocols/cache.py +0 -11
  144. rucio/rse/protocols/dummy.py +0 -11
  145. rucio/rse/protocols/gfal.py +14 -9
  146. rucio/rse/protocols/globus.py +1 -1
  147. rucio/rse/protocols/http_cache.py +1 -1
  148. rucio/rse/protocols/posix.py +2 -2
  149. rucio/rse/protocols/protocol.py +84 -317
  150. rucio/rse/protocols/rclone.py +2 -1
  151. rucio/rse/protocols/rfio.py +10 -1
  152. rucio/rse/protocols/ssh.py +2 -1
  153. rucio/rse/protocols/storm.py +2 -13
  154. rucio/rse/protocols/webdav.py +74 -30
  155. rucio/rse/protocols/xrootd.py +2 -1
  156. rucio/rse/rsemanager.py +170 -53
  157. rucio/rse/translation.py +260 -0
  158. rucio/tests/common.py +23 -13
  159. rucio/tests/common_server.py +26 -9
  160. rucio/transfertool/bittorrent.py +15 -14
  161. rucio/transfertool/bittorrent_driver.py +5 -7
  162. rucio/transfertool/bittorrent_driver_qbittorrent.py +9 -8
  163. rucio/transfertool/fts3.py +20 -16
  164. rucio/transfertool/mock.py +2 -3
  165. rucio/vcsversion.py +4 -4
  166. rucio/version.py +7 -0
  167. rucio/web/rest/flaskapi/v1/accounts.py +17 -3
  168. rucio/web/rest/flaskapi/v1/auth.py +5 -5
  169. rucio/web/rest/flaskapi/v1/credentials.py +3 -2
  170. rucio/web/rest/flaskapi/v1/dids.py +21 -15
  171. rucio/web/rest/flaskapi/v1/identities.py +33 -9
  172. rucio/web/rest/flaskapi/v1/redirect.py +5 -4
  173. rucio/web/rest/flaskapi/v1/replicas.py +12 -8
  174. rucio/web/rest/flaskapi/v1/rses.py +15 -4
  175. rucio/web/rest/flaskapi/v1/traces.py +56 -19
  176. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/alembic.ini.template +1 -1
  177. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/alembic_offline.ini.template +1 -1
  178. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +3 -2
  179. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio.cfg.template +3 -19
  180. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +1 -18
  181. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/requirements.server.txt +97 -68
  182. rucio-37.0.0.data/scripts/rucio +133 -0
  183. rucio-37.0.0.data/scripts/rucio-admin +97 -0
  184. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-atropos +2 -2
  185. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-auditor +2 -1
  186. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-automatix +2 -2
  187. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-cache-client +17 -10
  188. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-receiver +1 -0
  189. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-kronos +1 -0
  190. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-minos +2 -2
  191. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-minos-temporary-expiration +2 -2
  192. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-necromancer +2 -2
  193. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-reaper +6 -6
  194. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-transmogrifier +2 -2
  195. rucio-37.0.0.dist-info/METADATA +92 -0
  196. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/RECORD +237 -243
  197. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/licenses/AUTHORS.rst +3 -0
  198. rucio/common/schema/atlas.py +0 -413
  199. rucio/common/schema/belleii.py +0 -408
  200. rucio/common/schema/domatpc.py +0 -401
  201. rucio/common/schema/escape.py +0 -426
  202. rucio/common/schema/icecube.py +0 -406
  203. rucio/core/permission/atlas.py +0 -1348
  204. rucio/core/permission/belleii.py +0 -1077
  205. rucio/core/permission/escape.py +0 -1078
  206. rucio/daemons/c3po/algorithms/__init__.py +0 -13
  207. rucio/daemons/c3po/algorithms/simple.py +0 -134
  208. rucio/daemons/c3po/algorithms/t2_free_space.py +0 -128
  209. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +0 -130
  210. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +0 -294
  211. rucio/daemons/c3po/c3po.py +0 -371
  212. rucio/daemons/c3po/collectors/agis.py +0 -108
  213. rucio/daemons/c3po/collectors/free_space.py +0 -81
  214. rucio/daemons/c3po/collectors/jedi_did.py +0 -57
  215. rucio/daemons/c3po/collectors/mock_did.py +0 -51
  216. rucio/daemons/c3po/collectors/network_metrics.py +0 -71
  217. rucio/daemons/c3po/collectors/workload.py +0 -112
  218. rucio/daemons/c3po/utils/__init__.py +0 -13
  219. rucio/daemons/c3po/utils/dataset_cache.py +0 -50
  220. rucio/daemons/c3po/utils/expiring_dataset_cache.py +0 -56
  221. rucio/daemons/c3po/utils/expiring_list.py +0 -62
  222. rucio/daemons/c3po/utils/popularity.py +0 -85
  223. rucio/daemons/c3po/utils/timeseries.py +0 -89
  224. rucio/rse/protocols/gsiftp.py +0 -92
  225. rucio-35.7.0.data/scripts/rucio-c3po +0 -85
  226. rucio-35.7.0.dist-info/METADATA +0 -72
  227. /rucio/{daemons/c3po → cli/bin_legacy}/__init__.py +0 -0
  228. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
  229. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
  230. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  231. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  232. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  233. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  234. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  235. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  236. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  237. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/bootstrap.py +0 -0
  238. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
  239. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/reset_database.py +0 -0
  240. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-account +0 -0
  241. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-collection-replica +0 -0
  242. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-rse +0 -0
  243. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-bb8 +0 -0
  244. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-cache-consumer +0 -0
  245. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-finisher +0 -0
  246. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-poller +0 -0
  247. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-preparer +0 -0
  248. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-stager +0 -0
  249. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-submitter +0 -0
  250. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-throttler +0 -0
  251. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-dark-reaper +0 -0
  252. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-dumper +0 -0
  253. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-follower +0 -0
  254. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-hermes +0 -0
  255. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-cleaner +0 -0
  256. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-evaluator +0 -0
  257. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-injector +0 -0
  258. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-repairer +0 -0
  259. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-oauth-manager +0 -0
  260. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-replica-recoverer +0 -0
  261. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-rse-decommissioner +0 -0
  262. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-storage-consistency-actions +0 -0
  263. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-undertaker +0 -0
  264. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/WHEEL +0 -0
  265. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/licenses/LICENSE +0 -0
  266. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/top_level.txt +0 -0
rucio/db/sqla/session.py CHANGED
@@ -16,6 +16,7 @@ import copy
16
16
  import logging
17
17
  import os
18
18
  import sys
19
+ from contextlib import contextmanager
19
20
  from datetime import datetime, timedelta
20
21
  from functools import update_wrapper
21
22
  from inspect import getfullargspec, isgeneratorfunction
@@ -33,11 +34,12 @@ from rucio.common.config import config_get
33
34
  from rucio.common.exception import DatabaseException, InputValidationError, RucioException
34
35
  from rucio.common.extra import import_extras
35
36
  from rucio.common.utils import retrying
37
+ from rucio.db.sqla.constants import DatabaseOperationType
36
38
 
37
39
  EXTRA_MODULES = import_extras(['MySQLdb', 'pymysql'])
38
40
 
39
41
  if TYPE_CHECKING:
40
- from collections.abc import Callable
42
+ from collections.abc import Callable, Iterator
41
43
  from typing import Optional, ParamSpec, TypeVar
42
44
 
43
45
  from pymysql import Connection as MySQLConnection
@@ -49,7 +51,6 @@ if TYPE_CHECKING:
49
51
  R = TypeVar('R')
50
52
  CallableTypeVar = TypeVar('CallableTypeVar', bound='Callable[..., Any]')
51
53
 
52
-
53
54
  try:
54
55
  main_script = os.path.basename(sys.argv[0])
55
56
  CURRENT_COMPONENT = main_script.split('-')[1]
@@ -71,6 +72,13 @@ _METADATA = MetaData(schema=DEFAULT_SCHEMA_NAME)
71
72
  _MAKER, _ENGINE, _LOCK = None, None, Lock()
72
73
 
73
74
 
75
+ SQLA_CONFIG_POOLCLASS_MAPPING = {
76
+ 'queuepool': QueuePool,
77
+ 'singletonthreadpool': SingletonThreadPool,
78
+ 'nullpool': NullPool,
79
+ }
80
+
81
+
74
82
  class BASE(DeclarativeBase):
75
83
  metadata = _METADATA
76
84
 
@@ -151,22 +159,20 @@ def mysql_convert_decimal_to_float(
151
159
 
152
160
  def psql_convert_decimal_to_float(dbapi_conn, connection_rec) -> None:
153
161
  """
154
- The default datatype returned by psycopg2 for numerics is decimal.Decimal.
155
- This type cannot be serialised to JSON, therefore we need to autoconvert to floats.
162
+ Configure the PostgreSQL connection to return numeric types as float instead of Decimal.
163
+ Psycopg3 provides this functionality through type adapters.
156
164
 
157
165
  :param dbapi_conn: DBAPI connection
158
166
  :param connection_rec: connection record
159
167
  """
160
-
161
168
  try:
162
- import psycopg2.extensions # pylint: disable=import-error
163
- except:
164
- raise RucioException('Trying to use PostgreSQL without psycopg2 or psycopg2-binary installed!')
165
-
166
- DEC2FLOAT = psycopg2.extensions.new_type(psycopg2.extensions.DECIMAL.values,
167
- 'DEC2FLOAT',
168
- lambda value, curs: float(value) if value is not None else None)
169
- psycopg2.extensions.register_type(DEC2FLOAT)
169
+ import psycopg
170
+ # Register a global loader that converts numeric types to float
171
+ dbapi_conn.adapters.register_loader("numeric", psycopg.types.numeric.FloatLoader)
172
+ except ImportError:
173
+ raise RucioException('Trying to use PostgreSQL without psycopg installed!')
174
+ except Exception as error:
175
+ raise RucioException(f'Error setting up PostgreSQL Decimal to Float conversion: {str(error)}')
170
176
 
171
177
 
172
178
  def my_on_connect(dbapi_con, connection_record) -> None:
@@ -189,12 +195,6 @@ def _get_engine_poolclass(poolclass: str) -> Pool:
189
195
  :raises InputValidationError: if config value doesn't correspond to an SQLAlchemy Pool class.
190
196
  """
191
197
 
192
- SQLA_CONFIG_POOLCLASS_MAPPING = {
193
- 'queuepool': QueuePool,
194
- 'singletonthreadpool': SingletonThreadPool,
195
- 'nullpool': NullPool,
196
- }
197
-
198
198
  poolclass = poolclass.lower()
199
199
 
200
200
  if poolclass not in SQLA_CONFIG_POOLCLASS_MAPPING:
@@ -204,7 +204,7 @@ def _get_engine_poolclass(poolclass: str) -> Pool:
204
204
 
205
205
 
206
206
  def get_engine() -> 'Engine':
207
- """ Creates a engine to a specific database.
207
+ """ Creates an engine to a specific database.
208
208
  :returns: engine
209
209
  """
210
210
  global _ENGINE
@@ -223,9 +223,7 @@ def get_engine() -> 'Engine':
223
223
  params[param] = param_type(config_get(DATABASE_SECTION, param, check_config_table=False))
224
224
  except:
225
225
  pass
226
- # Using sqlAlchemy 2.0 with future=True.
227
- # if backing up from 2.0, need to remove future=True .
228
- _ENGINE = create_engine(sql_connection, future=True, **params)
226
+ _ENGINE = create_engine(sql_connection, **params)
229
227
  if 'mysql' in sql_connection:
230
228
  event.listen(_ENGINE, 'checkout', mysql_ping_listener)
231
229
  elif 'postgresql' in sql_connection:
@@ -261,6 +259,7 @@ def get_dump_engine(
261
259
  print(statement.replace(')', ');\n'))
262
260
  else:
263
261
  print(statement)
262
+
264
263
  sql_connection = config_get(DATABASE_SECTION, 'default', check_config_table=False)
265
264
 
266
265
  engine = create_engine(sql_connection, echo=echo, strategy='mock', executor=dump)
@@ -276,8 +275,7 @@ def get_maker() -> sessionmaker:
276
275
  if not _ENGINE:
277
276
  raise RuntimeError("Could not form database engine.")
278
277
  if not _MAKER:
279
- # turn on sqlAlchemy 2.0 with future=True.
280
- _MAKER = sessionmaker(bind=_ENGINE, autocommit=False, autoflush=True, expire_on_commit=True, future=True)
278
+ _MAKER = sessionmaker(bind=_ENGINE, autocommit=False, autoflush=True, expire_on_commit=True)
281
279
  return _MAKER
282
280
 
283
281
 
@@ -387,12 +385,14 @@ def read_session(function: "Callable[P, R]"):
387
385
  This is useful if only SELECTs and the like are being done; anything involving
388
386
  INSERTs, UPDATEs etc should use transactional_session.
389
387
  '''
388
+
390
389
  @retrying(retry_on_exception=retry_if_db_connection_error,
391
390
  wait_fixed=500,
392
391
  stop_max_attempt_number=2)
393
392
  def new_funct(*args: "P.args", session: "Optional[Session]" = None, **kwargs): # pylint:disable=missing-kwoa
394
393
  if isgeneratorfunction(function):
395
- raise RucioException('read_session decorator should not be used with generator. Use stream_session instead.')
394
+ raise RucioException(
395
+ 'read_session decorator should not be used with generator. Use stream_session instead.')
396
396
 
397
397
  if not session:
398
398
  session_scoped = get_session()
@@ -415,6 +415,7 @@ def read_session(function: "Callable[P, R]"):
415
415
  return function(*args, session=session, **kwargs)
416
416
  except Exception:
417
417
  raise
418
+
418
419
  return _update_session_wrapper(new_funct, function)
419
420
 
420
421
 
@@ -427,13 +428,15 @@ def stream_session(function: "Callable[P, R]"):
427
428
  This is useful if only SELECTs and the like are being done; anything involving
428
429
  INSERTs, UPDATEs etc should use transactional_session.
429
430
  '''
431
+
430
432
  @retrying(retry_on_exception=retry_if_db_connection_error,
431
433
  wait_fixed=500,
432
434
  stop_max_attempt_number=2)
433
435
  def new_funct(*args: "P.args", session: "Optional[Session]" = None, **kwargs): # pylint:disable=missing-kwoa
434
436
 
435
437
  if not isgeneratorfunction(function):
436
- raise RucioException('stream_session decorator should be used only with generator. Use read_session instead.')
438
+ raise RucioException(
439
+ 'stream_session decorator should be used only with generator. Use read_session instead.')
437
440
 
438
441
  if not session:
439
442
  session_scoped = get_session()
@@ -469,6 +472,7 @@ def transactional_session(function: "Callable[P, R]") -> 'Callable':
469
472
 
470
473
  session is a sqlalchemy session, and you can get one calling get_session().
471
474
  '''
475
+
472
476
  def new_funct(
473
477
  *args: "P.args",
474
478
  session: "Optional[Session]" = None,
@@ -495,4 +499,31 @@ def transactional_session(function: "Callable[P, R]") -> 'Callable':
495
499
  else:
496
500
  result = function(*args, session=session, **kwargs)
497
501
  return result
502
+
498
503
  return _update_session_wrapper(new_funct, function)
504
+
505
+
506
+ @retrying(retry_on_exception=retry_if_db_connection_error,
507
+ wait_fixed=500,
508
+ stop_max_attempt_number=2)
509
+ @contextmanager
510
+ def db_session(operation: DatabaseOperationType) -> "Iterator[Session]":
511
+ session_scoped = get_session()
512
+ session = session_scoped()
513
+ session.begin()
514
+
515
+ try:
516
+ yield session
517
+ if operation is DatabaseOperationType.WRITE:
518
+ session.commit()
519
+ except TimeoutError as error:
520
+ session.rollback()
521
+ raise DatabaseException(str(error))
522
+ except DatabaseError as error:
523
+ session.rollback()
524
+ raise DatabaseException(str(error))
525
+ except Exception:
526
+ session.rollback()
527
+ raise
528
+ finally:
529
+ session_scoped.remove()
rucio/db/sqla/types.py CHANGED
@@ -164,7 +164,7 @@ class InternalAccountString(TypeDecorator):
164
164
  def process_result_value(self, value, dialect):
165
165
  if value is None:
166
166
  return value
167
- return InternalAccount(value, fromExternal=False)
167
+ return InternalAccount(value, from_external=False)
168
168
 
169
169
  def coerce_compared_value(self, op, value):
170
170
  if op in (operators.like_op, operators.notlike_op):
@@ -197,7 +197,7 @@ class InternalScopeString(TypeDecorator):
197
197
  def process_result_value(self, value, dialect):
198
198
  if value is None:
199
199
  return value
200
- return InternalScope(value, fromExternal=False)
200
+ return InternalScope(value, from_external=False)
201
201
 
202
202
  def coerce_compared_value(self, op, value):
203
203
  if op in (operators.like_op, operators.notlike_op):
rucio/db/sqla/util.py CHANGED
@@ -31,7 +31,7 @@ from sqlalchemy.sql.ddl import DropSchema
31
31
  from sqlalchemy.sql.expression import select, text
32
32
 
33
33
  from rucio import alembicrevision
34
- from rucio.common.cache import make_region_memcached
34
+ from rucio.common.cache import MemcacheRegion
35
35
  from rucio.common.config import config_get, config_get_list
36
36
  from rucio.common.schema import get_schema_value
37
37
  from rucio.common.types import InternalAccount, LoggerFunction
@@ -50,7 +50,7 @@ if TYPE_CHECKING:
50
50
  # TypeVar representing the DeclarativeObj class defined inside _create_temp_table
51
51
  DeclarativeObj = TypeVar('DeclarativeObj')
52
52
 
53
- REGION = make_region_memcached(expiration_time=600, memcached_expire_time=3660)
53
+ REGION = MemcacheRegion(expiration_time=600, memcached_expire_time=3660)
54
54
 
55
55
 
56
56
  def build_database() -> None:
rucio/gateway/account.py CHANGED
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from collections.abc import Iterator
16
15
  from typing import TYPE_CHECKING, Any, Optional
17
16
 
18
17
  import rucio.common.exception
@@ -27,6 +26,8 @@ from rucio.db.sqla.constants import AccountType
27
26
  from rucio.db.sqla.session import read_session, stream_session, transactional_session
28
27
 
29
28
  if TYPE_CHECKING:
29
+ from collections.abc import Iterator
30
+
30
31
  from sqlalchemy.orm import Session
31
32
 
32
33
  from rucio.common.types import AccountAttributesDict, IdentityDict, UsageDict
@@ -59,8 +60,9 @@ def add_account(
59
60
  validate_schema(name='account', obj=account, vo=vo)
60
61
 
61
62
  kwargs = {'account': account, 'type': type_}
62
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='add_account', kwargs=kwargs, session=session):
63
- raise rucio.common.exception.AccessDenied('Account %s can not add account' % (issuer))
63
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='add_account', kwargs=kwargs, session=session)
64
+ if not auth_result.allowed:
65
+ raise rucio.common.exception.AccessDenied('Account %s can not add account. %s' % (issuer, auth_result.message))
64
66
 
65
67
  internal_account = InternalAccount(account, vo=vo)
66
68
 
@@ -85,8 +87,9 @@ def del_account(
85
87
 
86
88
  """
87
89
  kwargs = {'account': account}
88
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='del_account', kwargs=kwargs, session=session):
89
- raise rucio.common.exception.AccessDenied('Account %s can not delete account' % (issuer))
90
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='del_account', kwargs=kwargs, session=session)
91
+ if not auth_result.allowed:
92
+ raise rucio.common.exception.AccessDenied('Account %s can not delete account. %s' % (issuer, auth_result.message))
90
93
 
91
94
  internal_account = InternalAccount(account, vo=vo)
92
95
 
@@ -137,8 +140,9 @@ def update_account(
137
140
  """
138
141
  validate_schema(name='account', obj=account, vo=vo)
139
142
  kwargs = {}
140
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='update_account', kwargs=kwargs, session=session):
141
- raise rucio.common.exception.AccessDenied('Account %s can not change %s of the account' % (issuer, key))
143
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='update_account', kwargs=kwargs, session=session)
144
+ if not auth_result.allowed:
145
+ raise rucio.common.exception.AccessDenied('Account %s can not change %s of the account. %s' % (issuer, key, auth_result.message))
142
146
 
143
147
  internal_account = InternalAccount(account, vo=vo)
144
148
 
@@ -146,7 +150,7 @@ def update_account(
146
150
 
147
151
 
148
152
  @stream_session
149
- def list_accounts(filter_: Optional[dict[str, Any]] = None, vo: str = 'def', *, session: "Session") -> Iterator[dict[str, Any]]:
153
+ def list_accounts(filter_: Optional[dict[str, Any]] = None, vo: str = 'def', *, session: "Session") -> 'Iterator[dict[str, Any]]':
150
154
  """
151
155
  Lists all the Rucio account names.
152
156
 
@@ -254,8 +258,9 @@ def add_account_attribute(
254
258
  validate_schema(name='account_attribute', obj=value, vo=vo)
255
259
 
256
260
  kwargs = {'account': account, 'key': key, 'value': value}
257
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='add_attribute', kwargs=kwargs, session=session):
258
- raise rucio.common.exception.AccessDenied('Account %s can not add attributes' % (issuer))
261
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='add_attribute', kwargs=kwargs, session=session)
262
+ if not auth_result.allowed:
263
+ raise rucio.common.exception.AccessDenied('Account %s can not add attributes. %s' % (issuer, auth_result.message))
259
264
 
260
265
  internal_account = InternalAccount(account, vo=vo)
261
266
 
@@ -281,8 +286,9 @@ def del_account_attribute(
281
286
  :param session: The database session in use.
282
287
  """
283
288
  kwargs = {'account': account, 'key': key}
284
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='del_attribute', kwargs=kwargs, session=session):
285
- raise rucio.common.exception.AccessDenied('Account %s can not delete attribute' % (issuer))
289
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='del_attribute', kwargs=kwargs, session=session)
290
+ if not auth_result.allowed:
291
+ raise rucio.common.exception.AccessDenied('Account %s can not delete attribute. %s' % (issuer, auth_result.message))
286
292
 
287
293
  internal_account = InternalAccount(account, vo=vo)
288
294
 
@@ -12,11 +12,11 @@
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
15
+ from typing import TYPE_CHECKING, Any, Union
16
16
 
17
17
  import rucio.common.exception
18
18
  import rucio.gateway.permission
19
- from rucio.common.types import InternalAccount
19
+ from rucio.common.types import InternalAccount, RSEResolvedGlobalAccountLimitDict
20
20
  from rucio.common.utils import gateway_update_return_dict
21
21
  from rucio.core import account_limit as account_limit_core
22
22
  from rucio.core.account import account_exists
@@ -28,7 +28,12 @@ if TYPE_CHECKING:
28
28
 
29
29
 
30
30
  @read_session
31
- def get_rse_account_usage(rse, vo='def', *, session: "Session"):
31
+ def get_rse_account_usage(
32
+ rse: str,
33
+ vo: str = 'def',
34
+ *,
35
+ session: "Session"
36
+ ) -> list[dict[str, Any]]:
32
37
  """
33
38
  Returns the account limit and usage for all for all accounts on a RSE.
34
39
 
@@ -43,7 +48,12 @@ def get_rse_account_usage(rse, vo='def', *, session: "Session"):
43
48
 
44
49
 
45
50
  @read_session
46
- def get_local_account_limits(account, vo='def', *, session: "Session"):
51
+ def get_local_account_limits(
52
+ account: str,
53
+ vo: str = 'def',
54
+ *,
55
+ session: "Session"
56
+ ) -> dict[str, Any]:
47
57
  """
48
58
  Lists the limitation names/values for the specified account name.
49
59
 
@@ -56,16 +66,22 @@ def get_local_account_limits(account, vo='def', *, session: "Session"):
56
66
  :returns: The account limits.
57
67
  """
58
68
 
59
- account = InternalAccount(account, vo=vo)
69
+ internal_account = InternalAccount(account, vo=vo)
60
70
 
61
71
  rse_instead_id = {}
62
- for elem in account_limit_core.get_local_account_limits(account=account, session=session).items():
72
+ for elem in account_limit_core.get_local_account_limits(account=internal_account, session=session).items():
63
73
  rse_instead_id[get_rse_name(rse_id=elem[0], session=session)] = elem[1]
64
74
  return rse_instead_id
65
75
 
66
76
 
67
77
  @read_session
68
- def get_local_account_limit(account, rse, vo='def', *, session: "Session"):
78
+ def get_local_account_limit(
79
+ account: str,
80
+ rse: str,
81
+ vo: str = 'def',
82
+ *,
83
+ session: "Session"
84
+ ) -> dict[str, Union[int, float, None]]:
69
85
  """
70
86
  Lists the limitation names/values for the specified account name and rse name.
71
87
 
@@ -79,14 +95,19 @@ def get_local_account_limit(account, rse, vo='def', *, session: "Session"):
79
95
  :returns: The account limit.
80
96
  """
81
97
 
82
- account = InternalAccount(account, vo=vo)
98
+ internal_account = InternalAccount(account, vo=vo)
83
99
 
84
100
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
85
- return {rse: account_limit_core.get_local_account_limit(account=account, rse_id=rse_id, session=session)}
101
+ return {rse: account_limit_core.get_local_account_limit(account=internal_account, rse_id=rse_id, session=session)}
86
102
 
87
103
 
88
104
  @read_session
89
- def get_global_account_limits(account, vo='def', *, session: "Session"):
105
+ def get_global_account_limits(
106
+ account: str,
107
+ vo: str = 'def',
108
+ *,
109
+ session: "Session"
110
+ ) -> dict[str, RSEResolvedGlobalAccountLimitDict]:
90
111
  """
91
112
  Lists the limitation names/values for the specified account name.
92
113
 
@@ -99,15 +120,21 @@ def get_global_account_limits(account, vo='def', *, session: "Session"):
99
120
  :returns: The account limits.
100
121
  """
101
122
  if account:
102
- account = InternalAccount(account, vo=vo)
123
+ internal_account = InternalAccount(account, vo=vo)
103
124
  else:
104
- account = InternalAccount('*', vo=vo)
125
+ internal_account = InternalAccount('*', vo=vo)
105
126
 
106
- return account_limit_core.get_global_account_limits(account=account, session=session)
127
+ return account_limit_core.get_global_account_limits(account=internal_account, session=session)
107
128
 
108
129
 
109
130
  @read_session
110
- def get_global_account_limit(account, rse_expression, vo='def', *, session: "Session"):
131
+ def get_global_account_limit(
132
+ account: str,
133
+ rse_expression: str,
134
+ vo: str = 'def',
135
+ *,
136
+ session: "Session"
137
+ ) -> dict[str, dict[str, RSEResolvedGlobalAccountLimitDict]]:
111
138
  """
112
139
  Lists the limitation names/values for the specified account name and rse expression.
113
140
 
@@ -121,15 +148,23 @@ def get_global_account_limit(account, rse_expression, vo='def', *, session: "Ses
121
148
  :returns: The account limit.
122
149
  """
123
150
 
124
- account = InternalAccount(account, vo=vo)
151
+ internal_account = InternalAccount(account, vo=vo)
125
152
 
126
- return {rse_expression: account_limit_core.get_global_account_limit(account=account, rse_expression=rse_expression, session=session)}
153
+ return {rse_expression: account_limit_core.get_global_account_limit(account=internal_account, rse_expression=rse_expression, session=session)}
127
154
 
128
155
 
129
156
  @transactional_session
130
- def set_local_account_limit(account, rse, bytes_, issuer, vo='def', *, session: "Session"):
157
+ def set_local_account_limit(
158
+ account: str,
159
+ rse: str,
160
+ bytes_: int,
161
+ issuer: str,
162
+ vo: str = 'def',
163
+ *,
164
+ session: "Session"
165
+ ) -> None:
131
166
  """
132
- Set an account limit..
167
+ Set an account limit.
133
168
 
134
169
  :param account: The account name.
135
170
  :param rse: The rse name.
@@ -141,19 +176,28 @@ def set_local_account_limit(account, rse, bytes_, issuer, vo='def', *, session:
141
176
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
142
177
 
143
178
  kwargs = {'account': account, 'rse': rse, 'rse_id': rse_id, 'bytes': bytes_}
144
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='set_local_account_limit', kwargs=kwargs, session=session):
145
- raise rucio.common.exception.AccessDenied('Account %s can not set account limits.' % (issuer))
179
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='set_local_account_limit', kwargs=kwargs, session=session)
180
+ if not auth_result.allowed:
181
+ raise rucio.common.exception.AccessDenied('Account %s can not set account limits. %s' % (issuer, auth_result.message))
146
182
 
147
- account = InternalAccount(account, vo=vo)
183
+ internal_account = InternalAccount(account, vo=vo)
148
184
 
149
- if not account_exists(account=account, session=session):
150
- raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (account))
185
+ if not account_exists(account=internal_account, session=session):
186
+ raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (internal_account))
151
187
 
152
- account_limit_core.set_local_account_limit(account=account, rse_id=rse_id, bytes_=bytes_, session=session)
188
+ account_limit_core.set_local_account_limit(account=internal_account, rse_id=rse_id, bytes_=bytes_, session=session)
153
189
 
154
190
 
155
191
  @transactional_session
156
- def set_global_account_limit(account, rse_expression, bytes_, issuer, vo='def', *, session: "Session"):
192
+ def set_global_account_limit(
193
+ account: str,
194
+ rse_expression: str,
195
+ bytes_: int,
196
+ issuer: str,
197
+ vo: str = 'def',
198
+ *,
199
+ session: "Session"
200
+ ) -> None:
157
201
  """
158
202
  Set a global account limit.
159
203
 
@@ -166,21 +210,29 @@ def set_global_account_limit(account, rse_expression, bytes_, issuer, vo='def',
166
210
  """
167
211
 
168
212
  kwargs = {'account': account, 'rse_expression': rse_expression, 'bytes': bytes_}
169
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='set_global_account_limit', kwargs=kwargs, session=session):
170
- raise rucio.common.exception.AccessDenied('Account %s can not set account limits.' % (issuer))
213
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='set_global_account_limit', kwargs=kwargs, session=session)
214
+ if not auth_result.allowed:
215
+ raise rucio.common.exception.AccessDenied('Account %s can not set account limits. %s' % (issuer, auth_result.message))
171
216
 
172
- account = InternalAccount(account, vo=vo)
217
+ internal_account = InternalAccount(account, vo=vo)
173
218
 
174
- if not account_exists(account=account, session=session):
175
- raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (account))
219
+ if not account_exists(account=internal_account, session=session):
220
+ raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (internal_account))
176
221
 
177
- account_limit_core.set_global_account_limit(account=account, rse_expression=rse_expression, bytes_=bytes_, session=session)
222
+ account_limit_core.set_global_account_limit(account=internal_account, rse_expression=rse_expression, bytes_=bytes_, session=session)
178
223
 
179
224
 
180
225
  @transactional_session
181
- def delete_local_account_limit(account, rse, issuer, vo='def', *, session: "Session"):
226
+ def delete_local_account_limit(
227
+ account: str,
228
+ rse: str,
229
+ issuer: str,
230
+ vo: str = 'def',
231
+ *,
232
+ session: "Session"
233
+ ) -> bool:
182
234
  """
183
- Delete an account limit..
235
+ Delete an account limit.
184
236
 
185
237
  :param account: The account name.
186
238
  :param rse: The rse name.
@@ -193,19 +245,27 @@ def delete_local_account_limit(account, rse, issuer, vo='def', *, session: "Sess
193
245
 
194
246
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
195
247
  kwargs = {'account': account, 'rse': rse, 'rse_id': rse_id}
196
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='delete_local_account_limit', kwargs=kwargs, session=session):
197
- raise rucio.common.exception.AccessDenied('Account %s can not delete account limits.' % (issuer))
248
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='delete_local_account_limit', kwargs=kwargs, session=session)
249
+ if not auth_result.allowed:
250
+ raise rucio.common.exception.AccessDenied('Account %s can not delete account limits. %s' % (issuer, auth_result.message))
198
251
 
199
- account = InternalAccount(account, vo=vo)
252
+ internal_account = InternalAccount(account, vo=vo)
200
253
 
201
- if not account_exists(account=account, session=session):
202
- raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (account))
254
+ if not account_exists(account=internal_account, session=session):
255
+ raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (internal_account))
203
256
 
204
- return account_limit_core.delete_local_account_limit(account=account, rse_id=rse_id, session=session)
257
+ return account_limit_core.delete_local_account_limit(account=internal_account, rse_id=rse_id, session=session)
205
258
 
206
259
 
207
260
  @transactional_session
208
- def delete_global_account_limit(account, rse_expression, issuer, vo='def', *, session: "Session"):
261
+ def delete_global_account_limit(
262
+ account: str,
263
+ rse_expression: str,
264
+ issuer: str,
265
+ vo: str = 'def',
266
+ *,
267
+ session: "Session"
268
+ ) -> bool:
209
269
  """
210
270
  Delete a global account limit..
211
271
 
@@ -219,19 +279,27 @@ def delete_global_account_limit(account, rse_expression, issuer, vo='def', *, se
219
279
  """
220
280
 
221
281
  kwargs = {'account': account, 'rse_expression': rse_expression}
222
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='delete_global_account_limit', kwargs=kwargs, session=session):
223
- raise rucio.common.exception.AccessDenied('Account %s can not delete global account limits.' % (issuer))
282
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='delete_global_account_limit', kwargs=kwargs, session=session)
283
+ if not auth_result.allowed:
284
+ raise rucio.common.exception.AccessDenied('Account %s can not delete global account limits. %s' % (issuer, auth_result.message))
224
285
 
225
- account = InternalAccount(account, vo=vo)
286
+ internal_account = InternalAccount(account, vo=vo)
226
287
 
227
- if not account_exists(account=account, session=session):
228
- raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (account))
288
+ if not account_exists(account=internal_account, session=session):
289
+ raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (internal_account))
229
290
 
230
- return account_limit_core.delete_global_account_limit(account=account, rse_expression=rse_expression, session=session)
291
+ return account_limit_core.delete_global_account_limit(account=internal_account, rse_expression=rse_expression, session=session)
231
292
 
232
293
 
233
294
  @read_session
234
- def get_local_account_usage(account, rse, issuer, vo='def', *, session: "Session"):
295
+ def get_local_account_usage(
296
+ account: str,
297
+ rse: str,
298
+ issuer: str,
299
+ vo: str = 'def',
300
+ *,
301
+ session: "Session"
302
+ ) -> list[dict[str, Any]]:
235
303
  """
236
304
  Get the account usage and connect it with (if available) the account limits of the account.
237
305
 
@@ -249,19 +317,27 @@ def get_local_account_usage(account, rse, issuer, vo='def', *, session: "Session
249
317
  if rse:
250
318
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
251
319
  kwargs = {'account': account, 'rse': rse, 'rse_id': rse_id}
252
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='get_local_account_usage', kwargs=kwargs, session=session):
253
- raise rucio.common.exception.AccessDenied('Account %s can not list account usage.' % (issuer))
320
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='get_local_account_usage', kwargs=kwargs, session=session)
321
+ if not auth_result.allowed:
322
+ raise rucio.common.exception.AccessDenied('Account %s can not list account usage. %s' % (issuer, auth_result.message))
254
323
 
255
- account = InternalAccount(account, vo=vo)
324
+ internal_account = InternalAccount(account, vo=vo)
256
325
 
257
- if not account_exists(account=account, session=session):
258
- raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (account))
326
+ if not account_exists(account=internal_account, session=session):
327
+ raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (internal_account))
259
328
 
260
- return [gateway_update_return_dict(d, session=session) for d in account_limit_core.get_local_account_usage(account=account, rse_id=rse_id, session=session)]
329
+ return [gateway_update_return_dict(d, session=session) for d in account_limit_core.get_local_account_usage(account=internal_account, rse_id=rse_id, session=session)]
261
330
 
262
331
 
263
332
  @read_session
264
- def get_global_account_usage(account, rse_expression, issuer, vo='def', *, session: "Session"):
333
+ def get_global_account_usage(
334
+ account: str,
335
+ rse_expression: str,
336
+ issuer: str,
337
+ vo: str = 'def',
338
+ *,
339
+ session: "Session"
340
+ ) -> list[dict[str, Any]]:
265
341
  """
266
342
  Get the account usage and connect it with (if available) the account limits of the account.
267
343
 
@@ -275,12 +351,13 @@ def get_global_account_usage(account, rse_expression, issuer, vo='def', *, sessi
275
351
  """
276
352
 
277
353
  kwargs = {'account': account, 'rse_expression': rse_expression}
278
- if not rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='get_global_account_usage', kwargs=kwargs, session=session):
279
- raise rucio.common.exception.AccessDenied('Account %s can not list global account usage.' % (issuer))
354
+ auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='get_global_account_usage', kwargs=kwargs, session=session)
355
+ if not auth_result.allowed:
356
+ raise rucio.common.exception.AccessDenied('Account %s can not list global account usage. %s' % (issuer, auth_result.message))
280
357
 
281
- account = InternalAccount(account, vo=vo)
358
+ internal_account = InternalAccount(account, vo=vo)
282
359
 
283
- if not account_exists(account=account, session=session):
284
- raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (account))
360
+ if not account_exists(account=internal_account, session=session):
361
+ raise rucio.common.exception.AccountNotFound('Account %s does not exist' % (internal_account))
285
362
 
286
- return [gateway_update_return_dict(d, session=session) for d in account_limit_core.get_global_account_usage(account=account, rse_expression=rse_expression, session=session)]
363
+ return [gateway_update_return_dict(d, session=session) for d in account_limit_core.get_global_account_usage(account=internal_account, rse_expression=rse_expression, session=session)]