rucio 37.0.0rc1__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 (487) hide show
  1. rucio/__init__.py +17 -0
  2. rucio/alembicrevision.py +15 -0
  3. rucio/cli/__init__.py +14 -0
  4. rucio/cli/account.py +216 -0
  5. rucio/cli/bin_legacy/__init__.py +13 -0
  6. rucio/cli/bin_legacy/rucio.py +2825 -0
  7. rucio/cli/bin_legacy/rucio_admin.py +2500 -0
  8. rucio/cli/command.py +272 -0
  9. rucio/cli/config.py +72 -0
  10. rucio/cli/did.py +191 -0
  11. rucio/cli/download.py +128 -0
  12. rucio/cli/lifetime_exception.py +33 -0
  13. rucio/cli/replica.py +162 -0
  14. rucio/cli/rse.py +293 -0
  15. rucio/cli/rule.py +158 -0
  16. rucio/cli/scope.py +40 -0
  17. rucio/cli/subscription.py +73 -0
  18. rucio/cli/upload.py +60 -0
  19. rucio/cli/utils.py +226 -0
  20. rucio/client/__init__.py +15 -0
  21. rucio/client/accountclient.py +432 -0
  22. rucio/client/accountlimitclient.py +183 -0
  23. rucio/client/baseclient.py +983 -0
  24. rucio/client/client.py +120 -0
  25. rucio/client/configclient.py +126 -0
  26. rucio/client/credentialclient.py +59 -0
  27. rucio/client/didclient.py +868 -0
  28. rucio/client/diracclient.py +56 -0
  29. rucio/client/downloadclient.py +1783 -0
  30. rucio/client/exportclient.py +44 -0
  31. rucio/client/fileclient.py +50 -0
  32. rucio/client/importclient.py +42 -0
  33. rucio/client/lifetimeclient.py +90 -0
  34. rucio/client/lockclient.py +109 -0
  35. rucio/client/metaconventionsclient.py +140 -0
  36. rucio/client/pingclient.py +44 -0
  37. rucio/client/replicaclient.py +452 -0
  38. rucio/client/requestclient.py +125 -0
  39. rucio/client/richclient.py +317 -0
  40. rucio/client/rseclient.py +746 -0
  41. rucio/client/ruleclient.py +294 -0
  42. rucio/client/scopeclient.py +90 -0
  43. rucio/client/subscriptionclient.py +173 -0
  44. rucio/client/touchclient.py +82 -0
  45. rucio/client/uploadclient.py +969 -0
  46. rucio/common/__init__.py +13 -0
  47. rucio/common/bittorrent.py +234 -0
  48. rucio/common/cache.py +111 -0
  49. rucio/common/checksum.py +168 -0
  50. rucio/common/client.py +122 -0
  51. rucio/common/config.py +788 -0
  52. rucio/common/constants.py +217 -0
  53. rucio/common/constraints.py +17 -0
  54. rucio/common/didtype.py +237 -0
  55. rucio/common/dumper/__init__.py +342 -0
  56. rucio/common/dumper/consistency.py +497 -0
  57. rucio/common/dumper/data_models.py +362 -0
  58. rucio/common/dumper/path_parsing.py +75 -0
  59. rucio/common/exception.py +1208 -0
  60. rucio/common/extra.py +31 -0
  61. rucio/common/logging.py +420 -0
  62. rucio/common/pcache.py +1409 -0
  63. rucio/common/plugins.py +185 -0
  64. rucio/common/policy.py +93 -0
  65. rucio/common/schema/__init__.py +200 -0
  66. rucio/common/schema/generic.py +416 -0
  67. rucio/common/schema/generic_multi_vo.py +395 -0
  68. rucio/common/stomp_utils.py +423 -0
  69. rucio/common/stopwatch.py +55 -0
  70. rucio/common/test_rucio_server.py +154 -0
  71. rucio/common/types.py +483 -0
  72. rucio/common/utils.py +1688 -0
  73. rucio/core/__init__.py +13 -0
  74. rucio/core/account.py +496 -0
  75. rucio/core/account_counter.py +236 -0
  76. rucio/core/account_limit.py +425 -0
  77. rucio/core/authentication.py +620 -0
  78. rucio/core/config.py +437 -0
  79. rucio/core/credential.py +224 -0
  80. rucio/core/did.py +3004 -0
  81. rucio/core/did_meta_plugins/__init__.py +252 -0
  82. rucio/core/did_meta_plugins/did_column_meta.py +331 -0
  83. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
  84. rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
  85. rucio/core/did_meta_plugins/filter_engine.py +672 -0
  86. rucio/core/did_meta_plugins/json_meta.py +240 -0
  87. rucio/core/did_meta_plugins/mongo_meta.py +229 -0
  88. rucio/core/did_meta_plugins/postgres_meta.py +352 -0
  89. rucio/core/dirac.py +237 -0
  90. rucio/core/distance.py +187 -0
  91. rucio/core/exporter.py +59 -0
  92. rucio/core/heartbeat.py +363 -0
  93. rucio/core/identity.py +301 -0
  94. rucio/core/importer.py +260 -0
  95. rucio/core/lifetime_exception.py +377 -0
  96. rucio/core/lock.py +577 -0
  97. rucio/core/message.py +288 -0
  98. rucio/core/meta_conventions.py +203 -0
  99. rucio/core/monitor.py +448 -0
  100. rucio/core/naming_convention.py +195 -0
  101. rucio/core/nongrid_trace.py +136 -0
  102. rucio/core/oidc.py +1463 -0
  103. rucio/core/permission/__init__.py +161 -0
  104. rucio/core/permission/generic.py +1124 -0
  105. rucio/core/permission/generic_multi_vo.py +1144 -0
  106. rucio/core/quarantined_replica.py +224 -0
  107. rucio/core/replica.py +4483 -0
  108. rucio/core/replica_sorter.py +362 -0
  109. rucio/core/request.py +3091 -0
  110. rucio/core/rse.py +2079 -0
  111. rucio/core/rse_counter.py +185 -0
  112. rucio/core/rse_expression_parser.py +459 -0
  113. rucio/core/rse_selector.py +304 -0
  114. rucio/core/rule.py +4484 -0
  115. rucio/core/rule_grouping.py +1620 -0
  116. rucio/core/scope.py +181 -0
  117. rucio/core/subscription.py +362 -0
  118. rucio/core/topology.py +490 -0
  119. rucio/core/trace.py +375 -0
  120. rucio/core/transfer.py +1531 -0
  121. rucio/core/vo.py +169 -0
  122. rucio/core/volatile_replica.py +151 -0
  123. rucio/daemons/__init__.py +13 -0
  124. rucio/daemons/abacus/__init__.py +13 -0
  125. rucio/daemons/abacus/account.py +116 -0
  126. rucio/daemons/abacus/collection_replica.py +124 -0
  127. rucio/daemons/abacus/rse.py +117 -0
  128. rucio/daemons/atropos/__init__.py +13 -0
  129. rucio/daemons/atropos/atropos.py +242 -0
  130. rucio/daemons/auditor/__init__.py +289 -0
  131. rucio/daemons/auditor/hdfs.py +97 -0
  132. rucio/daemons/auditor/srmdumps.py +355 -0
  133. rucio/daemons/automatix/__init__.py +13 -0
  134. rucio/daemons/automatix/automatix.py +304 -0
  135. rucio/daemons/badreplicas/__init__.py +13 -0
  136. rucio/daemons/badreplicas/minos.py +322 -0
  137. rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
  138. rucio/daemons/badreplicas/necromancer.py +196 -0
  139. rucio/daemons/bb8/__init__.py +13 -0
  140. rucio/daemons/bb8/bb8.py +353 -0
  141. rucio/daemons/bb8/common.py +759 -0
  142. rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
  143. rucio/daemons/bb8/t2_background_rebalance.py +153 -0
  144. rucio/daemons/cache/__init__.py +13 -0
  145. rucio/daemons/cache/consumer.py +133 -0
  146. rucio/daemons/common.py +405 -0
  147. rucio/daemons/conveyor/__init__.py +13 -0
  148. rucio/daemons/conveyor/common.py +562 -0
  149. rucio/daemons/conveyor/finisher.py +529 -0
  150. rucio/daemons/conveyor/poller.py +394 -0
  151. rucio/daemons/conveyor/preparer.py +205 -0
  152. rucio/daemons/conveyor/receiver.py +179 -0
  153. rucio/daemons/conveyor/stager.py +133 -0
  154. rucio/daemons/conveyor/submitter.py +403 -0
  155. rucio/daemons/conveyor/throttler.py +532 -0
  156. rucio/daemons/follower/__init__.py +13 -0
  157. rucio/daemons/follower/follower.py +101 -0
  158. rucio/daemons/hermes/__init__.py +13 -0
  159. rucio/daemons/hermes/hermes.py +534 -0
  160. rucio/daemons/judge/__init__.py +13 -0
  161. rucio/daemons/judge/cleaner.py +159 -0
  162. rucio/daemons/judge/evaluator.py +185 -0
  163. rucio/daemons/judge/injector.py +162 -0
  164. rucio/daemons/judge/repairer.py +154 -0
  165. rucio/daemons/oauthmanager/__init__.py +13 -0
  166. rucio/daemons/oauthmanager/oauthmanager.py +198 -0
  167. rucio/daemons/reaper/__init__.py +13 -0
  168. rucio/daemons/reaper/dark_reaper.py +282 -0
  169. rucio/daemons/reaper/reaper.py +739 -0
  170. rucio/daemons/replicarecoverer/__init__.py +13 -0
  171. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
  172. rucio/daemons/rsedecommissioner/__init__.py +13 -0
  173. rucio/daemons/rsedecommissioner/config.py +81 -0
  174. rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
  175. rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
  176. rucio/daemons/rsedecommissioner/profiles/generic.py +452 -0
  177. rucio/daemons/rsedecommissioner/profiles/types.py +93 -0
  178. rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
  179. rucio/daemons/storage/__init__.py +13 -0
  180. rucio/daemons/storage/consistency/__init__.py +13 -0
  181. rucio/daemons/storage/consistency/actions.py +848 -0
  182. rucio/daemons/tracer/__init__.py +13 -0
  183. rucio/daemons/tracer/kronos.py +511 -0
  184. rucio/daemons/transmogrifier/__init__.py +13 -0
  185. rucio/daemons/transmogrifier/transmogrifier.py +762 -0
  186. rucio/daemons/undertaker/__init__.py +13 -0
  187. rucio/daemons/undertaker/undertaker.py +137 -0
  188. rucio/db/__init__.py +13 -0
  189. rucio/db/sqla/__init__.py +52 -0
  190. rucio/db/sqla/constants.py +206 -0
  191. rucio/db/sqla/migrate_repo/__init__.py +13 -0
  192. rucio/db/sqla/migrate_repo/env.py +110 -0
  193. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
  194. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
  195. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
  196. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
  197. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
  198. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
  199. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
  200. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
  201. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
  202. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
  203. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
  204. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
  205. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
  206. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
  207. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
  208. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
  209. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
  210. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
  211. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
  212. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
  213. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
  214. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
  215. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
  216. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
  217. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
  218. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
  219. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
  220. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
  221. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
  222. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
  223. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
  224. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
  225. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
  226. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
  227. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
  228. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
  229. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
  230. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
  231. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
  232. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
  233. rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
  234. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
  235. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
  236. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
  237. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
  238. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
  239. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
  240. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
  241. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
  242. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
  243. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
  244. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
  245. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
  246. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
  247. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
  248. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
  249. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
  250. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
  251. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
  252. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
  253. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
  254. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
  255. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
  256. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
  257. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
  258. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
  259. rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
  260. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
  261. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
  262. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
  263. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
  264. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
  265. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
  266. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
  267. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
  268. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
  269. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
  270. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
  271. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
  272. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
  273. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
  274. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
  275. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
  276. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
  277. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
  278. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
  279. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
  280. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
  281. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
  282. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
  283. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
  284. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
  285. rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
  286. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
  287. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
  288. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
  289. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
  290. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
  291. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
  292. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
  293. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
  294. rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
  295. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
  296. rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
  297. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
  298. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
  299. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
  300. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
  301. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
  302. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
  303. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
  304. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
  305. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
  306. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
  307. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
  308. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
  309. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
  310. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
  311. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
  312. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
  313. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
  314. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
  315. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
  316. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
  317. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
  318. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
  319. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
  320. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
  321. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
  322. rucio/db/sqla/models.py +1743 -0
  323. rucio/db/sqla/sautils.py +55 -0
  324. rucio/db/sqla/session.py +529 -0
  325. rucio/db/sqla/types.py +206 -0
  326. rucio/db/sqla/util.py +543 -0
  327. rucio/gateway/__init__.py +13 -0
  328. rucio/gateway/account.py +345 -0
  329. rucio/gateway/account_limit.py +363 -0
  330. rucio/gateway/authentication.py +381 -0
  331. rucio/gateway/config.py +227 -0
  332. rucio/gateway/credential.py +70 -0
  333. rucio/gateway/did.py +987 -0
  334. rucio/gateway/dirac.py +83 -0
  335. rucio/gateway/exporter.py +60 -0
  336. rucio/gateway/heartbeat.py +76 -0
  337. rucio/gateway/identity.py +189 -0
  338. rucio/gateway/importer.py +46 -0
  339. rucio/gateway/lifetime_exception.py +121 -0
  340. rucio/gateway/lock.py +153 -0
  341. rucio/gateway/meta_conventions.py +98 -0
  342. rucio/gateway/permission.py +74 -0
  343. rucio/gateway/quarantined_replica.py +79 -0
  344. rucio/gateway/replica.py +538 -0
  345. rucio/gateway/request.py +330 -0
  346. rucio/gateway/rse.py +632 -0
  347. rucio/gateway/rule.py +437 -0
  348. rucio/gateway/scope.py +100 -0
  349. rucio/gateway/subscription.py +280 -0
  350. rucio/gateway/vo.py +126 -0
  351. rucio/rse/__init__.py +96 -0
  352. rucio/rse/protocols/__init__.py +13 -0
  353. rucio/rse/protocols/bittorrent.py +194 -0
  354. rucio/rse/protocols/cache.py +111 -0
  355. rucio/rse/protocols/dummy.py +100 -0
  356. rucio/rse/protocols/gfal.py +708 -0
  357. rucio/rse/protocols/globus.py +243 -0
  358. rucio/rse/protocols/http_cache.py +82 -0
  359. rucio/rse/protocols/mock.py +123 -0
  360. rucio/rse/protocols/ngarc.py +209 -0
  361. rucio/rse/protocols/posix.py +250 -0
  362. rucio/rse/protocols/protocol.py +361 -0
  363. rucio/rse/protocols/rclone.py +365 -0
  364. rucio/rse/protocols/rfio.py +145 -0
  365. rucio/rse/protocols/srm.py +338 -0
  366. rucio/rse/protocols/ssh.py +414 -0
  367. rucio/rse/protocols/storm.py +195 -0
  368. rucio/rse/protocols/webdav.py +594 -0
  369. rucio/rse/protocols/xrootd.py +302 -0
  370. rucio/rse/rsemanager.py +881 -0
  371. rucio/rse/translation.py +260 -0
  372. rucio/tests/__init__.py +13 -0
  373. rucio/tests/common.py +280 -0
  374. rucio/tests/common_server.py +149 -0
  375. rucio/transfertool/__init__.py +13 -0
  376. rucio/transfertool/bittorrent.py +200 -0
  377. rucio/transfertool/bittorrent_driver.py +50 -0
  378. rucio/transfertool/bittorrent_driver_qbittorrent.py +134 -0
  379. rucio/transfertool/fts3.py +1600 -0
  380. rucio/transfertool/fts3_plugins.py +152 -0
  381. rucio/transfertool/globus.py +201 -0
  382. rucio/transfertool/globus_library.py +181 -0
  383. rucio/transfertool/mock.py +89 -0
  384. rucio/transfertool/transfertool.py +221 -0
  385. rucio/vcsversion.py +11 -0
  386. rucio/version.py +45 -0
  387. rucio/web/__init__.py +13 -0
  388. rucio/web/rest/__init__.py +13 -0
  389. rucio/web/rest/flaskapi/__init__.py +13 -0
  390. rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
  391. rucio/web/rest/flaskapi/v1/__init__.py +13 -0
  392. rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
  393. rucio/web/rest/flaskapi/v1/accounts.py +1103 -0
  394. rucio/web/rest/flaskapi/v1/archives.py +102 -0
  395. rucio/web/rest/flaskapi/v1/auth.py +1644 -0
  396. rucio/web/rest/flaskapi/v1/common.py +426 -0
  397. rucio/web/rest/flaskapi/v1/config.py +304 -0
  398. rucio/web/rest/flaskapi/v1/credentials.py +213 -0
  399. rucio/web/rest/flaskapi/v1/dids.py +2340 -0
  400. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  401. rucio/web/rest/flaskapi/v1/export.py +75 -0
  402. rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
  403. rucio/web/rest/flaskapi/v1/identities.py +285 -0
  404. rucio/web/rest/flaskapi/v1/import.py +132 -0
  405. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
  406. rucio/web/rest/flaskapi/v1/locks.py +358 -0
  407. rucio/web/rest/flaskapi/v1/main.py +91 -0
  408. rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
  409. rucio/web/rest/flaskapi/v1/metrics.py +36 -0
  410. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  411. rucio/web/rest/flaskapi/v1/ping.py +88 -0
  412. rucio/web/rest/flaskapi/v1/redirect.py +366 -0
  413. rucio/web/rest/flaskapi/v1/replicas.py +1894 -0
  414. rucio/web/rest/flaskapi/v1/requests.py +998 -0
  415. rucio/web/rest/flaskapi/v1/rses.py +2250 -0
  416. rucio/web/rest/flaskapi/v1/rules.py +854 -0
  417. rucio/web/rest/flaskapi/v1/scopes.py +159 -0
  418. rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
  419. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  420. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  421. rucio/web/rest/flaskapi/v1/traces.py +137 -0
  422. rucio/web/rest/flaskapi/v1/types.py +20 -0
  423. rucio/web/rest/flaskapi/v1/vos.py +278 -0
  424. rucio/web/rest/main.py +18 -0
  425. rucio/web/rest/metrics.py +27 -0
  426. rucio/web/rest/ping.py +27 -0
  427. rucio-37.0.0rc1.data/data/rucio/etc/alembic.ini.template +71 -0
  428. rucio-37.0.0rc1.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  429. rucio-37.0.0rc1.data/data/rucio/etc/globus-config.yml.template +5 -0
  430. rucio-37.0.0rc1.data/data/rucio/etc/ldap.cfg.template +30 -0
  431. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  432. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  433. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  434. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  435. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  436. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  437. rucio-37.0.0rc1.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  438. rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.atlas.client.template +43 -0
  439. rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.template +241 -0
  440. rucio-37.0.0rc1.data/data/rucio/etc/rucio_multi_vo.cfg.template +217 -0
  441. rucio-37.0.0rc1.data/data/rucio/requirements.server.txt +297 -0
  442. rucio-37.0.0rc1.data/data/rucio/tools/bootstrap.py +34 -0
  443. rucio-37.0.0rc1.data/data/rucio/tools/merge_rucio_configs.py +144 -0
  444. rucio-37.0.0rc1.data/data/rucio/tools/reset_database.py +40 -0
  445. rucio-37.0.0rc1.data/scripts/rucio +133 -0
  446. rucio-37.0.0rc1.data/scripts/rucio-abacus-account +74 -0
  447. rucio-37.0.0rc1.data/scripts/rucio-abacus-collection-replica +46 -0
  448. rucio-37.0.0rc1.data/scripts/rucio-abacus-rse +78 -0
  449. rucio-37.0.0rc1.data/scripts/rucio-admin +97 -0
  450. rucio-37.0.0rc1.data/scripts/rucio-atropos +60 -0
  451. rucio-37.0.0rc1.data/scripts/rucio-auditor +206 -0
  452. rucio-37.0.0rc1.data/scripts/rucio-automatix +50 -0
  453. rucio-37.0.0rc1.data/scripts/rucio-bb8 +57 -0
  454. rucio-37.0.0rc1.data/scripts/rucio-cache-client +141 -0
  455. rucio-37.0.0rc1.data/scripts/rucio-cache-consumer +42 -0
  456. rucio-37.0.0rc1.data/scripts/rucio-conveyor-finisher +58 -0
  457. rucio-37.0.0rc1.data/scripts/rucio-conveyor-poller +66 -0
  458. rucio-37.0.0rc1.data/scripts/rucio-conveyor-preparer +37 -0
  459. rucio-37.0.0rc1.data/scripts/rucio-conveyor-receiver +44 -0
  460. rucio-37.0.0rc1.data/scripts/rucio-conveyor-stager +76 -0
  461. rucio-37.0.0rc1.data/scripts/rucio-conveyor-submitter +139 -0
  462. rucio-37.0.0rc1.data/scripts/rucio-conveyor-throttler +104 -0
  463. rucio-37.0.0rc1.data/scripts/rucio-dark-reaper +53 -0
  464. rucio-37.0.0rc1.data/scripts/rucio-dumper +160 -0
  465. rucio-37.0.0rc1.data/scripts/rucio-follower +44 -0
  466. rucio-37.0.0rc1.data/scripts/rucio-hermes +54 -0
  467. rucio-37.0.0rc1.data/scripts/rucio-judge-cleaner +89 -0
  468. rucio-37.0.0rc1.data/scripts/rucio-judge-evaluator +137 -0
  469. rucio-37.0.0rc1.data/scripts/rucio-judge-injector +44 -0
  470. rucio-37.0.0rc1.data/scripts/rucio-judge-repairer +44 -0
  471. rucio-37.0.0rc1.data/scripts/rucio-kronos +44 -0
  472. rucio-37.0.0rc1.data/scripts/rucio-minos +53 -0
  473. rucio-37.0.0rc1.data/scripts/rucio-minos-temporary-expiration +50 -0
  474. rucio-37.0.0rc1.data/scripts/rucio-necromancer +120 -0
  475. rucio-37.0.0rc1.data/scripts/rucio-oauth-manager +63 -0
  476. rucio-37.0.0rc1.data/scripts/rucio-reaper +83 -0
  477. rucio-37.0.0rc1.data/scripts/rucio-replica-recoverer +248 -0
  478. rucio-37.0.0rc1.data/scripts/rucio-rse-decommissioner +66 -0
  479. rucio-37.0.0rc1.data/scripts/rucio-storage-consistency-actions +74 -0
  480. rucio-37.0.0rc1.data/scripts/rucio-transmogrifier +77 -0
  481. rucio-37.0.0rc1.data/scripts/rucio-undertaker +76 -0
  482. rucio-37.0.0rc1.dist-info/METADATA +92 -0
  483. rucio-37.0.0rc1.dist-info/RECORD +487 -0
  484. rucio-37.0.0rc1.dist-info/WHEEL +5 -0
  485. rucio-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
  486. rucio-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
  487. rucio-37.0.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,394 @@
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
+ """
16
+ Conveyor is a daemon to manage file transfers.
17
+ """
18
+
19
+ import datetime
20
+ import itertools
21
+ import json
22
+ import logging
23
+ import re
24
+ import threading
25
+ import time
26
+ from itertools import groupby
27
+ from typing import TYPE_CHECKING, Any, Optional
28
+
29
+ from requests.exceptions import RequestException
30
+ from sqlalchemy.exc import DatabaseError
31
+
32
+ import rucio.db.sqla.util
33
+ from rucio.common.config import config_get, config_get_bool, config_get_float
34
+ from rucio.common.exception import DatabaseException, TransferToolTimeout, TransferToolWrongAnswer
35
+ from rucio.common.logging import setup_logging
36
+ from rucio.common.stopwatch import Stopwatch
37
+ from rucio.common.utils import dict_chunks
38
+ from rucio.core import request as request_core
39
+ from rucio.core import transfer as transfer_core
40
+ from rucio.core.monitor import MetricManager
41
+ from rucio.core.topology import ExpiringObjectCache, Topology
42
+ from rucio.daemons.common import ProducerConsumerDaemon, db_workqueue
43
+ from rucio.db.sqla.constants import MYSQL_LOCK_WAIT_TIMEOUT_EXCEEDED, ORACLE_DEADLOCK_DETECTED_REGEX, ORACLE_RESOURCE_BUSY_REGEX, RequestState, RequestType
44
+ from rucio.transfertool.fts3 import FTS3Transfertool
45
+
46
+ if TYPE_CHECKING:
47
+ from collections.abc import Mapping, Sequence
48
+ from types import FrameType
49
+
50
+ from rucio.common.types import LoggerFunction
51
+ from rucio.daemons.common import HeartbeatHandler
52
+ from rucio.transfertool.transfertool import Transfertool
53
+
54
+ GRACEFUL_STOP = threading.Event()
55
+ METRICS = MetricManager(module=__name__)
56
+ DAEMON_NAME = 'conveyor-poller'
57
+
58
+ TRANSFER_TOOL = config_get('conveyor', 'transfertool', False, None) # NOTE: This should eventually be completely removed, as it can be fetched from the request
59
+ FILTER_TRANSFERTOOL = config_get('conveyor', 'filter_transfertool', False, None) # NOTE: TRANSFERTOOL to filter requests on
60
+
61
+
62
+ def _fetch_requests(
63
+ db_bulk: int,
64
+ older_than: int,
65
+ activity_shares: Optional['Mapping[str, float]'],
66
+ transfertool: Optional[str],
67
+ filter_transfertool: Optional[str],
68
+ cached_topology: Optional[ExpiringObjectCache],
69
+ activity: str,
70
+ set_last_processed_by: bool,
71
+ heartbeat_handler: "HeartbeatHandler"
72
+ ) -> tuple[bool, list[dict[str, Any]]]:
73
+ worker_number, total_workers, logger = heartbeat_handler.live()
74
+
75
+ logger(logging.DEBUG, 'Start to poll transfers older than %i seconds for activity %s using transfer tool: %s' % (older_than, activity, filter_transfertool))
76
+
77
+ topology = cached_topology.get() if cached_topology else Topology()
78
+ transfs = request_core.get_and_mark_next(
79
+ rse_collection=topology,
80
+ request_type=[RequestType.TRANSFER, RequestType.STAGEIN, RequestType.STAGEOUT],
81
+ state=[RequestState.SUBMITTED],
82
+ processed_by=heartbeat_handler.short_executable if set_last_processed_by else None,
83
+ limit=db_bulk,
84
+ older_than=datetime.datetime.utcnow() - datetime.timedelta(seconds=older_than) if older_than else None,
85
+ total_workers=total_workers,
86
+ worker_number=worker_number,
87
+ mode_all=True,
88
+ hash_variable='id',
89
+ activity=activity,
90
+ activity_shares=activity_shares,
91
+ transfertool=filter_transfertool,
92
+ )
93
+
94
+ if transfertool and not filter_transfertool:
95
+ # only keep transfers which don't have any transfertool set, or have one equal to TRANSFER_TOOL
96
+ transfs_tmp = [t for t in transfs if not t['transfertool'] or t['transfertool'] == transfertool]
97
+ if len(transfs_tmp) != len(transfs):
98
+ logger(logging.INFO, 'Skipping %i transfers because of mismatched transfertool', len(transfs) - len(transfs_tmp))
99
+ transfs = transfs_tmp
100
+
101
+ if transfs:
102
+ logger(logging.DEBUG, 'Polling %i transfers for activity %s' % (len(transfs), activity))
103
+
104
+ must_sleep = False
105
+ if len(transfs) < db_bulk / 2:
106
+ logger(logging.INFO, "Only %s transfers for activity %s, which is less than half of the bulk %s" % (len(transfs), activity, db_bulk))
107
+ must_sleep = True
108
+
109
+ return must_sleep, transfs
110
+
111
+
112
+ def _handle_requests(
113
+ transfs: list[dict[str, Any]],
114
+ fts_bulk: int,
115
+ multi_vo: Optional[bool],
116
+ timeout: Optional[int],
117
+ transfertool: str,
118
+ transfer_stats_manager: request_core.TransferStatsManager,
119
+ oidc_support: bool,
120
+ *,
121
+ logger: "LoggerFunction" = logging.log,
122
+ ) -> None:
123
+ transfs.sort(key=lambda t: (t['external_host'] or '',
124
+ t['scope'].vo if multi_vo else '',
125
+ t['external_id'] or '',
126
+ t['request_id'] or ''))
127
+ for (external_host, vo), transfers_for_host in groupby(transfs, key=lambda t: (t['external_host'],
128
+ t['scope'].vo if multi_vo else None)):
129
+ transfers_by_eid = {}
130
+ for external_id, xfers in groupby(transfers_for_host, key=lambda t: t['external_id']):
131
+ transfers_by_eid[external_id] = {t['request_id']: t for t in xfers}
132
+
133
+ for chunk in dict_chunks(transfers_by_eid, fts_bulk):
134
+ try:
135
+ transfertool_cls = transfer_core.TRANSFERTOOL_CLASSES_BY_NAME.get(transfertool, FTS3Transfertool)
136
+
137
+ transfertool_kwargs = {}
138
+ if transfertool_cls.external_name == FTS3Transfertool.external_name:
139
+ transfertool_kwargs.update({
140
+ 'vo': vo,
141
+ 'oidc_support': oidc_support,
142
+ })
143
+
144
+ transfertool_obj = transfertool_cls(external_host=external_host, **transfertool_kwargs)
145
+ poll_transfers(
146
+ transfertool_obj=transfertool_obj,
147
+ transfers_by_eid=chunk,
148
+ transfer_stats_manager=transfer_stats_manager,
149
+ timeout=timeout,
150
+ logger=logger,
151
+ )
152
+ except Exception:
153
+ logger(logging.ERROR, 'Exception', exc_info=True)
154
+
155
+
156
+ def poller(
157
+ once: bool = False,
158
+ activities: Optional['Sequence[str]'] = None,
159
+ sleep_time: int = 60,
160
+ fts_bulk: int = 100,
161
+ db_bulk: int = 1000,
162
+ older_than: int = 60,
163
+ activity_shares: Optional['Mapping[str, float]'] = None,
164
+ partition_wait_time: int = 10,
165
+ transfertool: Optional[str] = TRANSFER_TOOL,
166
+ filter_transfertool: Optional[str] = FILTER_TRANSFERTOOL,
167
+ cached_topology: Optional[ExpiringObjectCache] = None,
168
+ total_threads: int = 1,
169
+ ) -> None:
170
+ """
171
+ Main loop to check the status of a transfer primitive with a transfertool.
172
+ """
173
+ timeout = config_get_float('conveyor', 'poll_timeout', default=None, raise_exception=False)
174
+ multi_vo = config_get_bool('common', 'multi_vo', False, None)
175
+ oidc_support = config_get_bool('conveyor', 'poller_oidc_support', default=False, raise_exception=False)
176
+
177
+ executable = DAEMON_NAME
178
+
179
+ if activities:
180
+ activities = sorted(activities)
181
+ executable += '--activities ' + str(activities)
182
+ if activity_shares:
183
+ executable += '--activity_shares' + str(sorted(activity_shares))
184
+ if filter_transfertool:
185
+ executable += ' --filter-transfertool ' + filter_transfertool
186
+
187
+ transfer_stats_manager = request_core.TransferStatsManager()
188
+
189
+ @db_workqueue(
190
+ once=once,
191
+ graceful_stop=GRACEFUL_STOP,
192
+ executable=executable,
193
+ partition_wait_time=partition_wait_time,
194
+ sleep_time=sleep_time,
195
+ activities=activities,
196
+ )
197
+ def _db_producer(
198
+ *,
199
+ activity: str,
200
+ heartbeat_handler: "HeartbeatHandler"
201
+ ) -> tuple[bool, list[dict[str, Any]]]:
202
+ return _fetch_requests(
203
+ db_bulk=db_bulk,
204
+ older_than=older_than,
205
+ activity_shares=activity_shares,
206
+ transfertool=transfertool,
207
+ filter_transfertool=filter_transfertool,
208
+ cached_topology=cached_topology,
209
+ activity=activity,
210
+ set_last_processed_by=not once,
211
+ heartbeat_handler=heartbeat_handler,
212
+ )
213
+
214
+ def _consumer(transfs: list[dict[str, Any]]) -> None:
215
+ return _handle_requests(
216
+ transfs=transfs,
217
+ fts_bulk=fts_bulk,
218
+ multi_vo=multi_vo,
219
+ timeout=timeout, # type: ignore (unclear if timeout is meant to be int or float)
220
+ oidc_support=oidc_support,
221
+ transfertool=transfertool, # type: ignore (transfertool is not None)
222
+ transfer_stats_manager=transfer_stats_manager,
223
+ )
224
+
225
+ with transfer_stats_manager:
226
+ ProducerConsumerDaemon(
227
+ producers=[_db_producer],
228
+ consumers=[_consumer for _ in range(total_threads)],
229
+ graceful_stop=GRACEFUL_STOP,
230
+ ).run()
231
+
232
+
233
+ def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
234
+ """
235
+ Graceful exit.
236
+ """
237
+
238
+ GRACEFUL_STOP.set()
239
+
240
+
241
+ def run(
242
+ once: bool = False,
243
+ sleep_time: int = 60,
244
+ activities: Optional['Sequence[str]'] = None,
245
+ fts_bulk: int = 100,
246
+ db_bulk: int = 1000,
247
+ older_than: int = 60,
248
+ activity_shares: Optional[str] = None,
249
+ total_threads: int = 1
250
+ ) -> None:
251
+ """
252
+ Starts up the conveyor threads.
253
+ """
254
+ setup_logging(process_name=DAEMON_NAME)
255
+
256
+ if rucio.db.sqla.util.is_old_db():
257
+ raise DatabaseException('Database was not updated, daemon won\'t start')
258
+
259
+ parsed_activity_shares = None
260
+ if activity_shares:
261
+
262
+ try:
263
+ parsed_activity_shares = {str(activity): float(share) for activity, share in json.loads(activity_shares).items()}
264
+ except Exception:
265
+ logging.critical('activity share is not a valid JSON dictionary')
266
+ return
267
+
268
+ try:
269
+ if round(sum(parsed_activity_shares.values()), 2) != 1:
270
+ logging.critical('activity shares do not sum up to 1, got %s - aborting' % round(sum(parsed_activity_shares.values()), 2))
271
+ return
272
+ except Exception:
273
+ logging.critical('activity shares are not numbers? - aborting')
274
+ return
275
+
276
+ parsed_activity_shares.update((share, int(percentage * db_bulk)) for share, percentage in parsed_activity_shares.items())
277
+ logging.info('activity shares enabled: %s' % parsed_activity_shares)
278
+
279
+ cached_topology = ExpiringObjectCache(ttl=300, new_obj_fnc=lambda: Topology())
280
+ poller(
281
+ once=once,
282
+ fts_bulk=fts_bulk,
283
+ db_bulk=db_bulk,
284
+ older_than=older_than,
285
+ sleep_time=sleep_time,
286
+ activities=activities,
287
+ activity_shares=parsed_activity_shares,
288
+ cached_topology=cached_topology,
289
+ total_threads=total_threads,
290
+ )
291
+
292
+
293
+ def poll_transfers(
294
+ transfertool_obj: 'Transfertool',
295
+ transfers_by_eid: 'Mapping[str, Mapping[str, Any]]',
296
+ transfer_stats_manager: request_core.TransferStatsManager,
297
+ timeout: "Optional[int]" = None,
298
+ logger: "LoggerFunction" = logging.log
299
+ ) -> None:
300
+ """
301
+ Poll a list of transfers from an FTS server
302
+ """
303
+
304
+ poll_individual_transfers = False
305
+ try:
306
+ _poll_transfers(transfertool_obj, transfers_by_eid, transfer_stats_manager, timeout, logger)
307
+ except TransferToolWrongAnswer:
308
+ poll_individual_transfers = True
309
+
310
+ if poll_individual_transfers:
311
+ logger(logging.ERROR, 'Problem querying %s on %s. All jobs are being checked individually' % (list(transfers_by_eid), transfertool_obj))
312
+ for external_id, transfers in transfers_by_eid.items():
313
+ logger(logging.DEBUG, 'Checking %s on %s' % (external_id, transfertool_obj))
314
+ try:
315
+ _poll_transfers(transfertool_obj, {external_id: transfers}, transfer_stats_manager, timeout, logger)
316
+ except Exception as err:
317
+ logger(logging.ERROR, 'Problem querying %s on %s . Error returned : %s' % (external_id, transfertool_obj, str(err)))
318
+
319
+
320
+ def _poll_transfers(
321
+ transfertool_obj: 'Transfertool',
322
+ transfers_by_eid: 'Mapping[str, Mapping[str, Any]]',
323
+ transfer_stats_manager: request_core.TransferStatsManager,
324
+ timeout: "Optional[int]" = None,
325
+ logger: "LoggerFunction" = logging.log
326
+ ) -> None:
327
+ """
328
+ Helper function for poll_transfers which performs the actual polling and database update.
329
+ """
330
+ is_bulk = len(transfers_by_eid) > 1
331
+ try:
332
+ stopwatch = Stopwatch()
333
+ logger(logging.INFO, 'Polling %i transfers against %s with timeout %s' % (len(transfers_by_eid), transfertool_obj, timeout))
334
+ resps = transfertool_obj.bulk_query(requests_by_eid=transfers_by_eid, timeout=timeout)
335
+ stopwatch.stop()
336
+ METRICS.timer('bulk_query_transfers').observe(stopwatch.elapsed / (len(transfers_by_eid) or 1))
337
+ logger(logging.DEBUG, 'Polled %s transfer requests status in %s seconds' % (len(transfers_by_eid), stopwatch.elapsed))
338
+ except TransferToolTimeout as error:
339
+ logger(logging.ERROR, str(error))
340
+ return
341
+ except TransferToolWrongAnswer as error:
342
+ logger(logging.ERROR, str(error))
343
+ if is_bulk:
344
+ raise # The calling context will retry transfers one-by-one
345
+ else:
346
+ return
347
+ except RequestException as error:
348
+ logger(logging.ERROR, "Failed to contact FTS server: %s" % (str(error)))
349
+ return
350
+ except Exception:
351
+ logger(logging.ERROR, "Failed to query FTS info", exc_info=True)
352
+ return
353
+
354
+ tss = time.time()
355
+ logger(logging.DEBUG, 'Updating %s transfer requests status' % (len(transfers_by_eid)))
356
+ cnt = 0
357
+
358
+ request_ids = set(itertools.chain.from_iterable(transfers_by_eid.values()))
359
+ for transfer_id in resps:
360
+ try:
361
+ transf_resp = resps[transfer_id]
362
+ # transf_resp is None: Lost.
363
+ # is Exception: Failed to get fts job status.
364
+ # is {}: No terminated jobs.
365
+ # is {request_id: {file_status}}: terminated jobs.
366
+ if transf_resp is None:
367
+ for request_id, request in transfers_by_eid[transfer_id].items():
368
+ transfer_core.mark_transfer_lost(request, logger=logger)
369
+ METRICS.counter('transfer_lost').inc()
370
+ elif isinstance(transf_resp, Exception):
371
+ logger(logging.WARNING, "Failed to poll FTS(%s) job (%s): %s" % (transfertool_obj, transfer_id, transf_resp))
372
+ METRICS.counter('query_transfer_exception').inc()
373
+ else:
374
+ for request_id in request_ids.intersection(transf_resp):
375
+ ret = transfer_core.update_transfer_state(
376
+ tt_status_report=transf_resp[request_id],
377
+ stats_manager=transfer_stats_manager,
378
+ logger=logger,
379
+ )
380
+ cnt += ret
381
+ if ret:
382
+ METRICS.counter('update_request_state.{updated}').labels(updated=True).inc(delta=ret)
383
+ else:
384
+ METRICS.counter('update_request_state.{updated}').labels(updated=False).inc()
385
+
386
+ # should touch transfers.
387
+ # Otherwise if one bulk transfer includes many requests and one is not terminated, the transfer will be poll again.
388
+ transfer_core.touch_transfer(transfertool_obj.external_host, transfer_id)
389
+ except (DatabaseException, DatabaseError) as error:
390
+ if re.match(ORACLE_RESOURCE_BUSY_REGEX, error.args[0]) or re.match(ORACLE_DEADLOCK_DETECTED_REGEX, error.args[0]) or MYSQL_LOCK_WAIT_TIMEOUT_EXCEEDED in error.args[0]:
391
+ logger(logging.WARNING, "Lock detected when handling request %s - skipping" % transfer_id)
392
+ else:
393
+ logger(logging.ERROR, 'Exception', exc_info=True)
394
+ logger(logging.DEBUG, 'Finished updating %s transfer requests status (%i requests state changed) in %s seconds' % (len(transfers_by_eid), cnt, (time.time() - tss)))
@@ -0,0 +1,205 @@
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
+ import logging
16
+ import threading
17
+ from time import time
18
+ from typing import TYPE_CHECKING, Optional
19
+
20
+ import rucio.db.sqla.util
21
+ from rucio.common import exception
22
+ from rucio.common.config import config_get_list
23
+ from rucio.common.exception import RucioException
24
+ from rucio.common.logging import setup_logging
25
+ from rucio.core import transfer as transfer_core
26
+ from rucio.core.request import RequestWithSources, list_and_mark_transfer_requests_and_source_replicas, transition_requests_state_if_possible
27
+ from rucio.core.topology import ExpiringObjectCache, Topology
28
+ from rucio.core.transfer import ProtocolFactory, build_transfer_paths, list_transfer_admin_accounts, prepare_transfers
29
+ from rucio.daemons.common import ProducerConsumerDaemon, db_workqueue
30
+ from rucio.db.sqla.constants import RequestState, RequestType
31
+
32
+ if TYPE_CHECKING:
33
+ from collections.abc import Mapping
34
+ from types import FrameType
35
+
36
+ from sqlalchemy.orm import Session
37
+
38
+ from rucio.common.types import LoggerFunction
39
+ from rucio.daemons.common import HeartbeatHandler
40
+
41
+ GRACEFUL_STOP = threading.Event()
42
+ DAEMON_NAME = 'conveyor-preparer'
43
+
44
+
45
+ def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
46
+ """
47
+ Graceful exit.
48
+ """
49
+
50
+ GRACEFUL_STOP.set()
51
+
52
+
53
+ def run(
54
+ once: bool = False,
55
+ threads: int = 1,
56
+ sleep_time: int = 10,
57
+ bulk: int = 100,
58
+ ignore_availability: bool = False
59
+ ) -> None:
60
+ """
61
+ Running the preparer daemon either once or by default in a loop until stop is called.
62
+ """
63
+ setup_logging(process_name=DAEMON_NAME)
64
+
65
+ if rucio.db.sqla.util.is_old_db():
66
+ raise exception.DatabaseException('Database was not updated, daemon won\'t start')
67
+
68
+ cached_topology = ExpiringObjectCache(ttl=300, new_obj_fnc=lambda: Topology(ignore_availability=ignore_availability))
69
+
70
+ preparer(
71
+ once=once,
72
+ sleep_time=sleep_time,
73
+ bulk=bulk,
74
+ ignore_availability=ignore_availability,
75
+ cached_topology=cached_topology,
76
+ total_threads=threads
77
+ )
78
+
79
+
80
+ def preparer(
81
+ once: bool,
82
+ sleep_time: int = 10,
83
+ bulk: int = 100,
84
+ ignore_availability: bool = False,
85
+ partition_wait_time: int = 10,
86
+ transfertools: Optional[list[str]] = None,
87
+ cached_topology: Optional[ExpiringObjectCache] = None,
88
+ total_threads: int = 1
89
+ ) -> None:
90
+ # Make an initial heartbeat so that all instanced daemons have the correct worker number on the next try
91
+ executable = DAEMON_NAME
92
+ if not transfertools:
93
+ transfertools = config_get_list('conveyor', 'transfertool', False, None)
94
+
95
+ @db_workqueue(
96
+ once=once,
97
+ graceful_stop=GRACEFUL_STOP,
98
+ executable=executable,
99
+ partition_wait_time=partition_wait_time,
100
+ sleep_time=sleep_time)
101
+ def _db_producer(
102
+ *,
103
+ activity: str,
104
+ heartbeat_handler: "HeartbeatHandler"
105
+ ) -> tuple[bool, tuple[Topology, dict[str, RequestWithSources]]]:
106
+ return _fetch_requests(
107
+ bulk=bulk,
108
+ ignore_availability=ignore_availability,
109
+ cached_topology=cached_topology,
110
+ heartbeat_handler=heartbeat_handler,
111
+ set_last_processed_by=not once,
112
+ )
113
+
114
+ def _consumer(batch: tuple[Topology, "Mapping[str, RequestWithSources]"]) -> None:
115
+ return _handle_requests(
116
+ batch,
117
+ transfertools=transfertools,
118
+ bulk=bulk,
119
+ )
120
+
121
+ ProducerConsumerDaemon(
122
+ producers=[_db_producer],
123
+ consumers=[_consumer for _ in range(total_threads)],
124
+ graceful_stop=GRACEFUL_STOP,
125
+ ).run()
126
+
127
+
128
+ def _fetch_requests(
129
+ bulk: int,
130
+ ignore_availability: bool,
131
+ cached_topology: Optional[ExpiringObjectCache],
132
+ heartbeat_handler: "HeartbeatHandler",
133
+ set_last_processed_by: bool,
134
+ *,
135
+ session: Optional["Session"] = None,
136
+ ) -> tuple[bool, tuple[Topology, dict[str, RequestWithSources]]]:
137
+ worker_number, total_workers, logger = heartbeat_handler.live()
138
+ topology = cached_topology.get() if cached_topology else Topology(ignore_availability=ignore_availability)
139
+ topology.configure_multihop(logger=logger, session=session)
140
+ requests_with_sources = list_and_mark_transfer_requests_and_source_replicas(
141
+ rse_collection=topology,
142
+ processed_by=heartbeat_handler.short_executable if set_last_processed_by else None,
143
+ total_workers=total_workers,
144
+ worker_number=worker_number,
145
+ limit=bulk,
146
+ request_state=RequestState.PREPARING,
147
+ request_type=[RequestType.TRANSFER, RequestType.STAGEIN],
148
+ ignore_availability=ignore_availability,
149
+ session=session,
150
+ )
151
+ must_sleep = False
152
+ if len(requests_with_sources) < bulk / 2:
153
+ logger(logging.INFO, "Only %s transfers, which is less than half of the bulk %s", len(requests_with_sources), bulk)
154
+ must_sleep = True
155
+ return must_sleep, (topology, requests_with_sources)
156
+
157
+
158
+ def _handle_requests(
159
+ batch: tuple[Topology, "Mapping[str, RequestWithSources]"],
160
+ *,
161
+ transfertools: Optional[list[str]] = None,
162
+ bulk: int = 100,
163
+ logger: "LoggerFunction" = logging.log,
164
+ ) -> None:
165
+ topology, requests_with_sources = batch
166
+
167
+ if not transfertools:
168
+ transfertools = list(transfer_core.TRANSFERTOOL_CLASSES_BY_NAME)
169
+
170
+ start_time = time()
171
+ try:
172
+ admin_accounts = list_transfer_admin_accounts()
173
+
174
+ ret = build_transfer_paths(
175
+ topology=topology,
176
+ protocol_factory=ProtocolFactory(),
177
+ requests_with_sources=list(requests_with_sources.values()),
178
+ admin_accounts=admin_accounts,
179
+ preparer_mode=True,
180
+ logger=logger,
181
+ )
182
+ requests_handled = sum(len(i) for i in ret)
183
+ if not requests_handled:
184
+ updated_msg = 'had nothing to do'
185
+ else:
186
+ candidate_paths, reqs_no_source, reqs_scheme_mismatch, reqs_only_tape_source, _ = ret
187
+ updated_reqs, reqs_no_transfertool = prepare_transfers(candidate_paths, transfertools=transfertools, logger=logger)
188
+ updated_msg = f'updated {len(updated_reqs)}/{bulk} requests'
189
+
190
+ if reqs_no_transfertool:
191
+ logger(logging.INFO, "Ignoring request because of unsupported transfertool: %s", reqs_no_transfertool)
192
+ reqs_no_source.update(reqs_no_transfertool)
193
+ if reqs_no_source:
194
+ logger(logging.INFO, "Marking requests as no-sources: %s", reqs_no_source)
195
+ transition_requests_state_if_possible(reqs_no_source, RequestState.NO_SOURCES, logger=logger)
196
+ if reqs_only_tape_source:
197
+ logger(logging.INFO, "Marking requests as only-tape-sources: %s", reqs_only_tape_source)
198
+ transition_requests_state_if_possible(reqs_only_tape_source, RequestState.ONLY_TAPE_SOURCES, logger=logger)
199
+ if reqs_scheme_mismatch:
200
+ logger(logging.INFO, "Marking requests as scheme-mismatch: %s", reqs_scheme_mismatch)
201
+ transition_requests_state_if_possible(reqs_scheme_mismatch, RequestState.MISMATCH_SCHEME, logger=logger)
202
+ except RucioException:
203
+ logger(logging.ERROR, 'errored with a RucioException, retrying later', exc_info=True)
204
+ updated_msg = 'errored'
205
+ logger(logging.INFO, '%s, taking %.3f seconds' % (updated_msg, time() - start_time))