rucio 35.7.0__py3-none-any.whl → 37.0.0rc2__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 (268) 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/stomp_utils.py +383 -119
  48. rucio/common/test_rucio_server.py +12 -6
  49. rucio/common/types.py +132 -52
  50. rucio/common/utils.py +93 -643
  51. rucio/core/account_limit.py +14 -12
  52. rucio/core/authentication.py +2 -2
  53. rucio/core/config.py +23 -42
  54. rucio/core/credential.py +14 -15
  55. rucio/core/did.py +5 -1
  56. rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
  57. rucio/core/did_meta_plugins/filter_engine.py +62 -3
  58. rucio/core/did_meta_plugins/json_meta.py +2 -2
  59. rucio/core/did_meta_plugins/mongo_meta.py +43 -30
  60. rucio/core/did_meta_plugins/postgres_meta.py +75 -39
  61. rucio/core/identity.py +6 -5
  62. rucio/core/importer.py +4 -3
  63. rucio/core/lifetime_exception.py +2 -2
  64. rucio/core/lock.py +8 -7
  65. rucio/core/message.py +6 -0
  66. rucio/core/monitor.py +30 -29
  67. rucio/core/naming_convention.py +2 -2
  68. rucio/core/nongrid_trace.py +2 -2
  69. rucio/core/oidc.py +11 -9
  70. rucio/core/permission/__init__.py +79 -37
  71. rucio/core/permission/generic.py +1 -7
  72. rucio/core/permission/generic_multi_vo.py +1 -7
  73. rucio/core/quarantined_replica.py +4 -3
  74. rucio/core/replica.py +464 -139
  75. rucio/core/replica_sorter.py +55 -59
  76. rucio/core/request.py +34 -32
  77. rucio/core/rse.py +301 -97
  78. rucio/core/rse_counter.py +1 -2
  79. rucio/core/rse_expression_parser.py +7 -7
  80. rucio/core/rse_selector.py +9 -7
  81. rucio/core/rule.py +41 -40
  82. rucio/core/rule_grouping.py +42 -40
  83. rucio/core/scope.py +5 -4
  84. rucio/core/subscription.py +26 -28
  85. rucio/core/topology.py +11 -11
  86. rucio/core/trace.py +2 -2
  87. rucio/core/transfer.py +29 -15
  88. rucio/core/volatile_replica.py +4 -3
  89. rucio/daemons/atropos/atropos.py +1 -1
  90. rucio/daemons/auditor/__init__.py +2 -2
  91. rucio/daemons/auditor/srmdumps.py +6 -6
  92. rucio/daemons/automatix/automatix.py +32 -21
  93. rucio/daemons/badreplicas/necromancer.py +2 -2
  94. rucio/daemons/bb8/nuclei_background_rebalance.py +1 -1
  95. rucio/daemons/bb8/t2_background_rebalance.py +1 -1
  96. rucio/daemons/cache/consumer.py +26 -90
  97. rucio/daemons/common.py +15 -25
  98. rucio/daemons/conveyor/finisher.py +2 -2
  99. rucio/daemons/conveyor/poller.py +18 -28
  100. rucio/daemons/conveyor/receiver.py +53 -123
  101. rucio/daemons/conveyor/stager.py +1 -0
  102. rucio/daemons/conveyor/submitter.py +3 -3
  103. rucio/daemons/hermes/hermes.py +129 -369
  104. rucio/daemons/judge/evaluator.py +2 -2
  105. rucio/daemons/oauthmanager/oauthmanager.py +3 -3
  106. rucio/daemons/reaper/dark_reaper.py +7 -3
  107. rucio/daemons/reaper/reaper.py +12 -16
  108. rucio/daemons/rsedecommissioner/config.py +1 -1
  109. rucio/daemons/rsedecommissioner/profiles/generic.py +5 -4
  110. rucio/daemons/rsedecommissioner/profiles/types.py +7 -6
  111. rucio/daemons/rsedecommissioner/rse_decommissioner.py +1 -1
  112. rucio/daemons/storage/consistency/actions.py +8 -6
  113. rucio/daemons/tracer/kronos.py +117 -142
  114. rucio/db/sqla/constants.py +5 -0
  115. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +4 -4
  116. rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
  117. rucio/db/sqla/models.py +157 -154
  118. rucio/db/sqla/session.py +58 -27
  119. rucio/db/sqla/types.py +2 -2
  120. rucio/db/sqla/util.py +2 -2
  121. rucio/gateway/account.py +18 -12
  122. rucio/gateway/account_limit.py +137 -60
  123. rucio/gateway/authentication.py +18 -12
  124. rucio/gateway/config.py +30 -20
  125. rucio/gateway/credential.py +9 -10
  126. rucio/gateway/did.py +70 -53
  127. rucio/gateway/dirac.py +6 -4
  128. rucio/gateway/exporter.py +3 -2
  129. rucio/gateway/heartbeat.py +6 -4
  130. rucio/gateway/identity.py +36 -51
  131. rucio/gateway/importer.py +3 -2
  132. rucio/gateway/lifetime_exception.py +3 -2
  133. rucio/gateway/meta_conventions.py +17 -6
  134. rucio/gateway/permission.py +4 -1
  135. rucio/gateway/quarantined_replica.py +3 -2
  136. rucio/gateway/replica.py +31 -22
  137. rucio/gateway/request.py +27 -18
  138. rucio/gateway/rse.py +69 -37
  139. rucio/gateway/rule.py +46 -26
  140. rucio/gateway/scope.py +3 -2
  141. rucio/gateway/subscription.py +14 -11
  142. rucio/gateway/vo.py +12 -8
  143. rucio/rse/__init__.py +3 -3
  144. rucio/rse/protocols/bittorrent.py +11 -1
  145. rucio/rse/protocols/cache.py +0 -11
  146. rucio/rse/protocols/dummy.py +0 -11
  147. rucio/rse/protocols/gfal.py +14 -9
  148. rucio/rse/protocols/globus.py +1 -1
  149. rucio/rse/protocols/http_cache.py +1 -1
  150. rucio/rse/protocols/posix.py +2 -2
  151. rucio/rse/protocols/protocol.py +84 -317
  152. rucio/rse/protocols/rclone.py +2 -1
  153. rucio/rse/protocols/rfio.py +10 -1
  154. rucio/rse/protocols/ssh.py +2 -1
  155. rucio/rse/protocols/storm.py +2 -13
  156. rucio/rse/protocols/webdav.py +74 -30
  157. rucio/rse/protocols/xrootd.py +2 -1
  158. rucio/rse/rsemanager.py +170 -53
  159. rucio/rse/translation.py +260 -0
  160. rucio/tests/common.py +23 -13
  161. rucio/tests/common_server.py +26 -9
  162. rucio/transfertool/bittorrent.py +15 -14
  163. rucio/transfertool/bittorrent_driver.py +5 -7
  164. rucio/transfertool/bittorrent_driver_qbittorrent.py +9 -8
  165. rucio/transfertool/fts3.py +20 -16
  166. rucio/transfertool/mock.py +2 -3
  167. rucio/vcsversion.py +4 -4
  168. rucio/version.py +7 -0
  169. rucio/web/rest/flaskapi/v1/accounts.py +17 -3
  170. rucio/web/rest/flaskapi/v1/auth.py +5 -5
  171. rucio/web/rest/flaskapi/v1/credentials.py +3 -2
  172. rucio/web/rest/flaskapi/v1/dids.py +21 -15
  173. rucio/web/rest/flaskapi/v1/identities.py +33 -9
  174. rucio/web/rest/flaskapi/v1/redirect.py +5 -4
  175. rucio/web/rest/flaskapi/v1/replicas.py +12 -8
  176. rucio/web/rest/flaskapi/v1/rses.py +15 -4
  177. rucio/web/rest/flaskapi/v1/traces.py +56 -19
  178. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/alembic.ini.template +1 -1
  179. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/alembic_offline.ini.template +1 -1
  180. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/rucio.cfg.atlas.client.template +3 -2
  181. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/rucio.cfg.template +3 -19
  182. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/rucio_multi_vo.cfg.template +1 -18
  183. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/requirements.server.txt +97 -68
  184. rucio-37.0.0rc2.data/scripts/rucio +133 -0
  185. rucio-37.0.0rc2.data/scripts/rucio-admin +97 -0
  186. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-atropos +2 -2
  187. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-auditor +2 -1
  188. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-automatix +2 -2
  189. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-cache-client +17 -10
  190. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-conveyor-receiver +1 -0
  191. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-kronos +1 -0
  192. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-minos +2 -2
  193. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-minos-temporary-expiration +2 -2
  194. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-necromancer +2 -2
  195. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-reaper +6 -6
  196. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-transmogrifier +2 -2
  197. rucio-37.0.0rc2.dist-info/METADATA +92 -0
  198. {rucio-35.7.0.dist-info → rucio-37.0.0rc2.dist-info}/RECORD +239 -245
  199. {rucio-35.7.0.dist-info → rucio-37.0.0rc2.dist-info}/licenses/AUTHORS.rst +3 -0
  200. rucio/common/schema/atlas.py +0 -413
  201. rucio/common/schema/belleii.py +0 -408
  202. rucio/common/schema/domatpc.py +0 -401
  203. rucio/common/schema/escape.py +0 -426
  204. rucio/common/schema/icecube.py +0 -406
  205. rucio/core/permission/atlas.py +0 -1348
  206. rucio/core/permission/belleii.py +0 -1077
  207. rucio/core/permission/escape.py +0 -1078
  208. rucio/daemons/c3po/algorithms/__init__.py +0 -13
  209. rucio/daemons/c3po/algorithms/simple.py +0 -134
  210. rucio/daemons/c3po/algorithms/t2_free_space.py +0 -128
  211. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +0 -130
  212. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +0 -294
  213. rucio/daemons/c3po/c3po.py +0 -371
  214. rucio/daemons/c3po/collectors/agis.py +0 -108
  215. rucio/daemons/c3po/collectors/free_space.py +0 -81
  216. rucio/daemons/c3po/collectors/jedi_did.py +0 -57
  217. rucio/daemons/c3po/collectors/mock_did.py +0 -51
  218. rucio/daemons/c3po/collectors/network_metrics.py +0 -71
  219. rucio/daemons/c3po/collectors/workload.py +0 -112
  220. rucio/daemons/c3po/utils/__init__.py +0 -13
  221. rucio/daemons/c3po/utils/dataset_cache.py +0 -50
  222. rucio/daemons/c3po/utils/expiring_dataset_cache.py +0 -56
  223. rucio/daemons/c3po/utils/expiring_list.py +0 -62
  224. rucio/daemons/c3po/utils/popularity.py +0 -85
  225. rucio/daemons/c3po/utils/timeseries.py +0 -89
  226. rucio/rse/protocols/gsiftp.py +0 -92
  227. rucio-35.7.0.data/scripts/rucio-c3po +0 -85
  228. rucio-35.7.0.dist-info/METADATA +0 -72
  229. /rucio/{daemons/c3po → cli/bin_legacy}/__init__.py +0 -0
  230. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/globus-config.yml.template +0 -0
  231. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/ldap.cfg.template +0 -0
  232. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  233. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  234. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  235. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  236. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  237. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  238. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  239. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/tools/bootstrap.py +0 -0
  240. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
  241. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/data/rucio/tools/reset_database.py +0 -0
  242. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-abacus-account +0 -0
  243. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-abacus-collection-replica +0 -0
  244. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-abacus-rse +0 -0
  245. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-bb8 +0 -0
  246. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-cache-consumer +0 -0
  247. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-conveyor-finisher +0 -0
  248. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-conveyor-poller +0 -0
  249. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-conveyor-preparer +0 -0
  250. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-conveyor-stager +0 -0
  251. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-conveyor-submitter +0 -0
  252. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-conveyor-throttler +0 -0
  253. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-dark-reaper +0 -0
  254. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-dumper +0 -0
  255. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-follower +0 -0
  256. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-hermes +0 -0
  257. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-judge-cleaner +0 -0
  258. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-judge-evaluator +0 -0
  259. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-judge-injector +0 -0
  260. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-judge-repairer +0 -0
  261. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-oauth-manager +0 -0
  262. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-replica-recoverer +0 -0
  263. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-rse-decommissioner +0 -0
  264. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-storage-consistency-actions +0 -0
  265. {rucio-35.7.0.data → rucio-37.0.0rc2.data}/scripts/rucio-undertaker +0 -0
  266. {rucio-35.7.0.dist-info → rucio-37.0.0rc2.dist-info}/WHEEL +0 -0
  267. {rucio-35.7.0.dist-info → rucio-37.0.0rc2.dist-info}/licenses/LICENSE +0 -0
  268. {rucio-35.7.0.dist-info → rucio-37.0.0rc2.dist-info}/top_level.txt +0 -0
rucio/core/topology.py CHANGED
@@ -17,7 +17,6 @@ import itertools
17
17
  import logging
18
18
  import threading
19
19
  import weakref
20
- from collections.abc import Callable, Iterable, Iterator
21
20
  from decimal import Decimal
22
21
  from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast
23
22
 
@@ -38,6 +37,7 @@ TE = TypeVar("TE", bound="Edge")
38
37
  ExpiringObjectCacheNewObject = TypeVar("ExpiringObjectCacheNewObject")
39
38
 
40
39
  if TYPE_CHECKING:
40
+ from collections.abc import Callable, Iterable, Iterator
41
41
  from typing import Protocol
42
42
 
43
43
  from sqlalchemy.orm import Session
@@ -63,7 +63,7 @@ INF = float('inf')
63
63
 
64
64
 
65
65
  class Node(RseData):
66
- def __init__(self, rse_id: str):
66
+ def __init__(self, rse_id: str) -> None:
67
67
  super().__init__(rse_id)
68
68
 
69
69
  self.in_edges = weakref.WeakKeyDictionary()
@@ -75,7 +75,7 @@ class Node(RseData):
75
75
 
76
76
 
77
77
  class Edge(Generic[TN]):
78
- def __init__(self, src_node: TN, dst_node: TN):
78
+ def __init__(self, src_node: TN, dst_node: TN) -> None:
79
79
  self._src_node = weakref.ref(src_node)
80
80
  self._dst_node = weakref.ref(dst_node)
81
81
 
@@ -123,11 +123,11 @@ class Topology(RseCollection, Generic[TN, TE]):
123
123
  """
124
124
  def __init__(
125
125
  self,
126
- rse_ids: Optional[Iterable[str]] = None,
126
+ rse_ids: Optional["Iterable[str]"] = None,
127
127
  ignore_availability: bool = False,
128
128
  node_cls: type[TN] = Node,
129
129
  edge_cls: type[TE] = Edge,
130
- ):
130
+ ) -> None:
131
131
  super().__init__(rse_ids=rse_ids, rse_data_cls=node_cls)
132
132
  self._edge_cls = edge_cls
133
133
  self._edges: dict[tuple[TN, TN], TE] = {}
@@ -284,7 +284,7 @@ class Topology(RseCollection, Generic[TN, TE]):
284
284
  @read_session
285
285
  def search_shortest_paths(
286
286
  self,
287
- src_nodes: Iterable[TN],
287
+ src_nodes: "Iterable[TN]",
288
288
  dst_node: TN,
289
289
  operation_src: str,
290
290
  operation_dest: str,
@@ -310,7 +310,7 @@ class Topology(RseCollection, Generic[TN, TE]):
310
310
  class _NodeStateProvider:
311
311
  _hop_penalty = self._hop_penalty
312
312
 
313
- def __init__(self, node: TN):
313
+ def __init__(self, node: TN) -> None:
314
314
  self.enabled: bool = True
315
315
  self.cost: _Number = 0
316
316
  if node != dst_node:
@@ -322,7 +322,7 @@ class Topology(RseCollection, Generic[TN, TE]):
322
322
  scheme_missmatch_found = {}
323
323
 
324
324
  class _EdgeStateProvider:
325
- def __init__(self, edge: TE):
325
+ def __init__(self, edge: TE) -> None:
326
326
  self.edge = edge
327
327
  self.chosen_scheme = {}
328
328
 
@@ -358,7 +358,7 @@ class Topology(RseCollection, Generic[TN, TE]):
358
358
  node_state_provider=_NodeStateProvider,
359
359
  edge_state_provider=_EdgeStateProvider):
360
360
  nh_node = edge_to_next_hop.dst_node
361
- edge_state = cast(_EdgeStateProvider, edge_state)
361
+ edge_state = cast("_EdgeStateProvider", edge_state)
362
362
  hop = {
363
363
  'source_rse': node,
364
364
  'dest_rse': nh_node,
@@ -433,8 +433,8 @@ class ExpiringObjectCache(Generic[ExpiringObjectCacheNewObject]):
433
433
  def __init__(
434
434
  self,
435
435
  ttl: int,
436
- new_obj_fnc: Callable[[], ExpiringObjectCacheNewObject]
437
- ):
436
+ new_obj_fnc: "Callable[[], ExpiringObjectCacheNewObject]"
437
+ ) -> None:
438
438
  self._lock = threading.Lock()
439
439
  self._object: Optional[ExpiringObjectCacheNewObject] = None
440
440
  self._creation_time: Optional[datetime.datetime] = None
rucio/core/trace.py CHANGED
@@ -26,7 +26,7 @@ from typing import TYPE_CHECKING, Any, Union, overload
26
26
  import stomp
27
27
  from jsonschema import Draft7Validator, ValidationError, validate
28
28
 
29
- from rucio.common.config import config_get, config_get_int
29
+ from rucio.common.config import config_get, config_get_int, config_get_list
30
30
  from rucio.common.exception import InvalidObject, TraceValidationSchemaNotFound
31
31
  from rucio.common.logging import rucio_log_formatter
32
32
  from rucio.common.schema.generic import TIME_ENTRY, UUID, IPv4orIPv6
@@ -70,7 +70,7 @@ ROTATING_LOGGER.addHandler(ROTATING_HANDLER)
70
70
 
71
71
  BROKERS_ALIAS, BROKERS_RESOLVED = [], []
72
72
  try:
73
- BROKERS_ALIAS = [b.strip() for b in config_get('trace', 'brokers').split(',')]
73
+ BROKERS_ALIAS = config_get_list('trace', 'brokers')
74
74
  except:
75
75
  raise Exception('Could not load brokers from configuration')
76
76
 
rucio/core/transfer.py CHANGED
@@ -38,7 +38,6 @@ from rucio.core import request as request_core
38
38
  from rucio.core.account import list_accounts
39
39
  from rucio.core.monitor import MetricManager
40
40
  from rucio.core.request import DirectTransfer, RequestSource, RequestWithSources, TransferDestination, transition_request_state
41
- from rucio.core.rse import RseData
42
41
  from rucio.core.rse_expression_parser import parse_expression
43
42
  from rucio.db.sqla import models
44
43
  from rucio.db.sqla.constants import DIDType, RequestState, RequestType, TransferLimitDirection
@@ -48,7 +47,6 @@ from rucio.transfertool.bittorrent import BittorrentTransfertool
48
47
  from rucio.transfertool.fts3 import FTS3Transfertool
49
48
  from rucio.transfertool.globus import GlobusTransferTool
50
49
  from rucio.transfertool.mock import MockTransfertool
51
- from rucio.transfertool.transfertool import TransferStatusReport, Transfertool
52
50
 
53
51
  if TYPE_CHECKING:
54
52
  from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
@@ -56,9 +54,11 @@ if TYPE_CHECKING:
56
54
 
57
55
  from sqlalchemy.orm import Session
58
56
 
59
- from rucio.common.types import InternalAccount
57
+ from rucio.common.types import InternalAccount, LFNDict
58
+ from rucio.core.rse import RseData
60
59
  from rucio.core.topology import Topology
61
60
  from rucio.rse.protocols.protocol import RSEProtocol
61
+ from rucio.transfertool.transfertool import TransferStatusReport, Transfertool
62
62
 
63
63
  LoggerFunction = Callable[..., Any]
64
64
 
@@ -90,7 +90,7 @@ class ProtocolFactory:
90
90
  def __init__(self):
91
91
  self.protocols = {}
92
92
 
93
- def protocol(self, rse: RseData, scheme: "Optional[str]", operation: str):
93
+ def protocol(self, rse: 'RseData', scheme: "Optional[str]", operation: str):
94
94
  protocol_key = '%s_%s_%s' % (operation, rse.id, scheme)
95
95
  protocol = self.protocols.get(protocol_key)
96
96
  if not protocol:
@@ -210,7 +210,12 @@ class DirectTransferImplementation(DirectTransfer):
210
210
  # Compute the source URL
211
211
  source_sign_url = src.rse.attributes.get(RseAttr.SIGN_URL, None)
212
212
  dest_sign_url = dst.rse.attributes.get(RseAttr.SIGN_URL, None)
213
- source_url = list(protocol.lfns2pfns(lfns={'scope': rws.scope.external, 'name': rws.name, 'path': src.file_path}).values())[0]
213
+ lfn: "LFNDict" = {
214
+ 'scope': rws.scope.external, # type: ignore (scope.external might be None)
215
+ 'name': rws.name,
216
+ 'path': src.file_path
217
+ }
218
+ source_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
214
219
  source_url = cls.__rewrite_source_url(source_url, source_sign_url=source_sign_url, dest_sign_url=dest_sign_url, source_scheme=src.scheme)
215
220
  return source_url
216
221
 
@@ -223,7 +228,11 @@ class DirectTransferImplementation(DirectTransfer):
223
228
  protocol = protocol_factory.protocol(dst.rse, dst.scheme, operation)
224
229
 
225
230
  if dst.rse.info['deterministic']:
226
- dest_url = list(protocol.lfns2pfns(lfns={'scope': rws.scope.external, 'name': rws.name}).values())[0]
231
+ lfn: "LFNDict" = {
232
+ 'scope': rws.scope.external, # type: ignore (scope.external might be None)
233
+ 'name': rws.name
234
+ }
235
+ dest_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
227
236
  else:
228
237
  # compute dest url in case of non deterministic
229
238
  # naming convention, etc.
@@ -236,7 +245,12 @@ class DirectTransferImplementation(DirectTransfer):
236
245
  if rws.retry_count or rws.activity == 'Recovery':
237
246
  dest_path = '%s_%i' % (dest_path, int(time.time()))
238
247
 
239
- dest_url = list(protocol.lfns2pfns(lfns={'scope': rws.scope.external, 'name': rws.name, 'path': dest_path}).values())[0]
248
+ lfn: "LFNDict" = {
249
+ 'scope': rws.scope.external, # type: ignore (scope.external might be None)
250
+ 'name': rws.name,
251
+ 'path': dest_path
252
+ }
253
+ dest_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
240
254
 
241
255
  dest_sign_url = dst.rse.attributes.get(RseAttr.SIGN_URL, None)
242
256
  dest_url = cls.__rewrite_dest_url(dest_url, dest_sign_url=dest_sign_url)
@@ -498,7 +512,7 @@ def set_transfers_state(
498
512
 
499
513
  @transactional_session
500
514
  def update_transfer_state(
501
- tt_status_report: TransferStatusReport,
515
+ tt_status_report: 'TransferStatusReport',
502
516
  stats_manager: request_core.TransferStatsManager,
503
517
  *,
504
518
  session: "Session",
@@ -744,7 +758,7 @@ def _create_stagein_definitions(
744
758
  """
745
759
  transfers_by_source = {
746
760
  source.rse: [
747
- cast(DirectTransfer, StageinTransferImplementation(
761
+ cast('DirectTransfer', StageinTransferImplementation(
748
762
  source=RequestSource(
749
763
  rse=source.rse,
750
764
  file_path=source.file_path,
@@ -973,7 +987,7 @@ class EnforceSourceRSEExpression(SourceFilterStrategy):
973
987
  return self._RankingContext(self, rws, allowed_source_rses)
974
988
 
975
989
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
976
- ctx = cast(EnforceSourceRSEExpression._RankingContext, ctx)
990
+ ctx = cast('EnforceSourceRSEExpression._RankingContext', ctx)
977
991
  if ctx.allowed_source_rses is not None and source.rse.id not in ctx.allowed_source_rses:
978
992
  return SKIP_SOURCE
979
993
 
@@ -1049,7 +1063,7 @@ class PathDistance(SourceRankingStrategy):
1049
1063
  return PathDistance._RankingContext(self, rws, paths_for_rws)
1050
1064
 
1051
1065
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1052
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1066
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1053
1067
  if not path:
1054
1068
  return SKIP_SOURCE
1055
1069
  return path[0].src.distance
@@ -1057,7 +1071,7 @@ class PathDistance(SourceRankingStrategy):
1057
1071
 
1058
1072
  class PreferSingleHop(PathDistance):
1059
1073
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1060
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1074
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1061
1075
  if not path:
1062
1076
  return SKIP_SOURCE
1063
1077
  return int(len(path) > 1)
@@ -1097,7 +1111,7 @@ class FailureRate(SourceRankingStrategy):
1097
1111
  self.source_stats.setdefault(stat['src_rse_id'], self._FailureRateStat()).incorporate_stat(stat)
1098
1112
 
1099
1113
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1100
- failure_rate = cast(FailureRate, ctx.strategy).source_stats.get(source.rse.id, self._FailureRateStat()).get_failure_rate()
1114
+ failure_rate = cast('FailureRate', ctx.strategy).source_stats.get(source.rse.id, self._FailureRateStat()).get_failure_rate()
1101
1115
  return failure_rate
1102
1116
 
1103
1117
 
@@ -1105,7 +1119,7 @@ class SkipSchemeMissmatch(PathDistance):
1105
1119
  filter_only = True
1106
1120
 
1107
1121
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1108
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1122
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1109
1123
  # path == None means that there is no path;
1110
1124
  # path == [] means that a path exists (according to distances) but cannot be used (scheme mismatch)
1111
1125
  if path is not None and not path:
@@ -1117,7 +1131,7 @@ class SkipIntermediateTape(PathDistance):
1117
1131
 
1118
1132
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1119
1133
  # Discard multihop transfers which contain a tape source as an intermediate hop
1120
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1134
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1121
1135
  if path and any(transfer.src.rse.is_tape_or_staging_required() for transfer in path[1:]):
1122
1136
  return SKIP_SOURCE
1123
1137
 
@@ -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 Iterable
16
15
  from datetime import datetime
17
16
  from typing import TYPE_CHECKING, Any
18
17
 
@@ -26,11 +25,13 @@ from rucio.db.sqla.constants import ReplicaState
26
25
  from rucio.db.sqla.session import transactional_session
27
26
 
28
27
  if TYPE_CHECKING:
28
+ from collections.abc import Iterable
29
+
29
30
  from sqlalchemy.orm import Session
30
31
 
31
32
 
32
33
  @transactional_session
33
- def add_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, session: "Session") -> None:
34
+ def add_volatile_replicas(rse_id: str, replicas: "Iterable[dict[str, Any]]", *, session: "Session") -> None:
34
35
  """
35
36
  Bulk add volatile replicas.
36
37
 
@@ -112,7 +113,7 @@ def add_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, se
112
113
 
113
114
 
114
115
  @transactional_session
115
- def delete_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, session: "Session") -> None:
116
+ def delete_volatile_replicas(rse_id: str, replicas: "Iterable[dict[str, Any]]", *, session: "Session") -> None:
116
117
  """
117
118
  Bulk delete volatile replicas.
118
119
 
@@ -81,7 +81,7 @@ def atropos(
81
81
 
82
82
  def run_once(
83
83
  heartbeat_handler: 'HeartbeatHandler',
84
- activity: None, # NOQA, pylint: disable=W0613
84
+ activity: None, # NOQA: ARG001
85
85
  date_check: datetime.datetime,
86
86
  dry_run: bool,
87
87
  grace_period: int,
@@ -16,9 +16,9 @@ import bz2
16
16
  import glob
17
17
  import logging
18
18
  import os
19
- import queue as Queue
20
19
  import select
21
20
  from datetime import datetime, timedelta
21
+ from queue import Empty as EmptyQueue
22
22
  from typing import TYPE_CHECKING, Optional
23
23
 
24
24
  from rucio.common import config
@@ -238,7 +238,7 @@ def check(
238
238
  while not terminate.is_set():
239
239
  try:
240
240
  rse, attempts = queue.get(timeout=30)
241
- except Queue.Empty:
241
+ except EmptyQueue:
242
242
  continue
243
243
  start = datetime.now()
244
244
  try:
@@ -12,15 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import configparser as ConfigParser
16
15
  import datetime
17
16
  import glob
18
17
  import hashlib
19
- import html.parser as HTMLParser
20
18
  import logging
21
19
  import operator
22
20
  import os
23
21
  import re
22
+ from configparser import RawConfigParser
23
+ from html.parser import HTMLParser
24
24
  from typing import IO, TYPE_CHECKING, Any, Optional
25
25
 
26
26
  import gfal2
@@ -49,7 +49,7 @@ __DUMPERCONFIGDIRS = list(
49
49
  OBJECTSTORE_NUM_TRIES = 30
50
50
 
51
51
 
52
- class Parser(ConfigParser.RawConfigParser):
52
+ class Parser(RawConfigParser):
53
53
  '''
54
54
  RawConfigParser subclass that doesn't modify the the name of the options
55
55
  and removes any quotes around the string values.
@@ -137,7 +137,7 @@ def gfal_links(base_url: str) -> list[str]:
137
137
  return ['/'.join((base_url, f)) for f in ctxt.listdir(str(base_url))]
138
138
 
139
139
 
140
- class _LinkCollector(HTMLParser.HTMLParser):
140
+ class _LinkCollector(HTMLParser):
141
141
  def __init__(self):
142
142
  super(_LinkCollector, self).__init__()
143
143
  self.links = []
@@ -244,7 +244,7 @@ def parse_configuration(conf_dirs: Optional[list[str]] = None) -> Parser:
244
244
 
245
245
  def download_rse_dump(
246
246
  rse: str,
247
- configuration: ConfigParser.RawConfigParser,
247
+ configuration: RawConfigParser,
248
248
  date: Optional[datetime.datetime] = None,
249
249
  destdir: str = DUMPS_CACHE_DIR
250
250
  ) -> tuple[str, datetime.datetime]:
@@ -331,7 +331,7 @@ def download_rse_dump(
331
331
 
332
332
  def generate_url(
333
333
  rse: str,
334
- config: ConfigParser.RawConfigParser
334
+ config: RawConfigParser
335
335
  ) -> tuple[str, str]:
336
336
  '''
337
337
  :param rse: Name of the endpoint.
@@ -28,7 +28,7 @@ import rucio.db.sqla.util
28
28
  from rucio.client import Client
29
29
  from rucio.client.uploadclient import UploadClient
30
30
  from rucio.common import exception
31
- from rucio.common.config import config_get, config_get_bool, config_get_int
31
+ from rucio.common.config import config_get, config_get_bool, config_get_int, config_get_list
32
32
  from rucio.common.logging import setup_logging
33
33
  from rucio.common.stopwatch import Stopwatch
34
34
  from rucio.common.types import InternalScope, LoggerFunction
@@ -149,18 +149,14 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
149
149
 
150
150
  _, _, logger = heartbeat_handler.live()
151
151
  try:
152
- rses = [
153
- s.strip() for s in config_get("automatix", "rses").split(",")
154
- ] # TODO use config_get_list
152
+ rses = config_get_list("automatix", "rses")
155
153
  except (NoOptionError, NoSectionError, RuntimeError):
156
154
  logging.log(
157
155
  logging.ERROR,
158
156
  "Option rses not found in automatix section. Trying the legacy sites option",
159
157
  )
160
158
  try:
161
- rses = [
162
- s.strip() for s in config_get("automatix", "sites").split(",")
163
- ] # TODO use config_get_list
159
+ rses = config_get_list("automatix", "sites")
164
160
  logging.log(
165
161
  logging.WARNING,
166
162
  "Option sites found in automatix section. This option will be deprecated soon. Please update your config to use rses.",
@@ -190,6 +186,8 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
190
186
  logger(logging.DEBUG, "Probabilities %s", probabilities)
191
187
 
192
188
  cycle_stopwatch = Stopwatch()
189
+ successes = []
190
+ failures = []
193
191
  for rse in rses:
194
192
  stopwatch = Stopwatch()
195
193
  _, _, logger = heartbeat_handler.live()
@@ -239,24 +237,37 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
239
237
  file_["dataset_meta"]["lifetime"] = dataset_lifetime
240
238
  files.append(file_)
241
239
  logger(logging.INFO, "Upload %s:%s to %s", scope, dsn, rse)
242
- upload_client = UploadClient(client)
243
- ret = upload_client.upload(files)
244
- if ret == 0:
245
- logger(logging.INFO, "%s successfully registered" % dsn)
246
- METRICS.counter(name="addnewdataset.done").inc()
247
- METRICS.counter(name="addnewfile.done").inc(nbfiles)
248
- METRICS.timer(name='datasetinjection').observe(stopwatch.elapsed)
249
- else:
250
- logger(logging.INFO, "Error uploading files")
251
- for physical_fname in physical_fnames:
252
- remove(physical_fname)
253
- rmdir(tmpdir)
240
+ try:
241
+ upload_client = UploadClient(client)
242
+ ret = upload_client.upload(files)
243
+ if ret == 0:
244
+ logger(logging.INFO, "%s successfully registered on %s", dsn, rse)
245
+ METRICS.counter(name="addnewdataset.done").inc()
246
+ METRICS.counter(name="addnewfile.done").inc(nbfiles)
247
+ METRICS.timer(name='datasetinjection').observe(stopwatch.elapsed)
248
+ successes.append(rse)
249
+ else:
250
+ logger(logging.INFO, "Error uploading files")
251
+ failures.append(rse)
252
+ except Exception as error:
253
+ logger(logging.ERROR, "Error uploading files on %s: %s", rse, str(error))
254
+ failures.append(rse)
255
+ finally:
256
+ for physical_fname in physical_fnames:
257
+ remove(physical_fname)
258
+ rmdir(tmpdir)
254
259
  logger(
255
260
  logging.INFO,
256
- "It took %f seconds to upload one dataset on %s",
261
+ "It took %f seconds to upload datasets on %s RSEs: %s",
257
262
  cycle_stopwatch.elapsed,
258
- str(rses),
263
+ len(successes),
264
+ str(successes),
259
265
  )
266
+ if failures:
267
+ logger(
268
+ logging.WARNING,
269
+ "Datasets could not be uploaded on %s RSEs: %s", len(failures), str(failures),
270
+ )
260
271
  return True
261
272
 
262
273
 
@@ -25,7 +25,7 @@ from sqlalchemy.exc import DatabaseError
25
25
 
26
26
  import rucio.db.sqla.util
27
27
  from rucio.common import exception
28
- from rucio.common.cache import make_region_memcached
28
+ from rucio.common.cache import MemcacheRegion
29
29
  from rucio.common.config import config_get_int
30
30
  from rucio.common.exception import DatabaseException
31
31
  from rucio.common.logging import setup_logging
@@ -41,7 +41,7 @@ if TYPE_CHECKING:
41
41
 
42
42
  graceful_stop = threading.Event()
43
43
  METRICS = MetricManager(module=__name__)
44
- REGION = make_region_memcached(expiration_time=config_get_int('necromancer', 'cache_time', False, 600))
44
+ REGION = MemcacheRegion(expiration_time=config_get_int('necromancer', 'cache_time', False, 600))
45
45
  DAEMON_NAME = 'necromancer'
46
46
 
47
47
 
@@ -61,7 +61,7 @@ total_total = 0
61
61
  global_ratio = float(0)
62
62
  for rse in rses:
63
63
  site_name = get_rse_attribute(rse['id'], RseAttr.SITE)
64
- rse['groupdisk'] = group_space(site_name)
64
+ rse['groupdisk'] = group_space(site_name) # type: ignore (site_name could be None)
65
65
  rse['primary'] = get_rse_usage(rse_id=rse['id'], source='rucio')[0]['used'] - get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
66
66
  rse['primary'] += rse['groupdisk']
67
67
  rse['secondary'] = get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
@@ -61,7 +61,7 @@ total_total = 0
61
61
  global_ratio = float(0)
62
62
  for rse in rses:
63
63
  site_name = get_rse_attribute(rse['id'], RseAttr.SITE)
64
- rse['groupdisk'] = group_space(site_name)
64
+ rse['groupdisk'] = group_space(site_name) # type: ignore (site_name could be None)
65
65
  rse['primary'] = get_rse_usage(rse_id=rse['id'], source='rucio')[0]['used'] - get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
66
66
  rse['primary'] += rse['groupdisk']
67
67
  rse['secondary'] = get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']