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
@@ -15,7 +15,6 @@
15
15
  """
16
16
  This daemon consumes tracer messages from ActiveMQ and updates the atime for replicas.
17
17
  """
18
-
19
18
  import functools
20
19
  import logging
21
20
  import re
@@ -26,13 +25,13 @@ from json import loads as jloads
26
25
  from queue import Queue
27
26
  from threading import Event, Thread
28
27
  from time import time
29
- from typing import TYPE_CHECKING, Optional
28
+ from typing import TYPE_CHECKING
30
29
 
31
30
  import rucio.db.sqla.util
32
- from rucio.common.config import config_get, config_get_bool, config_get_int, config_get_list
31
+ from rucio.common.config import config_get, config_get_int, config_get_list
33
32
  from rucio.common.exception import DatabaseException, RSENotFound
34
- from rucio.common.logging import setup_logging
35
- from rucio.common.stomp_utils import StompConnectionManager
33
+ from rucio.common.logging import formatted_logger, setup_logging
34
+ from rucio.common.stomp_utils import ListenerBase, StompConnectionManager
36
35
  from rucio.common.stopwatch import Stopwatch
37
36
  from rucio.common.types import InternalAccount, InternalScope, LoggerFunction
38
37
  from rucio.core.did import list_parent_dids, touch_dids
@@ -47,9 +46,10 @@ if TYPE_CHECKING:
47
46
  from collections.abc import Set
48
47
  from types import FrameType
49
48
 
50
- from stomp import Connection
51
49
  from stomp.utils import Frame
52
50
 
51
+ from rucio.common.stomp_utils import Connection
52
+
53
53
 
54
54
  logging.getLogger("stomp").setLevel(logging.CRITICAL)
55
55
 
@@ -57,23 +57,20 @@ METRICS = MetricManager(module=__name__)
57
57
  graceful_stop = Event()
58
58
 
59
59
 
60
- class AMQConsumer:
60
+ class AMQConsumer(ListenerBase):
61
61
  """ActiveMQ message consumer"""
62
62
 
63
- def __init__(
64
- self,
65
- broker: str,
66
- conn: "Connection",
67
- queue: str,
68
- chunksize: int,
69
- subscription_id: str,
70
- excluded_usrdns: "Set[str]",
71
- dataset_queue: Queue,
72
- bad_files_patterns: list[re.Pattern],
73
- logger: LoggerFunction = logging.log
74
- ):
75
- self.__broker = broker
76
- self.__conn = conn
63
+ def __init__(self,
64
+ conn: "Connection",
65
+ queue: str,
66
+ chunksize: int,
67
+ subscription_id: str,
68
+ excluded_usrdns: "Set[str]",
69
+ dataset_queue: Queue,
70
+ bad_files_patterns: list[re.Pattern],
71
+ logger: LoggerFunction = logging.log,
72
+ **kwargs: dict) -> None:
73
+ super().__init__(conn=conn, logger=logger, **kwargs)
77
74
  self.__queue = queue
78
75
  self.__reports = []
79
76
  self.__ids = []
@@ -85,15 +82,6 @@ class AMQConsumer:
85
82
  self.__excluded_usrdns = excluded_usrdns
86
83
  self.__dataset_queue = dataset_queue
87
84
  self.__bad_files_patterns = bad_files_patterns
88
- self.__logger = logger
89
-
90
- @METRICS.count_it
91
- def on_heartbeat_timeout(self) -> None:
92
- self.__conn.disconnect()
93
-
94
- @METRICS.count_it
95
- def on_error(self, frame: "Frame") -> None:
96
- self.__logger(logging.ERROR, 'Message receive error: [%s] %s' % (self.__broker, frame.body))
97
85
 
98
86
  @METRICS.count_it
99
87
  def on_message(self, frame: "Frame") -> None:
@@ -107,7 +95,7 @@ class AMQConsumer:
107
95
 
108
96
  try:
109
97
  if appversion == 'dq2':
110
- self.__conn.ack(msg_id, self.__subscription_id)
98
+ self._conn.ack(msg_id, self.__subscription_id)
111
99
  return
112
100
  else:
113
101
  report = jloads(frame.body) # type: ignore
@@ -115,22 +103,26 @@ class AMQConsumer:
115
103
  # message is corrupt, not much to do here
116
104
  # send count to graphite, send ack to broker and return
117
105
  METRICS.counter('json_error').inc()
118
- self.__logger(logging.ERROR, 'json error', exc_info=True)
119
- self.__conn.ack(msg_id, self.__subscription_id)
106
+ self._logger(logging.ERROR, 'json error', exc_info=True)
107
+ self._conn.ack(msg_id, self.__subscription_id)
120
108
  return
121
109
 
122
110
  self.__ids.append(msg_id)
123
111
  self.__reports.append(report)
124
112
 
125
113
  try:
126
- self.__logger(logging.DEBUG, 'message received: %s %s %s' % (str(report['eventType']), report['filename'], report['remoteSite']))
114
+ self._logger(logging.DEBUG,
115
+ "message received: %s %s %s",
116
+ str(report['eventType']),
117
+ report['filename'],
118
+ report['remoteSite'])
127
119
  except Exception:
128
120
  pass
129
121
 
130
122
  if len(self.__ids) >= self.__chunksize:
131
123
  self.__update_atime()
132
124
  for msg_id in self.__ids:
133
- self.__conn.ack(msg_id, self.__subscription_id)
125
+ self._conn.ack(msg_id, self.__subscription_id)
134
126
 
135
127
  self.__reports = []
136
128
  self.__ids = []
@@ -153,16 +145,19 @@ class AMQConsumer:
153
145
  if 'stateReason' in report and report['stateReason'] and isinstance(report['stateReason'], str) and pattern.match(report['stateReason']):
154
146
  reason = report['stateReason'][:255]
155
147
  if 'url' not in report or not report['url']:
156
- self.__logger(logging.ERROR, 'Missing url in the following trace : ' + str(report))
148
+ self._logger(logging.ERROR, 'Missing url in the following trace : ' + str(report))
157
149
  else:
158
150
  try:
159
- pfn = report['url']
160
- declare_bad_file_replicas([pfn, ], reason=reason, issuer=InternalAccount('root', vo=report['vo']), status=BadFilesStatus.SUSPICIOUS)
161
- self.__logger(logging.INFO, 'Declare suspicious file %s with reason %s' % (report['url'], reason))
151
+ surl = report['url']
152
+ declare_bad_file_replicas([surl, ], reason=reason, issuer=InternalAccount('root', vo=report['vo']), status=BadFilesStatus.SUSPICIOUS)
153
+ self._logger(logging.INFO,
154
+ "Declare suspicious file %s with reason %s",
155
+ report['url'],
156
+ reason)
162
157
  except Exception as error:
163
- self.__logger(logging.ERROR, 'Failed to declare suspicious file' + str(error))
158
+ self._logger(logging.ERROR, 'Failed to declare suspicious file' + str(error))
164
159
  except Exception as error:
165
- self.__logger(logging.ERROR, 'Problem with bad trace : %s . Error %s' % (str(report), str(error)))
160
+ self._logger(logging.ERROR, 'Problem with bad trace : %s . Error %s', str(report), str(error))
166
161
 
167
162
  # check if scope in report. if not skip this one.
168
163
  if 'scope' not in report:
@@ -225,7 +220,7 @@ class AMQConsumer:
225
220
  try:
226
221
  rse_id = get_rse_id(rse=rse, vo=report['vo'])
227
222
  except RSENotFound:
228
- self.__logger(logging.WARNING, "Cannot lookup rse_id for %s. Will skip this report.", rse)
223
+ self._logger(logging.WARNING, "Cannot lookup rse_id for %s. Will skip this report.", rse)
229
224
  METRICS.counter('rse_not_found').inc()
230
225
  continue
231
226
  replicas.append({'name': report['filename'], 'scope': report['scope'], 'rse': rse, 'rse_id': rse_id, 'accessed_at': datetime.utcfromtimestamp(report['traceTimeentryUnix']),
@@ -241,7 +236,7 @@ class AMQConsumer:
241
236
  try:
242
237
  rse_id = get_rse_id(rse=rse, vo=report['vo'])
243
238
  except RSENotFound:
244
- self.__logger(logging.WARNING, "Cannot lookup rse_id for %s.", rse)
239
+ self._logger(logging.WARNING, "Cannot lookup rse_id for %s.", rse)
245
240
  METRICS.counter('rse_not_found').inc()
246
241
  if 'datasetScope' in report:
247
242
  self.__dataset_queue.put({'scope': InternalScope(report['datasetScope'], vo=report['vo']),
@@ -259,11 +254,11 @@ class AMQConsumer:
259
254
  'accessed_at': datetime.utcfromtimestamp(report['traceTimeentryUnix'])})
260
255
 
261
256
  except (KeyError, AttributeError):
262
- self.__logger(logging.ERROR, "Cannot handle report.", exc_info=True)
257
+ self._logger(logging.ERROR, "Cannot handle report.", exc_info=True)
263
258
  METRICS.counter('report_error').inc()
264
259
  continue
265
260
  except Exception:
266
- self.__logger(logging.ERROR, "Exception", exc_info=True)
261
+ self._logger(logging.ERROR, "Exception", exc_info=True)
267
262
  continue
268
263
 
269
264
  for did in list_parent_dids(report['scope'], report['filename']):
@@ -276,15 +271,15 @@ class AMQConsumer:
276
271
  try:
277
272
  rse_id = get_rse_id(rse=rse, vo=report['vo'])
278
273
  except RSENotFound:
279
- self.__logger(logging.WARNING, "Cannot lookup rse_id for %s. Will skip this report.", rse)
274
+ self._logger(logging.WARNING, "Cannot lookup rse_id for %s. Will skip this report.", rse)
280
275
  METRICS.counter('rse_not_found').inc()
281
276
  continue
282
277
  self.__dataset_queue.put({'scope': did['scope'], 'name': did['name'], 'did_type': did['type'], 'rse_id': rse_id, 'accessed_at': datetime.utcfromtimestamp(report['traceTimeentryUnix'])})
283
278
 
284
- if not len(replicas):
279
+ if not replicas:
285
280
  return
286
281
 
287
- self.__logger(logging.DEBUG, "trying to update replicas: %s", replicas)
282
+ self._logger(logging.DEBUG, "trying to update replicas: %s", replicas)
288
283
 
289
284
  stopwatch = Stopwatch()
290
285
  try:
@@ -301,25 +296,50 @@ class AMQConsumer:
301
296
  'eventVersion': replica['eventVersion']}
302
297
  if replica['scope'].vo != 'def':
303
298
  resubmit['vo'] = replica['scope'].vo
304
- self.__conn.send(body=jdumps(resubmit), destination=self.__queue, headers={'appversion': 'rucio', 'resubmitted': '1'})
299
+ self._conn.send(body=jdumps(resubmit), destination=self.__queue, headers={'appversion': 'rucio', 'resubmitted': '1'})
305
300
  METRICS.counter('sent_resubmitted').inc()
306
301
  METRICS.timer('update_atime').observe(stopwatch.elapsed)
307
302
  except Exception:
308
- self.__logger(logging.ERROR, "Cannot update replicas.", exc_info=True)
303
+ self._logger(logging.ERROR, "Cannot update replicas.", exc_info=True)
309
304
  METRICS.counter('update_error').inc()
310
305
 
311
306
  METRICS.counter('updated_replicas').inc()
312
307
 
313
308
 
314
- def kronos_file(
315
- once: bool = False,
316
- dataset_queue: Optional[Queue] = None,
317
- sleep_time: int = 60
318
- ) -> None:
309
+ def kronos_file(once: bool = False,
310
+ dataset_queue: "Queue | None" = None,
311
+ sleep_time: int = 60,
312
+ logger: LoggerFunction = logging.log) -> None:
319
313
  """
320
314
  Main loop to consume tracer reports.
321
315
  """
322
- stomp_conn_mngr = StompConnectionManager()
316
+ bad_files_patterns = []
317
+ try:
318
+ patterns = config_get_list(section='kronos', option='bad_files_patterns', session=None)
319
+ for pat in patterns:
320
+ bad_files_patterns.append(re.compile(pat.strip()))
321
+ except (NoOptionError, NoSectionError, RuntimeError):
322
+ logger(logging.ERROR, "Failed to get bad_file_patterns")
323
+ bad_files_patterns.clear()
324
+ except Exception as error:
325
+ logger(logging.ERROR, f'Failed to get bad_file_patterns {str(error)}')
326
+ bad_files_patterns.clear()
327
+
328
+ excluded_usrdns = set(config_get('tracer-kronos', 'excluded_usrdns').split(','))
329
+
330
+ subscription_id = config_get('tracer-kronos', 'subscription_id')
331
+ stomp_conn_mngr = StompConnectionManager(config_section='tracer-kronos',
332
+ logger=logger)
333
+ stomp_conn_mngr.set_listener_factory('rucio-tracer-kronos',
334
+ AMQConsumer,
335
+ queue=config_get('tracer-kronos', 'queue'),
336
+ chunksize=config_get_int('tracer-kronos', 'chunksize'),
337
+ subscription_id=subscription_id,
338
+ excluded_usrdns=excluded_usrdns,
339
+ dataset_queue=dataset_queue,
340
+ bad_files_patterns=bad_files_patterns,
341
+ heartbeats=stomp_conn_mngr.config.heartbeats)
342
+
323
343
  run_daemon(
324
344
  once=once,
325
345
  graceful_stop=graceful_stop,
@@ -336,74 +356,20 @@ def kronos_file(
336
356
  stomp_conn_mngr.disconnect()
337
357
 
338
358
 
339
- def run_once_kronos_file(heartbeat_handler: HeartbeatHandler, stomp_conn_mngr: StompConnectionManager, dataset_queue: Queue, sleep_time: int, **kwargs) -> None:
359
+ def run_once_kronos_file(heartbeat_handler: HeartbeatHandler,
360
+ stomp_conn_mngr: StompConnectionManager,
361
+ dataset_queue: Queue,
362
+ sleep_time: int,
363
+ **kwargs: dict) -> None:
340
364
  """
341
365
  Run the amq consumer once.
342
366
  """
343
367
  _, _, logger = heartbeat_handler.live()
344
368
 
345
- chunksize = config_get_int('tracer-kronos', 'chunksize')
346
- prefetch_size = config_get_int('tracer-kronos', 'prefetch_size')
347
- subscription_id = config_get('tracer-kronos', 'subscription_id')
348
- # Load bad file patterns from config
349
- try:
350
- bad_files_patterns = []
351
- pattern = config_get(section='kronos', option='bad_files_patterns', session=None)
352
- pattern = str(pattern)
353
- patterns = pattern.split(",")
354
- for pat in patterns:
355
- bad_files_patterns.append(re.compile(pat.strip()))
356
- except (NoOptionError, NoSectionError, RuntimeError):
357
- bad_files_patterns = []
358
- except Exception as error:
359
- logger.error(f'Failed to get bad_file_patterns {str(error)}')
360
- bad_files_patterns = []
361
-
362
- use_ssl = config_get_bool('tracer-kronos', 'use_ssl', default=True, raise_exception=False)
363
- if not use_ssl:
364
- username = config_get('tracer-kronos', 'username')
365
- password = config_get('tracer-kronos', 'password')
366
-
367
- excluded_usrdns = set(config_get('tracer-kronos', 'excluded_usrdns').split(','))
368
- vhost = config_get('tracer-kronos', 'broker_virtual_host', raise_exception=False)
369
-
370
- brokers_alias = config_get_list('tracer-kronos', 'brokers')
371
- port = config_get_int('tracer-kronos', 'port')
372
- reconnect_attempts = config_get_int('tracer-kronos', 'reconnect_attempts')
373
- ssl_key_file = config_get('tracer-kronos', 'ssl_key_file', raise_exception=False)
374
- ssl_cert_file = config_get('tracer-kronos', 'ssl_cert_file', raise_exception=False)
375
-
376
- created_conns, _ = stomp_conn_mngr.re_configure(
377
- brokers=brokers_alias,
378
- port=port,
379
- use_ssl=use_ssl,
380
- vhost=vhost,
381
- reconnect_attempts=reconnect_attempts,
382
- ssl_key_file=ssl_key_file,
383
- ssl_cert_file=ssl_cert_file,
384
- timeout=sleep_time,
385
- heartbeats=(0, 5000),
386
- logger=logger,
387
- )
388
-
389
- for conn in created_conns:
390
- if not conn.is_connected():
391
- logger(logging.INFO, 'connecting to %s' % str(conn.transport._Transport__host_and_ports[0]))
392
- METRICS.counter('reconnect.{host}').labels(host=conn.transport._Transport__host_and_ports[0][0]).inc()
393
- conn.set_listener('rucio-tracer-kronos', AMQConsumer(broker=conn.transport._Transport__host_and_ports[0],
394
- conn=conn,
395
- queue=config_get('tracer-kronos', 'queue'),
396
- chunksize=chunksize,
397
- subscription_id=subscription_id,
398
- excluded_usrdns=excluded_usrdns,
399
- dataset_queue=dataset_queue,
400
- bad_files_patterns=bad_files_patterns,
401
- logger=logger))
402
- if not use_ssl:
403
- conn.connect(username, password)
404
- else:
405
- conn.connect()
406
- conn.subscribe(destination=config_get('tracer-kronos', 'queue'), ack='client-individual', id=subscription_id, headers={'activemq.prefetchSize': prefetch_size})
369
+ stomp_conn_mngr.subscribe(id_=config_get('tracer-kronos', 'subscription_id'),
370
+ ack='client-individual',
371
+ destination=config_get('tracer-kronos', 'queue'),
372
+ headers={'activemq.prefetchSize': config_get_int('tracer-kronos', 'prefetch_size')})
407
373
 
408
374
 
409
375
  def kronos_dataset(dataset_queue: Queue, once: bool = False, sleep_time: int = 60) -> None:
@@ -422,10 +388,16 @@ def kronos_dataset(dataset_queue: Queue, once: bool = False, sleep_time: int = 6
422
388
  )
423
389
 
424
390
  # once again for potential backlog
425
- run_once_kronos_dataset(dataset_queue=dataset_queue, return_values=return_values, heartbeat_handler=return_values['heartbeat_handler'], sleep_time=sleep_time)
391
+ run_once_kronos_dataset(dataset_queue=dataset_queue,
392
+ return_values=return_values,
393
+ heartbeat_handler=return_values['heartbeat_handler'],
394
+ sleep_time=sleep_time)
426
395
 
427
396
 
428
- def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat_handler: HeartbeatHandler, **kwargs) -> None:
397
+ def run_once_kronos_dataset(dataset_queue: Queue,
398
+ return_values: dict,
399
+ heartbeat_handler: "HeartbeatHandler | None",
400
+ **kwargs) -> None:
429
401
  if heartbeat_handler is None:
430
402
  if "heartbeat_handler" not in return_values.keys():
431
403
  return_values["heartbeat_handler"] = HeartbeatHandler("kronos-dataset", 10)
@@ -458,7 +430,7 @@ def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat
458
430
  total, failed, start = 0, 0, time()
459
431
  for did, accessed_at in datasets.items():
460
432
  scope, name = did.split(':')
461
- scope = InternalScope(scope, fromExternal=False)
433
+ scope = InternalScope(scope, from_external=False)
462
434
  update_did = {'scope': scope, 'name': name, 'type': DIDType.DATASET, 'accessed_at': accessed_at}
463
435
  # if update fails, put back in queue and retry next time
464
436
  if not touch_dids((update_did,)):
@@ -471,7 +443,7 @@ def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat
471
443
  total, failed, start = 0, 0, time()
472
444
  for did, rses in dslocks.items():
473
445
  scope, name = did.split(':')
474
- scope = InternalScope(scope, fromExternal=False)
446
+ scope = InternalScope(scope, from_external=False)
475
447
  for rse, accessed_at in rses.items():
476
448
  update_dslock = {'scope': scope, 'name': name, 'rse_id': rse, 'accessed_at': accessed_at}
477
449
  # if update fails, put back in queue and retry next time
@@ -484,7 +456,7 @@ def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat
484
456
  total, failed, start = 0, 0, time()
485
457
  for did, rses in dslocks.items():
486
458
  scope, name = did.split(':')
487
- scope = InternalScope(scope, fromExternal=False)
459
+ scope = InternalScope(scope, from_external=False)
488
460
  for rse, accessed_at in rses.items():
489
461
  update_dslock = {'scope': scope, 'name': name, 'rse_id': rse, 'accessed_at': accessed_at}
490
462
  # if update fails, put back in queue and retry next time
@@ -495,7 +467,7 @@ def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat
495
467
  logger(logging.INFO, 'update done for %d collection replicas, %d failed (%ds)' % (total, failed, time() - start))
496
468
 
497
469
 
498
- def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
470
+ def stop(signum: "int | None" = None, frame: "FrameType | None" = None) -> None:
499
471
  """
500
472
  Graceful exit.
501
473
  """
@@ -506,31 +478,34 @@ def run(
506
478
  once: bool = False,
507
479
  threads: int = 1,
508
480
  sleep_time_datasets: int = 60,
509
- sleep_time_files: int = 60
510
- ) -> None:
481
+ sleep_time_files: int = 60) -> None:
511
482
  """
512
483
  Starts up the consumer threads
513
484
  """
514
485
  setup_logging(process_name='tracer-kronos')
486
+ logger = formatted_logger(logging.log, 'Kronos %s')
515
487
 
516
488
  if rucio.db.sqla.util.is_old_db():
517
489
  raise DatabaseException('Database was not updated, daemon won\'t start')
518
490
 
519
491
  dataset_queue = Queue()
520
- logging.info('starting tracer consumer threads')
492
+ logger(logging.INFO, 'starting tracer consumer threads')
521
493
 
522
494
  thread_list = []
523
- for _ in range(0, threads):
524
- thread_list.append(Thread(target=kronos_file, kwargs={'once': once,
525
- 'sleep_time': sleep_time_files,
526
- 'dataset_queue': dataset_queue}))
527
- thread_list.append(Thread(target=kronos_dataset, kwargs={'once': once,
528
- 'sleep_time': sleep_time_datasets,
529
- 'dataset_queue': dataset_queue}))
530
-
531
- [thread.start() for thread in thread_list]
532
-
533
- logging.info('waiting for interrupts')
534
-
535
- while len(thread_list) > 0:
536
- thread_list = [thread.join(timeout=3) for thread in thread_list if thread and thread.is_alive()]
495
+ for _ in range(threads):
496
+ krf_thread = Thread(target=kronos_file, kwargs={'once': once,
497
+ 'logger': logger,
498
+ 'sleep_time': sleep_time_files,
499
+ 'dataset_queue': dataset_queue})
500
+ krf_thread.start()
501
+ krd_thread = Thread(target=kronos_dataset, kwargs={'once': once,
502
+ 'sleep_time': sleep_time_datasets,
503
+ 'dataset_queue': dataset_queue})
504
+ krd_thread.start()
505
+ thread_list.append(krf_thread)
506
+ thread_list.append(krd_thread)
507
+
508
+ logger(logging.INFO, 'waiting for interrupts')
509
+
510
+ while [thread.join(timeout=3.) for thread in thread_list if thread.is_alive()]:
511
+ pass
@@ -199,3 +199,8 @@ class SubscriptionState(Enum):
199
199
  class TransferLimitDirection(Enum):
200
200
  SOURCE = 'S'
201
201
  DESTINATION = 'D'
202
+
203
+
204
+ class DatabaseOperationType(Enum):
205
+ READ = 'read'
206
+ WRITE = 'write'
@@ -38,7 +38,7 @@ def upgrade():
38
38
  add_column("rses", sa.Column("availability_write", sa.Boolean, server_default=true()), schema=schema)
39
39
  add_column("rses", sa.Column("availability_delete", sa.Boolean, server_default=true()), schema=schema)
40
40
 
41
- RSE = sa.sql.table(
41
+ rse = sa.sql.table(
42
42
  "rses",
43
43
  sa.Column("id", GUID()),
44
44
  sa.Column("availability", sa.Integer),
@@ -50,9 +50,9 @@ def upgrade():
50
50
 
51
51
  conn = get_bind()
52
52
 
53
- conn.execute(RSE.update().where(RSE.c.availability.in_([0, 1, 2, 3])).values({"availability_read": False}))
54
- conn.execute(RSE.update().where(RSE.c.availability.in_([0, 1, 4, 5])).values({"availability_write": False}))
55
- conn.execute(RSE.update().where(RSE.c.availability.in_([0, 2, 4, 6])).values({"availability_delete": False}))
53
+ conn.execute(rse.update().where(rse.c.availability.in_([0, 1, 2, 3])).values({"availability_read": False}))
54
+ conn.execute(rse.update().where(rse.c.availability.in_([0, 1, 4, 5])).values({"availability_write": False}))
55
+ conn.execute(rse.update().where(rse.c.availability.in_([0, 2, 4, 6])).values({"availability_delete": False}))
56
56
 
57
57
 
58
58
  def downgrade():
@@ -0,0 +1,37 @@
1
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Increase OAuthRequest.redirect_msg length""" # noqa: D400, D415
16
+
17
+ import sqlalchemy as sa
18
+ from alembic import context
19
+ from alembic.op import alter_column
20
+
21
+ # Alembic revision identifiers
22
+ revision = '30d5206e9cad'
23
+ down_revision = 'b0070f3695c8'
24
+
25
+
26
+ def upgrade():
27
+ """Upgrade the database to this revision."""
28
+ if context.get_context().dialect.name in ['oracle', 'mysql', 'postgresql']:
29
+ schema = context.get_context().version_table_schema if context.get_context().version_table_schema else ''
30
+ alter_column('oauth_requests', 'redirect_msg', existing_type=sa.String(2048), type_=sa.String(4000), schema=schema)
31
+
32
+
33
+ def downgrade():
34
+ """Downgrade the database to the previous revision."""
35
+ if context.get_context().dialect.name in ['oracle', 'mysql', 'postgresql']:
36
+ schema = context.get_context().version_table_schema if context.get_context().version_table_schema else ''
37
+ alter_column('oauth_requests', 'redirect_msg', existing_type=sa.String(4000), type_=sa.String(2048), schema=schema)