rucio 32.8.6__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 (481) hide show
  1. rucio/__init__.py +18 -0
  2. rucio/alembicrevision.py +16 -0
  3. rucio/api/__init__.py +14 -0
  4. rucio/api/account.py +266 -0
  5. rucio/api/account_limit.py +287 -0
  6. rucio/api/authentication.py +302 -0
  7. rucio/api/config.py +218 -0
  8. rucio/api/credential.py +60 -0
  9. rucio/api/did.py +726 -0
  10. rucio/api/dirac.py +71 -0
  11. rucio/api/exporter.py +60 -0
  12. rucio/api/heartbeat.py +62 -0
  13. rucio/api/identity.py +160 -0
  14. rucio/api/importer.py +46 -0
  15. rucio/api/lifetime_exception.py +95 -0
  16. rucio/api/lock.py +131 -0
  17. rucio/api/meta.py +85 -0
  18. rucio/api/permission.py +72 -0
  19. rucio/api/quarantined_replica.py +69 -0
  20. rucio/api/replica.py +528 -0
  21. rucio/api/request.py +220 -0
  22. rucio/api/rse.py +601 -0
  23. rucio/api/rule.py +335 -0
  24. rucio/api/scope.py +89 -0
  25. rucio/api/subscription.py +255 -0
  26. rucio/api/temporary_did.py +49 -0
  27. rucio/api/vo.py +112 -0
  28. rucio/client/__init__.py +16 -0
  29. rucio/client/accountclient.py +413 -0
  30. rucio/client/accountlimitclient.py +155 -0
  31. rucio/client/baseclient.py +929 -0
  32. rucio/client/client.py +77 -0
  33. rucio/client/configclient.py +113 -0
  34. rucio/client/credentialclient.py +54 -0
  35. rucio/client/didclient.py +691 -0
  36. rucio/client/diracclient.py +48 -0
  37. rucio/client/downloadclient.py +1674 -0
  38. rucio/client/exportclient.py +44 -0
  39. rucio/client/fileclient.py +51 -0
  40. rucio/client/importclient.py +42 -0
  41. rucio/client/lifetimeclient.py +74 -0
  42. rucio/client/lockclient.py +99 -0
  43. rucio/client/metaclient.py +137 -0
  44. rucio/client/pingclient.py +45 -0
  45. rucio/client/replicaclient.py +444 -0
  46. rucio/client/requestclient.py +109 -0
  47. rucio/client/rseclient.py +664 -0
  48. rucio/client/ruleclient.py +287 -0
  49. rucio/client/scopeclient.py +88 -0
  50. rucio/client/subscriptionclient.py +161 -0
  51. rucio/client/touchclient.py +78 -0
  52. rucio/client/uploadclient.py +871 -0
  53. rucio/common/__init__.py +14 -0
  54. rucio/common/cache.py +74 -0
  55. rucio/common/config.py +796 -0
  56. rucio/common/constants.py +92 -0
  57. rucio/common/constraints.py +18 -0
  58. rucio/common/didtype.py +187 -0
  59. rucio/common/dumper/__init__.py +306 -0
  60. rucio/common/dumper/consistency.py +449 -0
  61. rucio/common/dumper/data_models.py +325 -0
  62. rucio/common/dumper/path_parsing.py +65 -0
  63. rucio/common/exception.py +1092 -0
  64. rucio/common/extra.py +37 -0
  65. rucio/common/logging.py +404 -0
  66. rucio/common/pcache.py +1387 -0
  67. rucio/common/policy.py +84 -0
  68. rucio/common/schema/__init__.py +143 -0
  69. rucio/common/schema/atlas.py +411 -0
  70. rucio/common/schema/belleii.py +406 -0
  71. rucio/common/schema/cms.py +478 -0
  72. rucio/common/schema/domatpc.py +399 -0
  73. rucio/common/schema/escape.py +424 -0
  74. rucio/common/schema/generic.py +431 -0
  75. rucio/common/schema/generic_multi_vo.py +410 -0
  76. rucio/common/schema/icecube.py +404 -0
  77. rucio/common/schema/lsst.py +423 -0
  78. rucio/common/stomp_utils.py +160 -0
  79. rucio/common/stopwatch.py +56 -0
  80. rucio/common/test_rucio_server.py +148 -0
  81. rucio/common/types.py +158 -0
  82. rucio/common/utils.py +1946 -0
  83. rucio/core/__init__.py +14 -0
  84. rucio/core/account.py +426 -0
  85. rucio/core/account_counter.py +171 -0
  86. rucio/core/account_limit.py +357 -0
  87. rucio/core/authentication.py +563 -0
  88. rucio/core/config.py +386 -0
  89. rucio/core/credential.py +218 -0
  90. rucio/core/did.py +3102 -0
  91. rucio/core/did_meta_plugins/__init__.py +250 -0
  92. rucio/core/did_meta_plugins/did_column_meta.py +326 -0
  93. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +116 -0
  94. rucio/core/did_meta_plugins/filter_engine.py +573 -0
  95. rucio/core/did_meta_plugins/json_meta.py +215 -0
  96. rucio/core/did_meta_plugins/mongo_meta.py +199 -0
  97. rucio/core/did_meta_plugins/postgres_meta.py +317 -0
  98. rucio/core/dirac.py +208 -0
  99. rucio/core/distance.py +164 -0
  100. rucio/core/exporter.py +59 -0
  101. rucio/core/heartbeat.py +263 -0
  102. rucio/core/identity.py +290 -0
  103. rucio/core/importer.py +248 -0
  104. rucio/core/lifetime_exception.py +377 -0
  105. rucio/core/lock.py +474 -0
  106. rucio/core/message.py +241 -0
  107. rucio/core/meta.py +190 -0
  108. rucio/core/monitor.py +441 -0
  109. rucio/core/naming_convention.py +154 -0
  110. rucio/core/nongrid_trace.py +124 -0
  111. rucio/core/oidc.py +1339 -0
  112. rucio/core/permission/__init__.py +107 -0
  113. rucio/core/permission/atlas.py +1333 -0
  114. rucio/core/permission/belleii.py +1076 -0
  115. rucio/core/permission/cms.py +1166 -0
  116. rucio/core/permission/escape.py +1076 -0
  117. rucio/core/permission/generic.py +1128 -0
  118. rucio/core/permission/generic_multi_vo.py +1148 -0
  119. rucio/core/quarantined_replica.py +190 -0
  120. rucio/core/replica.py +3627 -0
  121. rucio/core/replica_sorter.py +368 -0
  122. rucio/core/request.py +2241 -0
  123. rucio/core/rse.py +1835 -0
  124. rucio/core/rse_counter.py +155 -0
  125. rucio/core/rse_expression_parser.py +460 -0
  126. rucio/core/rse_selector.py +277 -0
  127. rucio/core/rule.py +3419 -0
  128. rucio/core/rule_grouping.py +1473 -0
  129. rucio/core/scope.py +152 -0
  130. rucio/core/subscription.py +316 -0
  131. rucio/core/temporary_did.py +188 -0
  132. rucio/core/topology.py +448 -0
  133. rucio/core/trace.py +361 -0
  134. rucio/core/transfer.py +1233 -0
  135. rucio/core/vo.py +151 -0
  136. rucio/core/volatile_replica.py +123 -0
  137. rucio/daemons/__init__.py +14 -0
  138. rucio/daemons/abacus/__init__.py +14 -0
  139. rucio/daemons/abacus/account.py +106 -0
  140. rucio/daemons/abacus/collection_replica.py +113 -0
  141. rucio/daemons/abacus/rse.py +107 -0
  142. rucio/daemons/atropos/__init__.py +14 -0
  143. rucio/daemons/atropos/atropos.py +243 -0
  144. rucio/daemons/auditor/__init__.py +261 -0
  145. rucio/daemons/auditor/hdfs.py +86 -0
  146. rucio/daemons/auditor/srmdumps.py +284 -0
  147. rucio/daemons/automatix/__init__.py +14 -0
  148. rucio/daemons/automatix/automatix.py +281 -0
  149. rucio/daemons/badreplicas/__init__.py +14 -0
  150. rucio/daemons/badreplicas/minos.py +311 -0
  151. rucio/daemons/badreplicas/minos_temporary_expiration.py +173 -0
  152. rucio/daemons/badreplicas/necromancer.py +200 -0
  153. rucio/daemons/bb8/__init__.py +14 -0
  154. rucio/daemons/bb8/bb8.py +356 -0
  155. rucio/daemons/bb8/common.py +762 -0
  156. rucio/daemons/bb8/nuclei_background_rebalance.py +147 -0
  157. rucio/daemons/bb8/t2_background_rebalance.py +146 -0
  158. rucio/daemons/c3po/__init__.py +14 -0
  159. rucio/daemons/c3po/algorithms/__init__.py +14 -0
  160. rucio/daemons/c3po/algorithms/simple.py +131 -0
  161. rucio/daemons/c3po/algorithms/t2_free_space.py +125 -0
  162. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +127 -0
  163. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +279 -0
  164. rucio/daemons/c3po/c3po.py +342 -0
  165. rucio/daemons/c3po/collectors/__init__.py +14 -0
  166. rucio/daemons/c3po/collectors/agis.py +108 -0
  167. rucio/daemons/c3po/collectors/free_space.py +62 -0
  168. rucio/daemons/c3po/collectors/jedi_did.py +48 -0
  169. rucio/daemons/c3po/collectors/mock_did.py +46 -0
  170. rucio/daemons/c3po/collectors/network_metrics.py +63 -0
  171. rucio/daemons/c3po/collectors/workload.py +110 -0
  172. rucio/daemons/c3po/utils/__init__.py +14 -0
  173. rucio/daemons/c3po/utils/dataset_cache.py +40 -0
  174. rucio/daemons/c3po/utils/expiring_dataset_cache.py +45 -0
  175. rucio/daemons/c3po/utils/expiring_list.py +63 -0
  176. rucio/daemons/c3po/utils/popularity.py +82 -0
  177. rucio/daemons/c3po/utils/timeseries.py +76 -0
  178. rucio/daemons/cache/__init__.py +14 -0
  179. rucio/daemons/cache/consumer.py +191 -0
  180. rucio/daemons/common.py +391 -0
  181. rucio/daemons/conveyor/__init__.py +14 -0
  182. rucio/daemons/conveyor/common.py +530 -0
  183. rucio/daemons/conveyor/finisher.py +492 -0
  184. rucio/daemons/conveyor/poller.py +372 -0
  185. rucio/daemons/conveyor/preparer.py +198 -0
  186. rucio/daemons/conveyor/receiver.py +206 -0
  187. rucio/daemons/conveyor/stager.py +127 -0
  188. rucio/daemons/conveyor/submitter.py +379 -0
  189. rucio/daemons/conveyor/throttler.py +468 -0
  190. rucio/daemons/follower/__init__.py +14 -0
  191. rucio/daemons/follower/follower.py +97 -0
  192. rucio/daemons/hermes/__init__.py +14 -0
  193. rucio/daemons/hermes/hermes.py +738 -0
  194. rucio/daemons/judge/__init__.py +14 -0
  195. rucio/daemons/judge/cleaner.py +149 -0
  196. rucio/daemons/judge/evaluator.py +172 -0
  197. rucio/daemons/judge/injector.py +154 -0
  198. rucio/daemons/judge/repairer.py +144 -0
  199. rucio/daemons/oauthmanager/__init__.py +14 -0
  200. rucio/daemons/oauthmanager/oauthmanager.py +199 -0
  201. rucio/daemons/reaper/__init__.py +14 -0
  202. rucio/daemons/reaper/dark_reaper.py +272 -0
  203. rucio/daemons/reaper/light_reaper.py +255 -0
  204. rucio/daemons/reaper/reaper.py +701 -0
  205. rucio/daemons/replicarecoverer/__init__.py +14 -0
  206. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +487 -0
  207. rucio/daemons/storage/__init__.py +14 -0
  208. rucio/daemons/storage/consistency/__init__.py +14 -0
  209. rucio/daemons/storage/consistency/actions.py +753 -0
  210. rucio/daemons/tracer/__init__.py +14 -0
  211. rucio/daemons/tracer/kronos.py +513 -0
  212. rucio/daemons/transmogrifier/__init__.py +14 -0
  213. rucio/daemons/transmogrifier/transmogrifier.py +753 -0
  214. rucio/daemons/undertaker/__init__.py +14 -0
  215. rucio/daemons/undertaker/undertaker.py +137 -0
  216. rucio/db/__init__.py +14 -0
  217. rucio/db/sqla/__init__.py +38 -0
  218. rucio/db/sqla/constants.py +192 -0
  219. rucio/db/sqla/migrate_repo/__init__.py +14 -0
  220. rucio/db/sqla/migrate_repo/env.py +111 -0
  221. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +71 -0
  222. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +50 -0
  223. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +61 -0
  224. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +46 -0
  225. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +93 -0
  226. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +78 -0
  227. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +46 -0
  228. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +53 -0
  229. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +69 -0
  230. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +42 -0
  231. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +46 -0
  232. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +61 -0
  233. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +42 -0
  234. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +141 -0
  235. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +75 -0
  236. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +75 -0
  237. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +46 -0
  238. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +51 -0
  239. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +135 -0
  240. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +65 -0
  241. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +42 -0
  242. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +66 -0
  243. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +54 -0
  244. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +43 -0
  245. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +46 -0
  246. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +47 -0
  247. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +54 -0
  248. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +39 -0
  249. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +48 -0
  250. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +47 -0
  251. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +48 -0
  252. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +59 -0
  253. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +47 -0
  254. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +72 -0
  255. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +46 -0
  256. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +45 -0
  257. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +48 -0
  258. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +48 -0
  259. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +42 -0
  260. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +69 -0
  261. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +46 -0
  262. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +78 -0
  263. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +62 -0
  264. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +74 -0
  265. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +44 -0
  266. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +67 -0
  267. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +134 -0
  268. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +58 -0
  269. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +79 -0
  270. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +61 -0
  271. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +45 -0
  272. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +46 -0
  273. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +65 -0
  274. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +42 -0
  275. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +46 -0
  276. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +46 -0
  277. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +80 -0
  278. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +43 -0
  279. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +61 -0
  280. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +47 -0
  281. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +46 -0
  282. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +52 -0
  283. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +42 -0
  284. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +65 -0
  285. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +46 -0
  286. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +47 -0
  287. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +45 -0
  288. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +46 -0
  289. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +48 -0
  290. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +50 -0
  291. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +59 -0
  292. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +48 -0
  293. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +108 -0
  294. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +57 -0
  295. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +51 -0
  296. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +50 -0
  297. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +46 -0
  298. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +42 -0
  299. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +93 -0
  300. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +73 -0
  301. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +52 -0
  302. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +45 -0
  303. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +46 -0
  304. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +54 -0
  305. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +48 -0
  306. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +70 -0
  307. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +48 -0
  308. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +95 -0
  309. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +55 -0
  310. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +74 -0
  311. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +78 -0
  312. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +49 -0
  313. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +124 -0
  314. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +60 -0
  315. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +53 -0
  316. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +56 -0
  317. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +67 -0
  318. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +50 -0
  319. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +46 -0
  320. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +92 -0
  321. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +42 -0
  322. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +46 -0
  323. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +147 -0
  324. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +78 -0
  325. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +53 -0
  326. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +74 -0
  327. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +56 -0
  328. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +46 -0
  329. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +68 -0
  330. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +48 -0
  331. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +149 -0
  332. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +106 -0
  333. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +47 -0
  334. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +45 -0
  335. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +105 -0
  336. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +52 -0
  337. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +106 -0
  338. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +30 -0
  339. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +75 -0
  340. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +49 -0
  341. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +45 -0
  342. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +38 -0
  343. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +44 -0
  344. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +46 -0
  345. rucio/db/sqla/models.py +1834 -0
  346. rucio/db/sqla/sautils.py +48 -0
  347. rucio/db/sqla/session.py +470 -0
  348. rucio/db/sqla/types.py +207 -0
  349. rucio/db/sqla/util.py +521 -0
  350. rucio/rse/__init__.py +97 -0
  351. rucio/rse/protocols/__init__.py +14 -0
  352. rucio/rse/protocols/cache.py +123 -0
  353. rucio/rse/protocols/dummy.py +112 -0
  354. rucio/rse/protocols/gfal.py +701 -0
  355. rucio/rse/protocols/globus.py +243 -0
  356. rucio/rse/protocols/gsiftp.py +93 -0
  357. rucio/rse/protocols/http_cache.py +83 -0
  358. rucio/rse/protocols/mock.py +124 -0
  359. rucio/rse/protocols/ngarc.py +210 -0
  360. rucio/rse/protocols/posix.py +251 -0
  361. rucio/rse/protocols/protocol.py +530 -0
  362. rucio/rse/protocols/rclone.py +365 -0
  363. rucio/rse/protocols/rfio.py +137 -0
  364. rucio/rse/protocols/srm.py +339 -0
  365. rucio/rse/protocols/ssh.py +414 -0
  366. rucio/rse/protocols/storm.py +207 -0
  367. rucio/rse/protocols/webdav.py +547 -0
  368. rucio/rse/protocols/xrootd.py +295 -0
  369. rucio/rse/rsemanager.py +752 -0
  370. rucio/tests/__init__.py +14 -0
  371. rucio/tests/common.py +244 -0
  372. rucio/tests/common_server.py +132 -0
  373. rucio/transfertool/__init__.py +14 -0
  374. rucio/transfertool/fts3.py +1484 -0
  375. rucio/transfertool/globus.py +200 -0
  376. rucio/transfertool/globus_library.py +182 -0
  377. rucio/transfertool/mock.py +81 -0
  378. rucio/transfertool/transfertool.py +212 -0
  379. rucio/vcsversion.py +11 -0
  380. rucio/version.py +46 -0
  381. rucio/web/__init__.py +14 -0
  382. rucio/web/rest/__init__.py +14 -0
  383. rucio/web/rest/flaskapi/__init__.py +14 -0
  384. rucio/web/rest/flaskapi/authenticated_bp.py +28 -0
  385. rucio/web/rest/flaskapi/v1/__init__.py +14 -0
  386. rucio/web/rest/flaskapi/v1/accountlimits.py +234 -0
  387. rucio/web/rest/flaskapi/v1/accounts.py +1088 -0
  388. rucio/web/rest/flaskapi/v1/archives.py +100 -0
  389. rucio/web/rest/flaskapi/v1/auth.py +1642 -0
  390. rucio/web/rest/flaskapi/v1/common.py +385 -0
  391. rucio/web/rest/flaskapi/v1/config.py +305 -0
  392. rucio/web/rest/flaskapi/v1/credentials.py +213 -0
  393. rucio/web/rest/flaskapi/v1/dids.py +2204 -0
  394. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  395. rucio/web/rest/flaskapi/v1/export.py +77 -0
  396. rucio/web/rest/flaskapi/v1/heartbeats.py +129 -0
  397. rucio/web/rest/flaskapi/v1/identities.py +263 -0
  398. rucio/web/rest/flaskapi/v1/import.py +133 -0
  399. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +315 -0
  400. rucio/web/rest/flaskapi/v1/locks.py +360 -0
  401. rucio/web/rest/flaskapi/v1/main.py +83 -0
  402. rucio/web/rest/flaskapi/v1/meta.py +226 -0
  403. rucio/web/rest/flaskapi/v1/metrics.py +37 -0
  404. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  405. rucio/web/rest/flaskapi/v1/ping.py +89 -0
  406. rucio/web/rest/flaskapi/v1/redirect.py +366 -0
  407. rucio/web/rest/flaskapi/v1/replicas.py +1866 -0
  408. rucio/web/rest/flaskapi/v1/requests.py +841 -0
  409. rucio/web/rest/flaskapi/v1/rses.py +2204 -0
  410. rucio/web/rest/flaskapi/v1/rules.py +824 -0
  411. rucio/web/rest/flaskapi/v1/scopes.py +161 -0
  412. rucio/web/rest/flaskapi/v1/subscriptions.py +646 -0
  413. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  414. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  415. rucio/web/rest/flaskapi/v1/tmp_dids.py +115 -0
  416. rucio/web/rest/flaskapi/v1/traces.py +100 -0
  417. rucio/web/rest/flaskapi/v1/vos.py +280 -0
  418. rucio/web/rest/main.py +19 -0
  419. rucio/web/rest/metrics.py +28 -0
  420. rucio-32.8.6.data/data/rucio/etc/alembic.ini.template +71 -0
  421. rucio-32.8.6.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  422. rucio-32.8.6.data/data/rucio/etc/globus-config.yml.template +5 -0
  423. rucio-32.8.6.data/data/rucio/etc/ldap.cfg.template +30 -0
  424. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  425. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  426. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  427. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  428. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  429. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  430. rucio-32.8.6.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  431. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.atlas.client.template +42 -0
  432. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.template +257 -0
  433. rucio-32.8.6.data/data/rucio/etc/rucio_multi_vo.cfg.template +234 -0
  434. rucio-32.8.6.data/data/rucio/requirements.txt +55 -0
  435. rucio-32.8.6.data/data/rucio/tools/bootstrap.py +34 -0
  436. rucio-32.8.6.data/data/rucio/tools/merge_rucio_configs.py +147 -0
  437. rucio-32.8.6.data/data/rucio/tools/reset_database.py +40 -0
  438. rucio-32.8.6.data/scripts/rucio +2540 -0
  439. rucio-32.8.6.data/scripts/rucio-abacus-account +75 -0
  440. rucio-32.8.6.data/scripts/rucio-abacus-collection-replica +47 -0
  441. rucio-32.8.6.data/scripts/rucio-abacus-rse +79 -0
  442. rucio-32.8.6.data/scripts/rucio-admin +2434 -0
  443. rucio-32.8.6.data/scripts/rucio-atropos +61 -0
  444. rucio-32.8.6.data/scripts/rucio-auditor +199 -0
  445. rucio-32.8.6.data/scripts/rucio-automatix +51 -0
  446. rucio-32.8.6.data/scripts/rucio-bb8 +58 -0
  447. rucio-32.8.6.data/scripts/rucio-c3po +86 -0
  448. rucio-32.8.6.data/scripts/rucio-cache-client +135 -0
  449. rucio-32.8.6.data/scripts/rucio-cache-consumer +43 -0
  450. rucio-32.8.6.data/scripts/rucio-conveyor-finisher +59 -0
  451. rucio-32.8.6.data/scripts/rucio-conveyor-poller +67 -0
  452. rucio-32.8.6.data/scripts/rucio-conveyor-preparer +38 -0
  453. rucio-32.8.6.data/scripts/rucio-conveyor-receiver +44 -0
  454. rucio-32.8.6.data/scripts/rucio-conveyor-stager +77 -0
  455. rucio-32.8.6.data/scripts/rucio-conveyor-submitter +140 -0
  456. rucio-32.8.6.data/scripts/rucio-conveyor-throttler +105 -0
  457. rucio-32.8.6.data/scripts/rucio-dark-reaper +54 -0
  458. rucio-32.8.6.data/scripts/rucio-dumper +159 -0
  459. rucio-32.8.6.data/scripts/rucio-follower +45 -0
  460. rucio-32.8.6.data/scripts/rucio-hermes +55 -0
  461. rucio-32.8.6.data/scripts/rucio-judge-cleaner +90 -0
  462. rucio-32.8.6.data/scripts/rucio-judge-evaluator +138 -0
  463. rucio-32.8.6.data/scripts/rucio-judge-injector +45 -0
  464. rucio-32.8.6.data/scripts/rucio-judge-repairer +45 -0
  465. rucio-32.8.6.data/scripts/rucio-kronos +45 -0
  466. rucio-32.8.6.data/scripts/rucio-light-reaper +53 -0
  467. rucio-32.8.6.data/scripts/rucio-minos +54 -0
  468. rucio-32.8.6.data/scripts/rucio-minos-temporary-expiration +51 -0
  469. rucio-32.8.6.data/scripts/rucio-necromancer +121 -0
  470. rucio-32.8.6.data/scripts/rucio-oauth-manager +64 -0
  471. rucio-32.8.6.data/scripts/rucio-reaper +84 -0
  472. rucio-32.8.6.data/scripts/rucio-replica-recoverer +249 -0
  473. rucio-32.8.6.data/scripts/rucio-storage-consistency-actions +75 -0
  474. rucio-32.8.6.data/scripts/rucio-transmogrifier +78 -0
  475. rucio-32.8.6.data/scripts/rucio-undertaker +77 -0
  476. rucio-32.8.6.dist-info/METADATA +83 -0
  477. rucio-32.8.6.dist-info/RECORD +481 -0
  478. rucio-32.8.6.dist-info/WHEEL +5 -0
  479. rucio-32.8.6.dist-info/licenses/AUTHORS.rst +94 -0
  480. rucio-32.8.6.dist-info/licenses/LICENSE +201 -0
  481. rucio-32.8.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,311 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import functools
17
+ import logging
18
+ import re
19
+ import threading
20
+ from collections.abc import Callable
21
+ from datetime import datetime
22
+ from typing import TYPE_CHECKING
23
+
24
+ import math
25
+ from sqlalchemy.exc import DatabaseError
26
+
27
+ import rucio.db.sqla.util
28
+ from rucio.common.config import config_get_int
29
+ from rucio.common.exception import UnsupportedOperation, DataIdentifierNotFound, ReplicaNotFound, DatabaseException
30
+ from rucio.common.logging import setup_logging
31
+ from rucio.common.utils import chunks
32
+ from rucio.core.did import get_metadata
33
+ from rucio.core.replica import (get_bad_pfns, get_pfn_to_rse, declare_bad_file_replicas,
34
+ get_did_from_pfns, update_replicas_states, bulk_add_bad_replicas,
35
+ bulk_delete_bad_pfns, get_replicas_state)
36
+ from rucio.core.rse import get_rse_name
37
+ from rucio.daemons.common import run_daemon
38
+ from rucio.db.sqla.constants import BadFilesStatus, BadPFNStatus, ReplicaState
39
+ from rucio.db.sqla.session import get_session
40
+
41
+ if TYPE_CHECKING:
42
+ from types import FrameType
43
+ from typing import Optional
44
+
45
+ from rucio.daemons.common import HeartbeatHandler
46
+ from rucio.common.types import InternalAccount
47
+
48
+ graceful_stop = threading.Event()
49
+ DAEMON_NAME = 'minos'
50
+
51
+
52
+ def __classify_bad_pfns(pfns: list) -> tuple[dict, dict]:
53
+ """
54
+ Function that takes a list of PFNs and classify them in 2 dictionaries : bad_replicas and temporary_unvailables
55
+ :param pfns: List of PFNs
56
+
57
+ :returns: Tuple (bad_replicas, temporary_unvailables)
58
+ """
59
+ states_mapping = {BadPFNStatus.BAD: BadFilesStatus.BAD,
60
+ BadPFNStatus.SUSPICIOUS: BadFilesStatus.SUSPICIOUS,
61
+ BadPFNStatus.TEMPORARY_UNAVAILABLE: BadFilesStatus.TEMPORARY_UNAVAILABLE}
62
+ bad_replicas, temporary_unvailables = {}, {}
63
+ for pfn in pfns:
64
+ path = pfn['pfn']
65
+ account = pfn['account']
66
+ reason = pfn['reason']
67
+ expires_at = pfn['expires_at']
68
+ state = states_mapping[pfn['state']]
69
+ if state in [BadFilesStatus.BAD, BadFilesStatus.SUSPICIOUS]:
70
+ if (account, reason, state) not in bad_replicas:
71
+ bad_replicas[(account, reason, state)] = []
72
+ bad_replicas[(account, reason, state)].append(path)
73
+ elif state == BadFilesStatus.TEMPORARY_UNAVAILABLE:
74
+ if (account, reason, expires_at) not in temporary_unvailables:
75
+ temporary_unvailables[(account, reason, expires_at)] = []
76
+ temporary_unvailables[(account, reason, expires_at)].append(path)
77
+ return bad_replicas, temporary_unvailables
78
+
79
+
80
+ def __clean_unknown_replicas(pfns: list, vo: str, logger: "Callable") -> dict:
81
+ """
82
+ Identify from the list of PFNs the one that are unknown and remove them from the bad_pfns table
83
+ :param pfns: List of PFNs
84
+ :param vo: The VO name
85
+ :param logger: The logger
86
+
87
+ :returns: Dictionary cleaned from unkwnon replicas
88
+ """
89
+ schemes = {}
90
+ dict_rse = {}
91
+ unknown_replicas = []
92
+ # Splitting the PFNs by schemes
93
+ for pfn in pfns:
94
+ scheme = pfn.split(':')[0]
95
+ if scheme not in schemes:
96
+ schemes[scheme] = []
97
+ schemes[scheme].append(pfn)
98
+ for scheme in schemes:
99
+ _, tmp_dict_rse, tmp_unknown_replicas = get_pfn_to_rse(schemes[scheme], vo=vo)
100
+ for rse_id in tmp_dict_rse:
101
+ if rse_id not in dict_rse:
102
+ dict_rse[rse_id] = {}
103
+ if scheme not in dict_rse[rse_id]:
104
+ dict_rse[rse_id][scheme] = []
105
+ dict_rse[rse_id][scheme].extend(tmp_dict_rse[rse_id])
106
+ unknown_replicas.extend(tmp_unknown_replicas.get('unknown', []))
107
+ # The replicas in unknown_replicas do not exist, so we flush them from bad_pfns
108
+ if unknown_replicas:
109
+ logger(logging.INFO, 'The following replicas are unknown and will be removed : %s', str(unknown_replicas))
110
+ bulk_delete_bad_pfns(pfns=unknown_replicas, session=None)
111
+ return dict_rse
112
+
113
+
114
+ def __update_temporary_unavailable(chunk: list, reason: str, expires_at: datetime, account: "InternalAccount", logger: "Callable") -> None:
115
+ """
116
+ Update temporary unavailable replicas one by one
117
+ :param chunk: List of unvailable replicas to update
118
+ :param reason: Reason of the temporary unavailable replica
119
+ :param expires_at: Expiration date of the temporary unavailability
120
+ :param account: Account who declared the replica
121
+ :param logger: The logger
122
+
123
+ """
124
+ for rep in chunk:
125
+ logger(logging.DEBUG, 'Working on %s', str(rep))
126
+ try:
127
+ get_metadata(rep['scope'], rep['name'])
128
+ unavailable_states = []
129
+ rep_state = get_replicas_state(rep['scope'], rep['name'])
130
+ unavailable_states.extend(rep_state.get(ReplicaState.TEMPORARY_UNAVAILABLE, []))
131
+ unavailable_states.extend(rep_state.get(ReplicaState.BEING_DELETED, []))
132
+ unavailable_states.extend(rep_state.get(ReplicaState.BAD, []))
133
+ # If the replica is already not available, it is removed from the bad PFNs table
134
+ if rep['rse_id'] in unavailable_states:
135
+ logger(logging.INFO, '%s is in unavailable state. Will be removed from the list of bad PFNs', str(rep['pfn']))
136
+ bulk_delete_bad_pfns(pfns=[rep['pfn']], session=None)
137
+ # If the expiration date of the TEMPORARY_UNAVAILABLE is in the past, it is removed from the bad PFNs table
138
+ elif expires_at < datetime.utcnow():
139
+ logger(logging.INFO, 'PFN %s expiration time (%s) is older than now and is not in unavailable state. Removing the PFNs from bad_pfns', str(rep['pfn']), expires_at)
140
+ bulk_delete_bad_pfns(pfns=[rep['pfn']], session=None)
141
+ # Else update everything in the same transaction
142
+ else:
143
+ try:
144
+ session = get_session()
145
+ update_replicas_states([rep], nowait=False, session=session)
146
+ bulk_add_bad_replicas([rep], account, state=BadFilesStatus.TEMPORARY_UNAVAILABLE, reason=reason, expires_at=expires_at, session=session)
147
+ bulk_delete_bad_pfns(pfns=[rep['pfn']], session=session)
148
+ session.commit() # pylint: disable=no-member
149
+ except Exception:
150
+ logger(logging.ERROR, 'Cannot update state of %s', str(rep['pfn']))
151
+ except (DataIdentifierNotFound, ReplicaNotFound):
152
+ logger(logging.ERROR, 'Will remove %s from the list of bad PFNs', str(rep['pfn']))
153
+ bulk_delete_bad_pfns(pfns=[rep['pfn']], session=None)
154
+
155
+
156
+ def minos(bulk: int = 1000, once: bool = False, sleep_time: int = 60) -> None:
157
+ """
158
+ Creates a Minos Worker that gets a list of bad PFNs,
159
+ extract the scope, name and rse_id and fill the bad_replicas table.
160
+
161
+ :param bulk: The number of requests to process.
162
+ :param once: Run only once.
163
+ :param sleep_time: Time between two cycles.
164
+ """
165
+ run_daemon(
166
+ once=once,
167
+ graceful_stop=graceful_stop,
168
+ executable=DAEMON_NAME,
169
+ partition_wait_time=10,
170
+ sleep_time=sleep_time,
171
+ run_once_fnc=functools.partial(
172
+ run_once,
173
+ bulk=bulk,
174
+ ),
175
+ )
176
+
177
+
178
+ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> bool:
179
+ worker_number, total_workers, logger = heartbeat_handler.live()
180
+ logger(logging.INFO, 'Minos started')
181
+
182
+ chunk_size = config_get_int('minos', 'commit_size', default=10, raise_exception=False) # The chunk size used for the commits
183
+
184
+ pfns = get_bad_pfns(thread=worker_number, total_threads=total_workers, limit=bulk)
185
+
186
+ # Class the PFNs into bad_replicas and temporary_unavailable
187
+ bad_replicas, temporary_unvailables = __classify_bad_pfns(pfns)
188
+
189
+ # Process the bad and suspicious files
190
+ # The scope, name, rse_id are extracted and filled into the bad_replicas table
191
+ for account, reason, state in bad_replicas:
192
+ vo = account.vo
193
+ pfns = bad_replicas[(account, reason, state)]
194
+ logger(logging.INFO, 'Declaring %s replicas with state %s and reason %s', len(pfns), str(state), reason)
195
+ session = get_session()
196
+ try:
197
+ dict_rse = __clean_unknown_replicas(pfns, vo, logger)
198
+ for rse_id, pfns_by_scheme in dict_rse.items():
199
+ rse = get_rse_name(rse_id=rse_id, session=None)
200
+ rse_vo_str = rse if vo == 'def' else '{} on VO {}'.format(rse, vo)
201
+ for scheme, pfns in pfns_by_scheme.items():
202
+ logger(logging.DEBUG, 'Running on RSE %s with %s replicas', rse_vo_str, len(pfns))
203
+ tot_chunk = int(math.ceil(len(pfns) / chunk_size))
204
+ for nchunk, chunk in enumerate(chunks(pfns, chunk_size)):
205
+ logger(logging.DEBUG, 'Running on %s chunk out of %s', nchunk + 1, tot_chunk)
206
+ unknown_replicas = declare_bad_file_replicas(chunk, reason=reason, issuer=account, status=state, session=session)
207
+ if unknown_replicas:
208
+ logger(logging.DEBUG, 'Unknown replicas : %s', str(unknown_replicas))
209
+ bulk_delete_bad_pfns(pfns=chunk, session=session)
210
+ session.commit() # pylint: disable=no-member
211
+ except (DatabaseException, DatabaseError) as error:
212
+ if re.match('.*ORA-00054.*', error.args[0]) or re.match('.*ORA-00060.*', error.args[0]) or 'ERROR 1205 (HY000)' in error.args[0]:
213
+ logger(logging.WARNING, 'Lock detected when handling request - skipping: %s', str(error))
214
+ else:
215
+ logger(logging.ERROR, 'Exception', exc_info=True)
216
+ session.rollback() # pylint: disable=no-member
217
+ except Exception:
218
+ session.rollback() # pylint: disable=no-member
219
+ logger(logging.CRITICAL, 'Exception', exc_info=True)
220
+
221
+ worker_number, total_workers, logger = heartbeat_handler.live()
222
+
223
+ # Now get the temporary unavailable and update the replicas states
224
+ for account, reason, expires_at in temporary_unvailables:
225
+ vo = account.vo
226
+ pfns = temporary_unvailables[(account, reason, expires_at)]
227
+ logger(logging.INFO, 'Declaring %s replicas temporary available with timeout %s and reason %s', len(pfns), str(expires_at), reason)
228
+ logger(logging.DEBUG, 'Extracting RSEs')
229
+
230
+ dict_rse = __clean_unknown_replicas(pfns, vo, logger)
231
+ for rse_id in dict_rse:
232
+ replicas = []
233
+ rse = get_rse_name(rse_id=rse_id, session=None)
234
+ rse_vo_str = rse if vo == 'def' else '{} on VO {}'.format(rse, vo)
235
+ logger(logging.DEBUG, 'Running on RSE %s', rse_vo_str)
236
+ for rse_id, pfns_by_scheme in dict_rse.items():
237
+ for scheme, pfns in pfns_by_scheme.items():
238
+ for rep in get_did_from_pfns(pfns=pfns, rse_id=None, vo=vo, session=None):
239
+ for pfn in rep:
240
+ scope = rep[pfn]['scope']
241
+ name = rep[pfn]['name']
242
+ replicas.append({'scope': scope, 'name': name, 'rse_id': rse_id, 'state': ReplicaState.TEMPORARY_UNAVAILABLE, 'pfn': pfn})
243
+ # The following part needs to be atomic
244
+ # We update the replicas states to TEMPORARY_UNAVAILABLE
245
+ # then insert a row in the bad_replicas table. TODO Update the row if it already exists
246
+ # then delete the corresponding rows into the bad_pfns table
247
+ logger(logging.DEBUG, 'Running on %s replicas on RSE %s', len(replicas), rse_vo_str)
248
+ tot_chunk = int(math.ceil(len(replicas) / float(chunk_size)))
249
+ session = get_session()
250
+ for nchunk, chunk in enumerate(chunks(replicas, chunk_size)):
251
+ try:
252
+ logger(logging.DEBUG, 'Running on %s chunk out of %s', nchunk + 1, tot_chunk)
253
+ update_replicas_states(chunk, nowait=False, session=session)
254
+ bulk_add_bad_replicas(chunk, account, state=BadFilesStatus.TEMPORARY_UNAVAILABLE, reason=reason, expires_at=expires_at, session=session)
255
+ pfns = [entry['pfn'] for entry in chunk]
256
+ bulk_delete_bad_pfns(pfns=pfns, session=session)
257
+ session.commit() # pylint: disable=no-member
258
+ except (UnsupportedOperation, ReplicaNotFound) as error:
259
+ session.rollback() # pylint: disable=no-member
260
+ logger(logging.ERROR, 'Problem to bulk update PFNs. PFNs will be updated individually. Error : %s', str(error))
261
+ # Update all the replicas one by one
262
+ __update_temporary_unavailable(chunk=chunk, reason=reason, expires_at=expires_at, account=account, logger=logger)
263
+ session = get_session()
264
+ except (DatabaseException, DatabaseError) as error:
265
+ if re.match('.*ORA-00054.*', error.args[0]) or re.match('.*ORA-00060.*', error.args[0]) or 'ERROR 1205 (HY000)' in error.args[0]:
266
+ logger(logging.WARNING, 'Lock detected when handling request - skipping: %s', str(error))
267
+ else:
268
+ logger(logging.ERROR, 'Exception', exc_info=True)
269
+ session.rollback() # pylint: disable=no-member
270
+ session = get_session()
271
+ except Exception:
272
+ session.rollback() # pylint: disable=no-member
273
+ logger(logging.CRITICAL, 'Exception', exc_info=True)
274
+ session = get_session()
275
+ must_sleep = True
276
+ if len(pfns) == bulk:
277
+ logger(logging.INFO, 'Processed maximum number of pfns according to the bulk size. Restart immediately next cycle')
278
+ must_sleep = False
279
+ return must_sleep
280
+ return must_sleep
281
+
282
+
283
+ def run(threads: int = 1, bulk: int = 100, once: bool = False, sleep_time: int = 60) -> None:
284
+ """
285
+ Starts up the minos threads.
286
+ """
287
+ setup_logging(process_name=DAEMON_NAME)
288
+
289
+ if rucio.db.sqla.util.is_old_db():
290
+ raise DatabaseException('Database was not updated, daemon won\'t start')
291
+
292
+ if once:
293
+ logging.info('Will run only one iteration in a single threaded mode')
294
+ minos(bulk=bulk, once=once)
295
+ else:
296
+ logging.info('starting transmogrifier threads')
297
+ thread_list = [threading.Thread(target=minos, kwargs={'once': once,
298
+ 'sleep_time': sleep_time,
299
+ 'bulk': bulk}) for _ in range(0, threads)]
300
+ [thread.start() for thread in thread_list]
301
+ logging.info('waiting for interrupts')
302
+ # Interruptible joins require a timeout.
303
+ while thread_list:
304
+ thread_list = [thread.join(timeout=3.14) for thread in thread_list if thread and thread.is_alive()]
305
+
306
+
307
+ def stop(signum: "Optional[int]" = None, frame: "Optional[FrameType]" = None) -> None:
308
+ """
309
+ Graceful exit.
310
+ """
311
+ graceful_stop.set()
@@ -0,0 +1,173 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import functools
17
+ import logging
18
+ import re
19
+ import threading
20
+ import traceback
21
+ from typing import TYPE_CHECKING
22
+
23
+ import math
24
+ from sqlalchemy.exc import DatabaseError
25
+
26
+ import rucio.db.sqla.util
27
+ from rucio.common import exception
28
+ from rucio.common.exception import DataIdentifierNotFound, ReplicaNotFound, DatabaseException
29
+ from rucio.common.logging import setup_logging
30
+ from rucio.common.utils import chunks
31
+ from rucio.core.did import get_metadata
32
+ from rucio.core.replica import (update_replicas_states, get_replicas_state,
33
+ bulk_delete_bad_replicas, list_expired_temporary_unavailable_replicas)
34
+ from rucio.daemons.common import run_daemon
35
+ from rucio.db.sqla.constants import BadFilesStatus, ReplicaState
36
+ from rucio.db.sqla.session import get_session
37
+
38
+ if TYPE_CHECKING:
39
+ from types import FrameType
40
+ from typing import Optional
41
+
42
+ from rucio.daemons.common import HeartbeatHandler
43
+
44
+ graceful_stop = threading.Event()
45
+ DAEMON_NAME = 'minos-temporary-expiration'
46
+
47
+
48
+ def minos_tu_expiration(bulk: int = 1000, once: bool = False, sleep_time: int = 60) -> None:
49
+ """
50
+ Creates a Minos Temporary Unavailable Replicas Expiration Worker that
51
+ gets the list of expired TU replicas and sets them back to AVAILABLE.
52
+
53
+ :param bulk: The number of requests to process.
54
+ :param once: Run only once.
55
+ :param sleep_time: Time between two cycles.
56
+ """
57
+ run_daemon(
58
+ once=once,
59
+ graceful_stop=graceful_stop,
60
+ executable=DAEMON_NAME,
61
+ partition_wait_time=10,
62
+ sleep_time=sleep_time,
63
+ run_once_fnc=functools.partial(
64
+ run_once,
65
+ bulk=bulk,
66
+ ),
67
+ )
68
+
69
+
70
+ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> bool:
71
+
72
+ worker_number, total_workers, logger = heartbeat_handler.live()
73
+ chunk_size = 10 # The chunk size used for the commits
74
+ logger(logging.INFO, 'Getting list of expired replicas')
75
+ expired_replicas = list_expired_temporary_unavailable_replicas(total_workers=total_workers,
76
+ worker_number=worker_number,
77
+ limit=1000)
78
+ logger(logging.INFO, '%s expired replicas returned', len(expired_replicas))
79
+ logger(logging.DEBUG, 'List of expired replicas returned %s', str(expired_replicas))
80
+ replicas = []
81
+ bad_replicas = []
82
+ nchunk = 0
83
+ tot_chunk = int(math.ceil(len(expired_replicas) / float(chunk_size)))
84
+ session = get_session()
85
+ for chunk in chunks(expired_replicas, chunk_size):
86
+ worker_number, total_workers, logger = heartbeat_handler.live()
87
+ skip_replica_update = []
88
+ # Process and update the replicas in chunks
89
+ for replica in chunk:
90
+ scope, name, rse_id = replica[0], replica[1], replica[2]
91
+ states_dictionary = get_replicas_state(scope=scope, name=name, session=session)
92
+ # Check if the replica is not declared bad
93
+ # If already declared bad don't update the replica state, but remove from bad_pfns
94
+ if not (ReplicaState.BAD in states_dictionary and rse_id in states_dictionary[ReplicaState.BAD]):
95
+ replicas.append({'scope': scope, 'name': name, 'rse_id': rse_id, 'state': ReplicaState.AVAILABLE})
96
+ else:
97
+ skip_replica_update.append((scope, name))
98
+ # Remove the replicas from bad_replicas table in chunks
99
+ bad_replicas.append({'scope': scope, 'name': name, 'rse_id': rse_id, 'state': BadFilesStatus.TEMPORARY_UNAVAILABLE})
100
+ try:
101
+ nchunk += 1
102
+ logger(logging.DEBUG, 'Running on %s chunk out of %s', nchunk, tot_chunk)
103
+ update_replicas_states(replicas, nowait=True, session=session)
104
+ bulk_delete_bad_replicas(bad_replicas, session=session)
105
+ session.commit() # pylint: disable=no-member
106
+ except (ReplicaNotFound, DataIdentifierNotFound) as error:
107
+ session.rollback() # pylint: disable=no-member
108
+ logger(logging.WARNING, 'One of the replicas does not exist anymore. Updating and deleting one by one. Error : %s', str(error))
109
+ for replica in chunk:
110
+ _, _, logger = heartbeat_handler.live()
111
+ scope, name, rse_id = replica[0], replica[1], replica[2]
112
+ logger(logging.DEBUG, 'Working on %s:%s on %s', scope, name, rse_id)
113
+ try:
114
+ # First check if the DID exists
115
+ get_metadata(scope, name)
116
+ if (scope, name) not in skip_replica_update:
117
+ update_replicas_states([{'scope': scope, 'name': name, 'rse_id': rse_id, 'state': ReplicaState.AVAILABLE}, ], nowait=True, session=session)
118
+ bulk_delete_bad_replicas([{'scope': scope, 'name': name, 'rse_id': rse_id, 'state': BadFilesStatus.TEMPORARY_UNAVAILABLE}, ], session=session)
119
+ session.commit() # pylint: disable=no-member
120
+ except DataIdentifierNotFound:
121
+ session.rollback() # pylint: disable=no-member
122
+ logger(logging.WARNING, 'DID %s:%s does not exist anymore.', scope, name)
123
+ bulk_delete_bad_replicas([{'scope': scope, 'name': name, 'rse_id': rse_id, 'state': BadFilesStatus.TEMPORARY_UNAVAILABLE}, ], session=session)
124
+ session.commit() # pylint: disable=no-member
125
+ except ReplicaNotFound:
126
+ session.rollback() # pylint: disable=no-member
127
+ logger(logging.WARNING, 'Replica %s:%s on RSEID %s does not exist anymore.', scope, name, rse_id)
128
+ bulk_delete_bad_replicas([{'scope': scope, 'name': name, 'rse_id': rse_id, 'state': BadFilesStatus.TEMPORARY_UNAVAILABLE}, ], session=session)
129
+ session.commit() # pylint: disable=no-member
130
+ session = get_session()
131
+ except (DatabaseException, DatabaseError) as error:
132
+ if re.match('.*ORA-00054.*', error.args[0]) or re.match('.*ORA-00060.*', error.args[0]) or 'ERROR 1205 (HY000)' in error.args[0]:
133
+ logger(logging.WARNING, 'Lock detected when handling request - skipping: %s', str(error))
134
+ else:
135
+ logger(logging.ERROR, 'Exception', exc_info=True)
136
+ session.rollback()
137
+ session = get_session()
138
+ except Exception:
139
+ session.rollback() # pylint: disable=no-member
140
+ logger(logging.CRITICAL, str(traceback.format_exc()))
141
+ session = get_session()
142
+ return True
143
+
144
+
145
+ def run(threads: int = 1, bulk: int = 100, once: bool = False, sleep_time: int = 60) -> None:
146
+ """
147
+ Starts up the minos threads.
148
+ """
149
+ setup_logging(process_name=DAEMON_NAME)
150
+
151
+ if rucio.db.sqla.util.is_old_db():
152
+ raise exception.DatabaseException('Database was not updated, daemon won\'t start')
153
+
154
+ if once:
155
+ logging.log(logging.INFO, 'Will run only one iteration in a single threaded mode')
156
+ minos_tu_expiration(bulk=bulk, once=once)
157
+ else:
158
+ logging.log(logging.INFO, 'Starting Minos Temporary Expiration threads')
159
+ thread_list = [threading.Thread(target=minos_tu_expiration, kwargs={'once': once,
160
+ 'sleep_time': sleep_time,
161
+ 'bulk': bulk}) for _ in range(0, threads)]
162
+ [thread.start() for thread in thread_list]
163
+ logging.log(logging.INFO, 'Waiting for interrupts')
164
+ # Interruptible joins require a timeout.
165
+ while thread_list:
166
+ thread_list = [thread.join(timeout=3.14) for thread in thread_list if thread and thread.is_alive()]
167
+
168
+
169
+ def stop(signum: "Optional[int]" = None, frame: "Optional[FrameType]" = None) -> None:
170
+ """
171
+ Graceful exit.
172
+ """
173
+ graceful_stop.set()