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
@@ -21,7 +21,7 @@ from datetime import datetime, timedelta
21
21
  from math import asin, cos, radians, sin, sqrt
22
22
  from pathlib import Path
23
23
  from tempfile import TemporaryDirectory, TemporaryFile
24
- from typing import Optional, Union
24
+ from typing import IO, TYPE_CHECKING, Any, Optional, Union
25
25
  from urllib.parse import urlparse
26
26
 
27
27
  import geoip2.database
@@ -29,20 +29,29 @@ import requests
29
29
  from dogpile.cache.api import NO_VALUE
30
30
 
31
31
  from rucio.common import utils
32
- from rucio.common.cache import make_region_memcached
32
+ from rucio.common.cache import MemcacheRegion
33
33
  from rucio.common.config import config_get, config_get_bool, config_get_int
34
34
  from rucio.common.constants import SORTING_ALGORITHMS
35
35
  from rucio.common.exception import InvalidRSEExpression, SortingAlgorithmNotSupported
36
36
  from rucio.core.rse_expression_parser import parse_expression
37
37
 
38
- REGION = make_region_memcached(expiration_time=900, function_key_generator=utils.my_key_generator)
38
+ if TYPE_CHECKING:
39
+ from _typeshed import StrPath
40
+
41
+ from rucio.common.types import IPDict, ReplicaDict
42
+
43
+ REGION = MemcacheRegion(expiration_time=900, function_key_generator=utils.my_key_generator)
39
44
 
40
45
  # This product uses GeoLite data created by MaxMind,
41
46
  # available from <a href="http://www.maxmind.com">http://www.maxmind.com</a>
42
47
  GEOIP_DB_EDITION = 'GeoLite2-City'
43
48
 
44
49
 
45
- def extract_file_from_tar_gz(archive_file_obj, file_name, destination):
50
+ def extract_file_from_tar_gz(
51
+ archive_file_obj: IO,
52
+ file_name: str,
53
+ destination: 'StrPath'
54
+ ) -> None:
46
55
  """
47
56
  Extract one file from the archive and put it at the destination
48
57
 
@@ -58,7 +67,7 @@ def extract_file_from_tar_gz(archive_file_obj, file_name, destination):
58
67
  shutil.move(tmp_dir / entry.name, destination)
59
68
 
60
69
 
61
- def __download_geoip_db(destination):
70
+ def __download_geoip_db(destination: 'StrPath') -> None:
62
71
  edition_id = GEOIP_DB_EDITION
63
72
  download_url = config_get('core', 'geoip_download_url', raise_exception=False, default=None)
64
73
  verify_tls = config_get_bool('core', 'geoip_download_verify_tls', raise_exception=False, default=True)
@@ -82,7 +91,7 @@ def __download_geoip_db(destination):
82
91
  result.text))
83
92
 
84
93
 
85
- def __geoip_db():
94
+ def __geoip_db() -> geoip2.database.Reader:
86
95
  db_path = Path(f'/tmp/{GEOIP_DB_EDITION}.mmdb')
87
96
  db_expire_delay = timedelta(days=config_get_int('core', 'geoip_expire_delay', raise_exception=False, default=30))
88
97
 
@@ -100,10 +109,13 @@ def __geoip_db():
100
109
  return geoip2.database.Reader(str(db_path))
101
110
 
102
111
 
103
- def __get_lat_long(se, gi):
112
+ def __get_lat_long(
113
+ se: str,
114
+ gi: geoip2.database.Reader
115
+ ) -> tuple[Optional[float], Optional[float]]:
104
116
  """
105
117
  Get the latitude and longitude on one host using the GeoLite DB
106
- :param se : A hostname or IP.
118
+ :param se : A hostname or IP.
107
119
  :param gi : A Reader object (geoip2 API).
108
120
  """
109
121
  try:
@@ -116,7 +128,11 @@ def __get_lat_long(se, gi):
116
128
  return None, None
117
129
 
118
130
 
119
- def __get_distance(se1, client_location, ignore_error):
131
+ def __get_distance(
132
+ se1: str,
133
+ client_location: 'IPDict',
134
+ ignore_error: bool
135
+ ) -> float:
120
136
  """
121
137
  Get the distance between 2 host using the GeoLite DB
122
138
  :param se1 : A first hostname or IP.
@@ -133,14 +149,15 @@ def __get_distance(se1, client_location, ignore_error):
133
149
  gi = __geoip_db()
134
150
 
135
151
  lat1, long1 = __get_lat_long(se1, gi)
136
- if client_location.get('latitude') and client_location.get('longitude'):
137
- lat2 = client_location['latitude']
138
- long2 = client_location['longitude']
139
- else:
152
+
153
+ lat2 = client_location.get('latitude')
154
+ long2 = client_location.get('longitude')
155
+
156
+ if not (lat2 and long2) and client_location['ip'] is not None:
140
157
  lat2, long2 = __get_lat_long(client_location['ip'], gi)
141
158
 
142
159
  if lat1 and lat2:
143
- long1, lat1, long2, lat2 = map(radians, [long1, lat1, long2, lat2])
160
+ long1, lat1, long2, lat2 = map(radians, [long1, lat1, long2, lat2]) # type: ignore (lat2 and long2 might be None)
144
161
  dlon = long2 - long1
145
162
  dlat = lat2 - lat1
146
163
  cache_val = 6378 * 2 * asin(sqrt(sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2))
@@ -152,7 +169,7 @@ def __get_distance(se1, client_location, ignore_error):
152
169
  # One host is on the Moon
153
170
  cache_val = 360000
154
171
  REGION.set(cache_key, cache_val)
155
- return cache_val
172
+ return cache_val # type: ignore (cache_val should not be None)
156
173
 
157
174
 
158
175
  def __download_custom_distance_table() -> None:
@@ -206,7 +223,7 @@ def __download_custom_distance_table() -> None:
206
223
  REGION.set(cache_key, distance)
207
224
 
208
225
 
209
- def __get_distance_custom(rse: Union[tuple, str], client_location: dict) -> float:
226
+ def __get_distance_custom(rse: Union[tuple, str], client_location: 'IPDict') -> float:
210
227
  """
211
228
  Return the distance from a client to a RSE by looking up in custom distance table
212
229
  :param rse: RSE name, or tuple containing replica information with RSE name third
@@ -228,7 +245,11 @@ def __get_distance_custom(rse: Union[tuple, str], client_location: dict) -> floa
228
245
  return cache_val
229
246
 
230
247
 
231
- def site_selector(replicas, site, vo):
248
+ def site_selector(
249
+ replicas: dict[str, 'ReplicaDict'],
250
+ site: str,
251
+ vo: str
252
+ ) -> list[str]:
232
253
  """
233
254
  Return a list of replicas located on one site.
234
255
  :param replicas : A dict with RSEs as values and replicas as keys (URIs).
@@ -249,7 +270,11 @@ def site_selector(replicas, site, vo):
249
270
  return result
250
271
 
251
272
 
252
- def sort_replicas(dictreplica: dict, client_location: dict, selection: Optional[str] = None) -> list:
273
+ def sort_replicas(
274
+ dictreplica: dict[str, Any],
275
+ client_location: 'IPDict',
276
+ selection: Optional[str] = None
277
+ ) -> list[str]:
253
278
  """
254
279
  General sorting method for a dictionary of replicas. Returns the List of replicas.
255
280
 
@@ -279,19 +304,13 @@ def sort_replicas(dictreplica: dict, client_location: dict, selection: Optional[
279
304
  replicas = sort_geoip(dictreplica, client_location, ignore_error=config_get_bool('core', 'geoip_ignore_error', raise_exception=False, default=True))
280
305
  elif selection == 'custom_table':
281
306
  replicas = sort_custom(dictreplica, client_location)
282
- elif selection == 'closeness':
283
- replicas = sort_closeness(dictreplica, client_location)
284
- elif selection == 'dynamic':
285
- replicas = sort_dynamic(dictreplica, client_location)
286
- elif selection == 'ranking':
287
- replicas = sort_ranking(dictreplica, client_location)
288
307
  elif selection == 'random':
289
308
  replicas = sort_random(dictreplica)
290
309
 
291
310
  return replicas
292
311
 
293
312
 
294
- def sort_random(dictreplica: dict) -> list:
313
+ def sort_random(dictreplica: dict[str, Any]) -> list[str]:
295
314
  """
296
315
  Return a list of replicas sorted randomly.
297
316
  :param dictreplica: A dict with replicas as keys (URIs).
@@ -302,7 +321,11 @@ def sort_random(dictreplica: dict) -> list:
302
321
  return list_replicas
303
322
 
304
323
 
305
- def sort_geoip(dictreplica: dict, client_location: dict, ignore_error: bool = False) -> list:
324
+ def sort_geoip(
325
+ dictreplica: dict[str, Any],
326
+ client_location: 'IPDict',
327
+ ignore_error: bool = False
328
+ ) -> list[str]:
306
329
  """
307
330
  Return a list of replicas sorted by geographical distance to the client IP.
308
331
  :param dictreplica: A dict with replicas as keys (URIs).
@@ -310,19 +333,22 @@ def sort_geoip(dictreplica: dict, client_location: dict, ignore_error: bool = Fa
310
333
  :param ignore_error: Ignore exception when the GeoLite DB cannot be retrieved
311
334
  """
312
335
 
313
- def distance(pfn):
336
+ def distance(pfn: str) -> float:
314
337
  url = urlparse(pfn)
315
338
  if url.scheme == 'root':
316
339
  # handle root proxy urls: root://10.0.0.1//root://192.168.1.1:1094//dpm/....
317
340
  sub_url = urlparse(url.path.lstrip('/'))
318
341
  if sub_url.scheme and sub_url.hostname:
319
342
  url = sub_url
320
- return __get_distance(url.hostname, client_location, ignore_error)
343
+ return __get_distance(url.hostname, client_location, ignore_error) # type: ignore (hostname might be None)
321
344
 
322
345
  return list(sorted(dictreplica, key=distance))
323
346
 
324
347
 
325
- def sort_custom(dictreplica: dict, client_location: dict) -> list:
348
+ def sort_custom(
349
+ dictreplica: dict[str, Any],
350
+ client_location: 'IPDict'
351
+ ) -> list[str]:
326
352
  """
327
353
  Return a list of replicas sorted according to the custom distance table.
328
354
  :param dictreplica: A dict with replicas as keys (URIs).
@@ -334,33 +360,3 @@ def sort_custom(dictreplica: dict, client_location: dict) -> list:
334
360
  return __get_distance_custom(dictreplica[pfn], client_location)
335
361
 
336
362
  return list(sorted(dictreplica, key=distance))
337
-
338
-
339
- def sort_closeness(dictreplica: dict, client_location: dict) -> list:
340
- """
341
- Return a list of replicas sorted by AGIS closeness. NOT IMPLEMENTED
342
- :param dictreplica: A dict with replicas as keys (URIs).
343
- :param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
344
- """
345
-
346
- return list(dictreplica.keys())
347
-
348
-
349
- def sort_ranking(dictreplica: dict, client_location: dict) -> list:
350
- """
351
- Return a list of replicas sorted by ranking metric. NOT IMPLEMENTED
352
- :param dictreplica: A dict with replicas as keys (URIs).
353
- :param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
354
- """
355
-
356
- return list(dictreplica.keys())
357
-
358
-
359
- def sort_dynamic(dictreplica: dict, client_location: dict) -> list:
360
- """
361
- Return a list of replicas sorted by dynamic network metrics. NOT IMPLEMENTED
362
- :param dictreplica: A dict with replicas as keys (URIs).
363
- :param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
364
- """
365
-
366
- return list(dictreplica.keys())
rucio/core/request.py CHANGED
@@ -20,10 +20,8 @@ import math
20
20
  import random
21
21
  import threading
22
22
  import traceback
23
- import uuid
24
23
  from abc import ABCMeta, abstractmethod
25
24
  from collections import defaultdict, namedtuple
26
- from collections.abc import Iterable, Iterator, Mapping, Sequence
27
25
  from dataclasses import dataclass
28
26
  from typing import TYPE_CHECKING, Any, Optional, Union
29
27
 
@@ -31,7 +29,6 @@ from sqlalchemy import and_, delete, exists, insert, or_, select, update
31
29
  from sqlalchemy.exc import IntegrityError
32
30
  from sqlalchemy.orm import aliased
33
31
  from sqlalchemy.sql.expression import asc, false, func, null, true
34
- from sqlalchemy.sql.functions import coalesce
35
32
 
36
33
  from rucio.common.config import config_get_bool, config_get_int
37
34
  from rucio.common.constants import RseAttr
@@ -51,6 +48,8 @@ from rucio.db.sqla.util import temp_table_mngr
51
48
  RequestAndState = namedtuple('RequestAndState', ['request_id', 'request_state'])
52
49
 
53
50
  if TYPE_CHECKING:
51
+ import uuid
52
+ from collections.abc import Iterable, Iterator, Mapping, Sequence
54
53
 
55
54
  from sqlalchemy.engine import Row
56
55
  from sqlalchemy.orm import Session
@@ -298,7 +297,7 @@ def requeue_and_archive(
298
297
  @METRICS.count_it
299
298
  @transactional_session
300
299
  def queue_requests(
301
- requests: Iterable[RequestDict],
300
+ requests: 'Iterable[RequestDict]',
302
301
  *,
303
302
  session: "Session",
304
303
  logger: LoggerFunction = logging.log
@@ -457,7 +456,7 @@ def list_and_mark_transfer_requests_and_source_replicas(
457
456
  limit: Optional[int] = None,
458
457
  activity: Optional[str] = None,
459
458
  older_than: Optional[datetime.datetime] = None,
460
- rses: Optional[Sequence[str]] = None,
459
+ rses: Optional['Sequence[str]'] = None,
461
460
  request_type: Optional[list[RequestType]] = None,
462
461
  request_state: Optional[RequestState] = None,
463
462
  required_source_rse_attrs: Optional[list[str]] = None,
@@ -494,8 +493,6 @@ def list_and_mark_transfer_requests_and_source_replicas(
494
493
  if request_type is None:
495
494
  request_type = [RequestType.TRANSFER]
496
495
 
497
- now = datetime.datetime.utcnow()
498
-
499
496
  sub_requests = select(
500
497
  models.Request.id,
501
498
  models.Request.request_type,
@@ -527,7 +524,11 @@ def list_and_mark_transfer_requests_and_source_replicas(
527
524
  models.ReplicationRule,
528
525
  models.Request.rule_id == models.ReplicationRule.id
529
526
  ).where(
530
- coalesce(models.ReplicationRule.expires_at, now) >= now
527
+ or_(models.ReplicationRule.child_rule_id != null(),
528
+ and_(models.ReplicationRule.child_rule_id == null(),
529
+ models.ReplicationRule.expires_at == null()),
530
+ and_(models.ReplicationRule.child_rule_id == null(),
531
+ models.ReplicationRule.expires_at > datetime.datetime.utcnow()))
531
532
  ).join(
532
533
  models.RSE,
533
534
  models.RSE.id == models.Request.dest_rse_id
@@ -1035,7 +1036,7 @@ def transition_request_state(
1035
1036
  @METRICS.count_it
1036
1037
  @transactional_session
1037
1038
  def transition_requests_state_if_possible(
1038
- request_ids: Iterable[str],
1039
+ request_ids: 'Iterable[str]',
1039
1040
  new_state: str,
1040
1041
  *,
1041
1042
  session: "Session",
@@ -1942,7 +1943,7 @@ class TransferStatsManager:
1942
1943
  resolution: datetime.timedelta,
1943
1944
  start_time: "Optional[datetime.datetime]" = None,
1944
1945
  end_time: "Optional[datetime.datetime]" = None
1945
- ) -> Iterator[tuple[datetime.datetime, datetime.datetime]]:
1946
+ ) -> 'Iterator[tuple[datetime.datetime, datetime.datetime]]':
1946
1947
  """
1947
1948
  Iterates, back in time, over time intervals of length `resolution` which are fully
1948
1949
  included within the input interval (start_time, end_time).
@@ -2065,17 +2066,18 @@ def get_request_stats(
2065
2066
  activity: Optional[str] = None,
2066
2067
  *,
2067
2068
  session: "Session"
2068
- ) -> Sequence[
2069
- """Row[tuple[
2070
- Optional[InternalAccount],
2071
- RequestState,
2072
- uuid.UUID,
2073
- Optional[uuid.UUID],
2074
- Optional[str],
2075
- int,
2076
- Optional[int]
2077
- ]]"""
2078
- ]:
2069
+ ) -> """Sequence[
2070
+ Row[tuple[
2071
+ Optional[InternalAccount],
2072
+ RequestState,
2073
+ uuid.UUID,
2074
+ Optional[uuid.UUID],
2075
+ Optional[str],
2076
+ int,
2077
+ Optional[int]
2078
+ ]
2079
+ ]
2080
+ ]""":
2079
2081
  """
2080
2082
  Retrieve statistics about requests by destination, activity and state.
2081
2083
  """
@@ -2521,7 +2523,7 @@ def release_all_waiting_requests(
2521
2523
  def list_transfer_limits(
2522
2524
  *,
2523
2525
  session: "Session",
2524
- ) -> Iterator[dict[str, Any]]:
2526
+ ) -> 'Iterator[dict[str, Any]]':
2525
2527
  stmt = select(
2526
2528
  models.TransferLimit
2527
2529
  )
@@ -2531,7 +2533,7 @@ def list_transfer_limits(
2531
2533
 
2532
2534
 
2533
2535
  def _sync_rse_transfer_limit(
2534
- limit_id: Union[str, uuid.UUID],
2536
+ limit_id: Union[str, 'uuid.UUID'],
2535
2537
  desired_rse_ids: set[str],
2536
2538
  *,
2537
2539
  session: "Session",
@@ -2609,7 +2611,7 @@ def set_transfer_limit(
2609
2611
  waitings: Optional[int] = None,
2610
2612
  *,
2611
2613
  session: "Session",
2612
- ) -> uuid.UUID:
2614
+ ) -> 'uuid.UUID':
2613
2615
  """
2614
2616
  Create or update a transfer limit
2615
2617
 
@@ -2991,12 +2993,12 @@ def get_source_rse(
2991
2993
 
2992
2994
  @stream_session
2993
2995
  def list_requests(
2994
- src_rse_ids: Sequence[str],
2995
- dst_rse_ids: Sequence[str],
2996
- states: Optional[Sequence[RequestState]] = None,
2996
+ src_rse_ids: 'Sequence[str]',
2997
+ dst_rse_ids: 'Sequence[str]',
2998
+ states: Optional['Sequence[RequestState]'] = None,
2997
2999
  *,
2998
3000
  session: "Session"
2999
- ) -> Iterator[models.Request]:
3001
+ ) -> 'Iterator[models.Request]':
3000
3002
  """
3001
3003
  List all requests in a specific state from a source RSE to a destination RSE.
3002
3004
 
@@ -3021,14 +3023,14 @@ def list_requests(
3021
3023
 
3022
3024
  @stream_session
3023
3025
  def list_requests_history(
3024
- src_rse_ids: Sequence[str],
3025
- dst_rse_ids: Sequence[str],
3026
- states: Optional[Sequence[RequestState]] = None,
3026
+ src_rse_ids: 'Sequence[str]',
3027
+ dst_rse_ids: 'Sequence[str]',
3028
+ states: Optional['Sequence[RequestState]'] = None,
3027
3029
  offset: Optional[int] = None,
3028
3030
  limit: Optional[int] = None,
3029
3031
  *,
3030
3032
  session: "Session"
3031
- ) -> Iterator[models.RequestHistory]:
3033
+ ) -> 'Iterator[models.RequestHistory]':
3032
3034
  """
3033
3035
  List all historical requests in a specific state from a source RSE to a destination RSE.
3034
3036