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/gateway/exporter.py CHANGED
@@ -35,8 +35,9 @@ def export_data(issuer: str, distance: bool = True, vo: str = 'def', *, session:
35
35
  :param session: The database session in use.
36
36
  """
37
37
  kwargs = {'issuer': issuer}
38
- if not permission.has_permission(issuer=issuer, vo=vo, action='export', kwargs=kwargs, session=session):
39
- raise exception.AccessDenied('Account %s can not export data' % 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))
40
41
 
41
42
  data = exporter.export_data(distance=distance, vo=vo, session=session)
42
43
  rses = {}
@@ -37,8 +37,9 @@ def list_heartbeats(issuer: Optional[str] = None, vo: str = 'def', *, session: "
37
37
  """
38
38
 
39
39
  kwargs = {'issuer': issuer}
40
- if not permission.has_permission(issuer=issuer, vo=vo, action='list_heartbeats', kwargs=kwargs, session=session):
41
- raise exception.AccessDenied('%s cannot list heartbeats' % 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))
42
43
  return heartbeat.list_heartbeats(session=session)
43
44
 
44
45
 
@@ -69,6 +70,7 @@ def create_heartbeat(
69
70
 
70
71
  """
71
72
  kwargs = {'issuer': issuer}
72
- if not permission.has_permission(issuer=issuer, vo=vo, action='send_heartbeats', kwargs=kwargs, session=session):
73
- raise exception.AccessDenied('%s cannot send heartbeats' % 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))
74
76
  heartbeat.live(executable=executable, hostname=hostname, pid=pid, thread=thread, older_than=older_than, payload=payload, session=session)
rucio/gateway/identity.py CHANGED
@@ -21,25 +21,21 @@ from typing import TYPE_CHECKING, Optional
21
21
  from rucio.common import exception
22
22
  from rucio.common.types import InternalAccount
23
23
  from rucio.core import identity
24
- from rucio.db.sqla.constants import IdentityType
25
- from rucio.db.sqla.session import read_session, transactional_session
24
+ from rucio.db.sqla.constants import DatabaseOperationType, IdentityType
25
+ from rucio.db.sqla.session import db_session
26
26
  from rucio.gateway import permission
27
27
 
28
28
  if TYPE_CHECKING:
29
29
  from collections.abc import Sequence
30
30
 
31
31
  from sqlalchemy import Row
32
- from sqlalchemy.orm import Session
33
32
 
34
33
 
35
- @transactional_session
36
34
  def add_identity(
37
35
  identity_key: str,
38
36
  id_type: str,
39
37
  email: str,
40
38
  password: Optional[str] = None,
41
- *,
42
- session: "Session"
43
39
  ) -> None:
44
40
  """
45
41
  Creates a user identity.
@@ -48,19 +44,16 @@ def add_identity(
48
44
  :param id_type: The type of the authentication (x509, gss, userpass, ssh, saml)
49
45
  :param email: The Email address associated with the identity.
50
46
  :param password: If type==userpass, this sets the password.
51
- :param session: The database session in use.
52
47
  """
53
- return identity.add_identity(identity_key, IdentityType[id_type.upper()], email, password=password, session=session)
48
+ with db_session(DatabaseOperationType.WRITE) as session:
49
+ return identity.add_identity(identity_key, IdentityType[id_type.upper()], email, password=password, session=session)
54
50
 
55
51
 
56
- @transactional_session
57
52
  def del_identity(
58
53
  identity_key: str,
59
54
  id_type: str,
60
55
  issuer: str,
61
56
  vo: str = 'def',
62
- *,
63
- session: "Session"
64
57
  ) -> None:
65
58
  """
66
59
  Deletes a user identity.
@@ -68,17 +61,18 @@ def del_identity(
68
61
  :param id_type: The type of the authentication (x509, gss, userpass, ssh, saml).
69
62
  :param issuer: The issuer account.
70
63
  :param vo: the VO of the issuer.
71
- :param session: The database session in use.
72
64
  """
73
65
  converted_id_type = IdentityType[id_type.upper()]
74
- kwargs = {'accounts': identity.list_accounts_for_identity(identity_key, converted_id_type, session=session)}
75
- if not permission.has_permission(issuer=issuer, vo=vo, action='del_identity', kwargs=kwargs, session=session):
76
- raise exception.AccessDenied('Account %s can not delete identity' % (issuer))
77
66
 
78
- return identity.del_identity(identity_key, converted_id_type, session=session)
67
+ with db_session(DatabaseOperationType.WRITE) as session:
68
+ kwargs = {'accounts': identity.list_accounts_for_identity(identity_key, converted_id_type, session=session)}
69
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='del_identity', kwargs=kwargs, session=session)
70
+ if not auth_result.allowed:
71
+ raise exception.AccessDenied('Account %s can not delete identity. %s' % (issuer, auth_result.message))
72
+
73
+ return identity.del_identity(identity_key, converted_id_type, session=session)
79
74
 
80
75
 
81
- @transactional_session
82
76
  def add_account_identity(
83
77
  identity_key: str,
84
78
  id_type: str,
@@ -88,8 +82,6 @@ def add_account_identity(
88
82
  default: bool = False,
89
83
  password: Optional[str] = None,
90
84
  vo: str = 'def',
91
- *,
92
- session: "Session"
93
85
  ) -> None:
94
86
  """
95
87
  Adds a membership association between identity and account.
@@ -102,39 +94,37 @@ def add_account_identity(
102
94
  :param default: If True, the account should be used by default with the provided identity.
103
95
  :param password: Password if id_type is userpass.
104
96
  :param vo: the VO to act on.
105
- :param session: The database session in use.
106
97
  """
107
98
  kwargs = {'identity': identity_key, 'type': id_type, 'account': account}
108
- if not permission.has_permission(issuer=issuer, vo=vo, action='add_account_identity', kwargs=kwargs, session=session):
109
- raise exception.AccessDenied('Account %s can not add account identity' % (issuer))
110
99
 
111
- internal_account = InternalAccount(account, vo=vo)
100
+ with db_session(DatabaseOperationType.WRITE) as session:
101
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='add_account_identity', kwargs=kwargs, session=session)
102
+ if not auth_result.allowed:
103
+ raise exception.AccessDenied('Account %s can not add account identity. %s' % (issuer, auth_result.message))
104
+
105
+ internal_account = InternalAccount(account, vo=vo)
112
106
 
113
- return identity.add_account_identity(identity=identity_key, type_=IdentityType[id_type.upper()], default=default,
114
- email=email, account=internal_account, password=password, session=session)
107
+ return identity.add_account_identity(identity=identity_key, type_=IdentityType[id_type.upper()], default=default,
108
+ email=email, account=internal_account, password=password, session=session)
115
109
 
116
110
 
117
- @read_session
118
- def verify_identity(identity_key: str, id_type: str, password: Optional[str] = None, *, session: "Session") -> bool:
111
+ def verify_identity(identity_key: str, id_type: str, password: Optional[str] = None) -> bool:
119
112
  """
120
113
  Verifies a user identity.
121
114
  :param identity_key: The identity key name. For example x509 DN, or a username.
122
115
  :param id_type: The type of the authentication (x509, gss, userpass, ssh, saml)
123
116
  :param password: If type==userpass, verifies the identity_key, .
124
- :param session: The database session in use.
125
117
  """
126
- return identity.verify_identity(identity_key, IdentityType[id_type.upper()], password=password, session=session)
118
+ with db_session(DatabaseOperationType.READ) as session:
119
+ return identity.verify_identity(identity_key, IdentityType[id_type.upper()], password=password, session=session)
127
120
 
128
121
 
129
- @transactional_session
130
122
  def del_account_identity(
131
123
  identity_key: str,
132
124
  id_type: str,
133
125
  account: str,
134
126
  issuer: str,
135
127
  vo: str = 'def',
136
- *,
137
- session: "Session"
138
128
  ) -> None:
139
129
  """
140
130
  Removes a membership association between identity and account.
@@ -144,61 +134,56 @@ def del_account_identity(
144
134
  :param account: The account name.
145
135
  :param issuer: The issuer account.
146
136
  :param vo: the VO to act on.
147
- :param session: The database session in use.
148
137
  """
149
138
  kwargs = {'account': account}
150
- if not permission.has_permission(issuer=issuer, vo=vo, action='del_account_identity', kwargs=kwargs, session=session):
151
- raise exception.AccessDenied('Account %s can not delete account identity' % (issuer))
152
139
 
153
- internal_account = InternalAccount(account, vo=vo)
140
+ with db_session(DatabaseOperationType.WRITE) as session:
141
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='del_account_identity', kwargs=kwargs, session=session)
142
+ if not auth_result.allowed:
143
+ raise exception.AccessDenied('Account %s can not delete account identity. %s' % (issuer, auth_result.message))
144
+
145
+ internal_account = InternalAccount(account, vo=vo)
154
146
 
155
- return identity.del_account_identity(identity_key, IdentityType[id_type.upper()], internal_account, session=session)
147
+ return identity.del_account_identity(identity_key, IdentityType[id_type.upper()], internal_account, session=session)
156
148
 
157
149
 
158
- @read_session
159
- def list_identities(*, session: "Session", **kwargs) -> "Sequence[Row[tuple[str, IdentityType]]]":
150
+ def list_identities(**kwargs) -> "Sequence[Row[tuple[str, IdentityType]]]":
160
151
  """
161
152
  Returns a list of all enabled identities.
162
153
 
163
- :param session: The database session in use.
164
154
  returns: A list of all enabled identities.
165
155
  """
166
- return identity.list_identities(session=session, **kwargs)
156
+ with db_session(DatabaseOperationType.READ) as session:
157
+ return identity.list_identities(session=session, **kwargs)
167
158
 
168
159
 
169
- @read_session
170
160
  def get_default_account(
171
161
  identity_key: str,
172
162
  id_type: str,
173
- *,
174
- session: "Session"
175
163
  ) -> str:
176
164
  """
177
165
  Returns the default account for this identity.
178
166
 
179
167
  :param identity_key: The identity key name. For example x509 DN, or a username.
180
168
  :param id_type: The type of the authentication (x509, gss, userpass, ssh, saml).
181
- :param session: The database session in use.
182
169
  """
183
- account = identity.get_default_account(identity_key, IdentityType[id_type.upper()], session=session)
170
+ with db_session(DatabaseOperationType.READ) as session:
171
+ account = identity.get_default_account(identity_key, IdentityType[id_type.upper()], session=session)
184
172
  return account.external
185
173
 
186
174
 
187
- @read_session
188
175
  def list_accounts_for_identity(
189
176
  identity_key: str,
190
177
  id_type: str,
191
- *,
192
- session: "Session"
193
178
  ) -> list[str]:
194
179
  """
195
180
  Returns a list of all accounts for an identity.
196
181
 
197
182
  :param identity: The identity key name. For example x509 DN, or a username.
198
183
  :param id_type: The type of the authentication (x509, gss, userpass, ssh, saml).
199
- :param session: The database session in use.
200
184
 
201
185
  returns: A list of all accounts for the identity.
202
186
  """
203
- accounts = identity.list_accounts_for_identity(identity_key, IdentityType[id_type.upper()], session=session)
187
+ with db_session(DatabaseOperationType.READ) as session:
188
+ accounts = identity.list_accounts_for_identity(identity_key, IdentityType[id_type.upper()], session=session)
204
189
  return [account.external for account in accounts]
rucio/gateway/importer.py CHANGED
@@ -37,8 +37,9 @@ def import_data(data: dict[str, Any], issuer: str, vo: str = 'def', *, session:
37
37
  """
38
38
  kwargs = {'issuer': issuer}
39
39
  validate_schema(name='import', obj=data, vo=vo)
40
- if not permission.has_permission(issuer=issuer, vo=vo, action='import', kwargs=kwargs, session=session):
41
- raise exception.AccessDenied('Account %s can not import data' % issuer)
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))
42
43
 
43
44
  for account in data.get('accounts', []):
44
45
  account['account'] = InternalAccount(account['account'], vo=vo)
@@ -115,6 +115,7 @@ def update_exception(
115
115
  :param session: The database session in use.
116
116
  """
117
117
  kwargs = {'exception_id': exception_id, 'vo': vo}
118
- if not permission.has_permission(issuer=issuer, vo=vo, action='update_lifetime_exceptions', kwargs=kwargs, session=session):
119
- raise exception.AccessDenied('Account %s can not update lifetime exceptions' % (issuer))
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))
120
121
  return lifetime_exception.update_exception(exception_id=exception_id, state=state, session=session)
@@ -16,7 +16,6 @@ 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.constants import KeyType
20
19
  from rucio.db.sqla.session import read_session, transactional_session
21
20
  from rucio.gateway.permission import has_permission
22
21
 
@@ -24,6 +23,7 @@ if TYPE_CHECKING:
24
23
  from sqlalchemy.orm import Session
25
24
 
26
25
  from rucio.common.types import InternalAccount
26
+ from rucio.db.sqla.constants import KeyType
27
27
 
28
28
 
29
29
  @read_session
@@ -53,7 +53,16 @@ def list_values(key: str, *, session: "Session") -> list[str]:
53
53
 
54
54
 
55
55
  @transactional_session
56
- def add_key(key: str, key_type: Union[KeyType, str], issuer: "InternalAccount", value_type: Optional[str] = None, value_regexp: Optional[str] = None, vo: str = 'def', *, session: "Session") -> None:
56
+ def add_key(
57
+ key: str,
58
+ key_type: Union["KeyType", str],
59
+ issuer: "InternalAccount",
60
+ value_type: Optional[str] = None,
61
+ value_regexp: Optional[str] = None,
62
+ vo: str = 'def',
63
+ *,
64
+ session: "Session"
65
+ ) -> None:
57
66
  """
58
67
  Add an allowed key for DID metadata (update the DID Metadata Conventions table with a new key).
59
68
 
@@ -66,8 +75,9 @@ def add_key(key: str, key_type: Union[KeyType, str], issuer: "InternalAccount",
66
75
  :param session: The database session in use.
67
76
  """
68
77
  kwargs = {'key': key, 'key_type': key_type, 'value_type': value_type, 'value_regexp': value_regexp}
69
- if not has_permission(issuer=issuer, vo=vo, action='add_key', kwargs=kwargs, session=session):
70
- raise AccessDenied('Account %s can not add key' % (issuer))
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))
71
81
  return meta_conventions.add_key(key=key, key_type=key_type, value_type=value_type, value_regexp=value_regexp, session=session)
72
82
 
73
83
 
@@ -82,6 +92,7 @@ def add_value(key: str, value: str, issuer: "InternalAccount", vo: str = 'def',
82
92
  :param session: The database session in use.
83
93
  """
84
94
  kwargs = {'key': key, 'value': value}
85
- if not has_permission(issuer=issuer, vo=vo, action='add_value', kwargs=kwargs, session=session):
86
- raise AccessDenied('Account %s can not add value %s to key %s' % (issuer, value, key))
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))
87
98
  return meta_conventions.add_value(key=key, value=value, session=session)
@@ -24,9 +24,11 @@ from rucio.db.sqla.session import read_session
24
24
  if TYPE_CHECKING:
25
25
  from sqlalchemy.orm import Session
26
26
 
27
+ from rucio.core.permission import PermissionResult
28
+
27
29
 
28
30
  @read_session
29
- def has_permission(issuer: str, action: str, kwargs: dict[str, Any], vo: str = 'def', *, session: "Session") -> bool:
31
+ def has_permission(issuer: str, action: str, kwargs: dict[str, Any], vo: str = 'def', *, session: "Session") -> 'PermissionResult':
30
32
  """
31
33
  Checks if an account has the specified permission to
32
34
  execute an action with parameters.
@@ -62,6 +64,7 @@ def has_permission(issuer: str, action: str, kwargs: dict[str, Any], vo: str = '
62
64
  r['account'] = InternalAccount(r['account'], vo=vo)
63
65
  if 'dids' in kwargs:
64
66
  for d in kwargs['dids']:
67
+ d['scope'] = InternalScope(d['scope'], vo=vo)
65
68
  if 'rules' in d:
66
69
  for r in d['rules']:
67
70
  r['account'] = InternalAccount(r['account'], vo=vo)
@@ -57,8 +57,9 @@ def quarantine_file_replicas(
57
57
  if rse_id is None:
58
58
  rse_id = get_rse_id(rse, vo=vo, session=session)
59
59
 
60
- if not permission.has_permission(issuer, 'quarantine_file_replicas', {}, vo=vo, session=session):
61
- raise exception.AccessDenied('Account %s can not quarantine replicas' % (issuer))
60
+ auth_result = permission.has_permission(issuer, 'quarantine_file_replicas', {}, vo=vo, session=session)
61
+ if not auth_result.allowed:
62
+ raise exception.AccessDenied('Account %s can not quarantine replicas. %s' % (issuer, auth_result.message))
62
63
 
63
64
  replica_infos = []
64
65
  for r in replicas:
rucio/gateway/replica.py CHANGED
@@ -13,7 +13,6 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import datetime
16
- from collections.abc import Iterator
17
16
  from typing import TYPE_CHECKING, Any, Optional
18
17
 
19
18
  from rucio.common import exception
@@ -28,6 +27,8 @@ from rucio.db.sqla.session import read_session, stream_session, transactional_se
28
27
  from rucio.gateway import permission
29
28
 
30
29
  if TYPE_CHECKING:
30
+ from collections.abc import Iterator
31
+
31
32
  from sqlalchemy.orm import Session
32
33
 
33
34
 
@@ -119,11 +120,12 @@ def declare_bad_file_replicas(replicas, reason, issuer, vo='def', force=False, *
119
120
  rse_id_to_name = invert_dict(rse_map) # RSE id -> RSE name
120
121
 
121
122
  for rse_id in rse_ids_to_check:
122
- if not permission.has_permission(issuer=issuer, vo=vo, action='declare_bad_file_replicas',
123
- kwargs={"rse_id": rse_id},
124
- session=session):
125
- raise exception.AccessDenied('Account %s can not declare bad replicas in RSE %s' %
126
- (issuer, rse_id_to_name.get(rse_id, rse_id)))
123
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='declare_bad_file_replicas',
124
+ kwargs={"rse_id": rse_id},
125
+ session=session)
126
+ if not auth_result.allowed:
127
+ raise exception.AccessDenied('Account %s can not declare bad replicas in RSE %s. %s' %
128
+ (issuer, rse_id_to_name.get(rse_id, rse_id), auth_result.message))
127
129
 
128
130
  undeclared = replica.declare_bad_file_replicas(replicas_lst, reason=reason,
129
131
  issuer=InternalAccount(issuer, vo=vo),
@@ -159,8 +161,9 @@ def declare_suspicious_file_replicas(pfns, reason, issuer, vo='def', *, session:
159
161
  :param session: The database session in use.
160
162
  """
161
163
  kwargs = {}
162
- if not permission.has_permission(issuer=issuer, vo=vo, action='declare_suspicious_file_replicas', kwargs=kwargs, session=session):
163
- raise exception.AccessDenied('Account %s can not declare suspicious replicas' % (issuer))
164
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='declare_suspicious_file_replicas', kwargs=kwargs, session=session)
165
+ if not auth_result.allowed:
166
+ raise exception.AccessDenied('Account %s can not declare suspicious replicas. %s' % (issuer, auth_result.message))
164
167
 
165
168
  issuer = InternalAccount(issuer, vo=vo)
166
169
 
@@ -248,7 +251,7 @@ def list_replicas(dids, schemes=None, unavailable=False, request_id=None,
248
251
  new_parents = []
249
252
  for p in rep['parents']:
250
253
  scope, name = p.split(':')
251
- scope = InternalScope(scope, fromExternal=False).external
254
+ scope = InternalScope(scope, from_external=False).external
252
255
  new_parents.append('{}:{}'.format(scope, name))
253
256
  rep['parents'] = new_parents
254
257
 
@@ -276,8 +279,9 @@ def add_replicas(rse, files, issuer, ignore_availability=False, vo='def', *, ses
276
279
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
277
280
 
278
281
  kwargs = {'rse': rse, 'rse_id': rse_id}
279
- if not permission.has_permission(issuer=issuer, vo=vo, action='add_replicas', kwargs=kwargs, session=session):
280
- raise exception.AccessDenied('Account %s can not add file replicas on %s' % (issuer, rse))
282
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='add_replicas', kwargs=kwargs, session=session)
283
+ if not auth_result.allowed:
284
+ raise exception.AccessDenied('Account %s can not add file replicas on %s. %s' % (issuer, rse, auth_result.message))
281
285
  if not permission.has_permission(issuer=issuer, vo=vo, action='skip_availability_check', kwargs=kwargs, session=session):
282
286
  ignore_availability = False
283
287
 
@@ -309,8 +313,9 @@ def delete_replicas(rse, files, issuer, ignore_availability=False, vo='def', *,
309
313
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
310
314
 
311
315
  kwargs = {'rse': rse, 'rse_id': rse_id}
312
- if not permission.has_permission(issuer=issuer, vo=vo, action='delete_replicas', kwargs=kwargs, session=session):
313
- raise exception.AccessDenied('Account %s can not delete file replicas on %s' % (issuer, rse))
316
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='delete_replicas', kwargs=kwargs, session=session)
317
+ if not auth_result.allowed:
318
+ raise exception.AccessDenied('Account %s can not delete file replicas on %s. %s' % (issuer, rse, auth_result.message))
314
319
  if not permission.has_permission(issuer=issuer, vo=vo, action='skip_availability_check', kwargs=kwargs, session=session):
315
320
  ignore_availability = False
316
321
 
@@ -338,8 +343,9 @@ def update_replicas_states(rse, files, issuer, vo='def', *, session: "Session"):
338
343
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
339
344
 
340
345
  kwargs = {'rse': rse, 'rse_id': rse_id}
341
- if not permission.has_permission(issuer=issuer, vo=vo, action='update_replicas_states', kwargs=kwargs, session=session):
342
- raise exception.AccessDenied('Account %s can not update file replicas state on %s' % (issuer, rse))
346
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='update_replicas_states', kwargs=kwargs, session=session)
347
+ if not auth_result.allowed:
348
+ raise exception.AccessDenied('Account %s can not update file replicas state on %s. %s' % (issuer, rse, auth_result.message))
343
349
  replicas = []
344
350
  for file in files:
345
351
  rep = file
@@ -419,7 +425,7 @@ def list_dataset_replicas_vp(scope, name, deep=False, vo='def', *, session: "Ses
419
425
 
420
426
 
421
427
  @stream_session
422
- def list_datasets_per_rse(rse: str, filters: Optional[dict[str, Any]] = None, limit: Optional[int] = None, vo: str = 'def', *, session: "Session") -> Iterator[dict[str, Any]]:
428
+ def list_datasets_per_rse(rse: str, filters: Optional[dict[str, Any]] = None, limit: Optional[int] = None, vo: str = 'def', *, session: "Session") -> 'Iterator[dict[str, Any]]':
423
429
  """
424
430
  :param scope: The scope of the dataset.
425
431
  :param name: The name of the dataset.
@@ -455,8 +461,9 @@ def add_bad_pfns(pfns, issuer, state, reason=None, expires_at=None, vo='def', *,
455
461
  :returns: True is successful.
456
462
  """
457
463
  kwargs = {'state': state}
458
- if not permission.has_permission(issuer=issuer, vo=vo, action='add_bad_pfns', kwargs=kwargs, session=session):
459
- raise exception.AccessDenied('Account %s can not declare bad PFNs' % (issuer))
464
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='add_bad_pfns', kwargs=kwargs, session=session)
465
+ if not auth_result.allowed:
466
+ raise exception.AccessDenied('Account %s can not declare bad PFNs. %s' % (issuer, auth_result.message))
460
467
 
461
468
  if expires_at and datetime.datetime.utcnow() <= expires_at and expires_at > datetime.datetime.utcnow() + datetime.timedelta(days=30):
462
469
  raise exception.InputValidationError('The given duration of %s days exceeds the maximum duration of 30 days.' % (expires_at - datetime.datetime.utcnow()).days)
@@ -483,8 +490,9 @@ def add_bad_dids(dids, rse, issuer, state, reason=None, expires_at=None, vo='def
483
490
  :returns: The list of replicas not declared bad
484
491
  """
485
492
  kwargs = {'state': state}
486
- if not permission.has_permission(issuer=issuer, vo=vo, action='add_bad_pfns', kwargs=kwargs, session=session):
487
- raise exception.AccessDenied('Account %s can not declare bad PFN or DIDs' % issuer)
493
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='add_bad_pfns', kwargs=kwargs, session=session)
494
+ if not auth_result.allowed:
495
+ raise exception.AccessDenied('Account %s can not declare bad PFN or DIDs. %s' % (issuer, auth_result.message))
488
496
 
489
497
  issuer = InternalAccount(issuer, vo=vo)
490
498
  rse_id = get_rse_id(rse=rse, session=session)
@@ -522,8 +530,9 @@ def set_tombstone(rse, scope, name, issuer, vo='def', *, session: "Session"):
522
530
 
523
531
  rse_id = get_rse_id(rse, vo=vo, session=session)
524
532
 
525
- if not permission.has_permission(issuer=issuer, vo=vo, action='set_tombstone', kwargs={}, session=session):
526
- raise exception.AccessDenied('Account %s can not set tombstones' % (issuer))
533
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='set_tombstone', kwargs={}, session=session)
534
+ if not auth_result.allowed:
535
+ raise exception.AccessDenied('Account %s can not set tombstones. %s' % (issuer, auth_result.message))
527
536
 
528
537
  scope = InternalScope(scope, vo=vo)
529
538
  replica.set_tombstone(rse_id, scope, name, session=session)
rucio/gateway/request.py CHANGED
@@ -53,8 +53,9 @@ def queue_requests(
53
53
  """
54
54
 
55
55
  kwargs = {'requests': requests, 'issuer': issuer}
56
- if not permission.has_permission(issuer=issuer, vo=vo, action='queue_requests', kwargs=kwargs, session=session):
57
- raise exception.AccessDenied(f'{issuer} can not queue request')
56
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='queue_requests', kwargs=kwargs, session=session)
57
+ if not auth_result.allowed:
58
+ raise exception.AccessDenied(f'{issuer} can not queue request. {auth_result.message}')
58
59
 
59
60
  for req in requests:
60
61
  req['scope'] = InternalScope(req['scope'], vo=vo) # type: ignore (type reassignment)
@@ -85,8 +86,9 @@ def cancel_request(
85
86
  """
86
87
 
87
88
  kwargs = {'account': account, 'issuer': issuer, 'request_id': request_id}
88
- if not permission.has_permission(issuer=issuer, vo=vo, action='cancel_request_', kwargs=kwargs, session=session):
89
- raise exception.AccessDenied('%s cannot cancel request %s' % (account, request_id))
89
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='cancel_request_', kwargs=kwargs, session=session)
90
+ if not auth_result.allowed:
91
+ raise exception.AccessDenied('%s cannot cancel request %s. %s' % (account, request_id, auth_result.message))
90
92
 
91
93
  raise NotImplementedError
92
94
 
@@ -119,8 +121,9 @@ def cancel_request_did(
119
121
  dest_rse_id = get_rse_id(rse=dest_rse, vo=vo, session=session)
120
122
 
121
123
  kwargs = {'account': account, 'issuer': issuer}
122
- if not permission.has_permission(issuer=issuer, vo=vo, action='cancel_request_did', kwargs=kwargs, session=session):
123
- raise exception.AccessDenied(f'{account} cannot cancel {request_type} request for {scope}:{name}')
124
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='cancel_request_did', kwargs=kwargs, session=session)
125
+ if not auth_result.allowed:
126
+ raise exception.AccessDenied(f'{account} cannot cancel {request_type} request for {scope}:{name}. {auth_result.message}')
124
127
 
125
128
  internal_scope = InternalScope(scope, vo=vo)
126
129
  return request.cancel_request_did(internal_scope, name, dest_rse_id, request_type, session=session)
@@ -149,8 +152,9 @@ def get_next(
149
152
  """
150
153
 
151
154
  kwargs = {'account': account, 'issuer': issuer, 'request_type': request_type, 'state': state}
152
- if not permission.has_permission(issuer=issuer, vo=vo, action='get_next', kwargs=kwargs, session=session):
153
- raise exception.AccessDenied(f'{account} cannot get the next request of type {request_type} in state {state}')
155
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='get_next', kwargs=kwargs, session=session)
156
+ if not auth_result.allowed:
157
+ raise exception.AccessDenied(f'{account} cannot get the next request of type {request_type} in state {state}. {auth_result.message}')
154
158
 
155
159
  reqs = request.get_and_mark_next(request_type, state, session=session)
156
160
  return [gateway_update_return_dict(r, session=session) for r in reqs]
@@ -180,8 +184,9 @@ def get_request_by_did(
180
184
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
181
185
 
182
186
  kwargs = {'scope': scope, 'name': name, 'rse': rse, 'rse_id': rse_id, 'issuer': issuer}
183
- if not permission.has_permission(issuer=issuer, vo=vo, action='get_request_by_did', kwargs=kwargs, session=session):
184
- raise exception.AccessDenied(f'{issuer} cannot retrieve the request DID {scope}:{name} to RSE {rse}')
187
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='get_request_by_did', kwargs=kwargs, session=session)
188
+ if not auth_result.allowed:
189
+ raise exception.AccessDenied(f'{issuer} cannot retrieve the request DID {scope}:{name} to RSE {rse}. {auth_result.message}')
185
190
 
186
191
  internal_scope = InternalScope(scope, vo=vo)
187
192
  req = request.get_request_by_did(internal_scope, name, rse_id, session=session)
@@ -213,8 +218,9 @@ def get_request_history_by_did(
213
218
  rse_id = get_rse_id(rse=rse, vo=vo, session=session)
214
219
 
215
220
  kwargs = {'scope': scope, 'name': name, 'rse': rse, 'rse_id': rse_id, 'issuer': issuer}
216
- if not permission.has_permission(issuer=issuer, vo=vo, action='get_request_history_by_did', kwargs=kwargs, session=session):
217
- raise exception.AccessDenied(f'{issuer} cannot retrieve the request DID {scope}:{name} to RSE {rse}')
221
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='get_request_history_by_did', kwargs=kwargs, session=session)
222
+ if not auth_result.allowed:
223
+ raise exception.AccessDenied(f'{issuer} cannot retrieve the request DID {scope}:{name} to RSE {rse}. {auth_result.message}')
218
224
 
219
225
  internal_scope = InternalScope(scope, vo=vo)
220
226
  req = request.get_request_history_by_did(internal_scope, name, rse_id, session=session)
@@ -245,8 +251,9 @@ def list_requests(
245
251
  dst_rse_ids = [get_rse_id(rse=rse, vo=vo, session=session) for rse in dst_rses]
246
252
 
247
253
  kwargs = {'src_rse_id': src_rse_ids, 'dst_rse_id': dst_rse_ids, 'issuer': issuer}
248
- if not permission.has_permission(issuer=issuer, vo=vo, action='list_requests', kwargs=kwargs, session=session):
249
- raise exception.AccessDenied(f'{issuer} cannot list requests from RSEs {src_rses} to RSEs {dst_rses}')
254
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='list_requests', kwargs=kwargs, session=session)
255
+ if not auth_result.allowed:
256
+ raise exception.AccessDenied(f'{issuer} cannot list requests from RSEs {src_rses} to RSEs {dst_rses}. {auth_result.message}')
250
257
 
251
258
  for req in request.list_requests(src_rse_ids, dst_rse_ids, states, session=session):
252
259
  req = req.to_dict()
@@ -279,8 +286,9 @@ def list_requests_history(
279
286
  dst_rse_ids = [get_rse_id(rse=rse, vo=vo, session=session) for rse in dst_rses]
280
287
 
281
288
  kwargs = {'src_rse_id': src_rse_ids, 'dst_rse_id': dst_rse_ids, 'issuer': issuer}
282
- if not permission.has_permission(issuer=issuer, vo=vo, action='list_requests_history', kwargs=kwargs, session=session):
283
- raise exception.AccessDenied(f'{issuer} cannot list requests from RSEs {src_rses} to RSEs {dst_rses}')
289
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='list_requests_history', kwargs=kwargs, session=session)
290
+ if not auth_result.allowed:
291
+ raise exception.AccessDenied(f'{issuer} cannot list requests from RSEs {src_rses} to RSEs {dst_rses}. {auth_result.message}')
284
292
 
285
293
  for req in request.list_requests_history(src_rse_ids, dst_rse_ids, states, offset, limit, session=session):
286
294
  req = req.to_dict()
@@ -315,7 +323,8 @@ def get_request_metrics(
315
323
  if dst_rse:
316
324
  dst_rse_id = get_rse_id(rse=dst_rse, vo=vo, session=session)
317
325
  kwargs = {'issuer': issuer}
318
- if not permission.has_permission(issuer=issuer, vo=vo, action='get_request_metrics', kwargs=kwargs, session=session):
319
- raise exception.AccessDenied(f'{issuer} cannot get request statistics')
326
+ auth_result = permission.has_permission(issuer=issuer, vo=vo, action='get_request_metrics', kwargs=kwargs, session=session)
327
+ if not auth_result.allowed:
328
+ raise exception.AccessDenied(f'{issuer} cannot get request statistics. {auth_result.message}')
320
329
 
321
330
  return request.get_request_metrics(dest_rse_id=dst_rse_id, src_rse_id=src_rse_id, activity=activity, group_by_rse_attribute=group_by_rse_attribute, session=session)