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,372 @@
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
+ """
17
+ Conveyor is a daemon to manage file transfers.
18
+ """
19
+
20
+ import datetime
21
+ import itertools
22
+ import json
23
+ import logging
24
+ import re
25
+ import threading
26
+ import time
27
+ from itertools import groupby
28
+ from types import FrameType
29
+ from typing import TYPE_CHECKING, Mapping, Optional, Sequence
30
+
31
+ from requests.exceptions import RequestException
32
+ from sqlalchemy.exc import DatabaseError
33
+
34
+ import rucio.db.sqla.util
35
+ from rucio.common.config import config_get, config_get_bool
36
+ from rucio.common.exception import DatabaseException, TransferToolTimeout, TransferToolWrongAnswer
37
+ from rucio.common.logging import setup_logging
38
+ from rucio.common.stopwatch import Stopwatch
39
+ from rucio.common.types import InternalAccount
40
+ from rucio.common.utils import dict_chunks
41
+ from rucio.core import transfer as transfer_core, request as request_core
42
+ from rucio.core.monitor import MetricManager
43
+ from rucio.core.topology import Topology, ExpiringObjectCache
44
+ from rucio.daemons.common import db_workqueue, ProducerConsumerDaemon
45
+ from rucio.db.sqla.constants import RequestState, RequestType
46
+ from rucio.transfertool.fts3 import FTS3Transfertool
47
+ from rucio.transfertool.globus import GlobusTransferTool
48
+ from rucio.transfertool.mock import MockTransfertool
49
+
50
+ if TYPE_CHECKING:
51
+ from rucio.daemons.common import HeartbeatHandler
52
+
53
+ GRACEFUL_STOP = threading.Event()
54
+ METRICS = MetricManager(module=__name__)
55
+ DAEMON_NAME = 'conveyor-poller'
56
+
57
+ TRANSFER_TOOL = config_get('conveyor', 'transfertool', False, None) # NOTE: This should eventually be completely removed, as it can be fetched from the request
58
+ FILTER_TRANSFERTOOL = config_get('conveyor', 'filter_transfertool', False, None) # NOTE: TRANSFERTOOL to filter requests on
59
+
60
+
61
+ def _fetch_requests(
62
+ db_bulk,
63
+ older_than,
64
+ activity_shares,
65
+ transfertool,
66
+ filter_transfertool,
67
+ cached_topology,
68
+ activity,
69
+ set_last_processed_by: bool,
70
+ heartbeat_handler
71
+ ):
72
+ worker_number, total_workers, logger = heartbeat_handler.live()
73
+
74
+ logger(logging.DEBUG, 'Start to poll transfers older than %i seconds for activity %s using transfer tool: %s' % (older_than, activity, filter_transfertool))
75
+
76
+ topology = cached_topology.get() if cached_topology else Topology()
77
+ transfs = request_core.get_and_mark_next(
78
+ rse_collection=topology,
79
+ request_type=[RequestType.TRANSFER, RequestType.STAGEIN, RequestType.STAGEOUT],
80
+ state=[RequestState.SUBMITTED],
81
+ processed_by=heartbeat_handler.short_executable if set_last_processed_by else None,
82
+ limit=db_bulk,
83
+ older_than=datetime.datetime.utcnow() - datetime.timedelta(seconds=older_than) if older_than else None,
84
+ total_workers=total_workers,
85
+ worker_number=worker_number,
86
+ mode_all=True,
87
+ hash_variable='id',
88
+ activity=activity,
89
+ activity_shares=activity_shares,
90
+ transfertool=filter_transfertool,
91
+ )
92
+
93
+ if transfertool and not filter_transfertool:
94
+ # only keep transfers which don't have any transfertool set, or have one equal to TRANSFER_TOOL
95
+ transfs_tmp = [t for t in transfs if not t['transfertool'] or t['transfertool'] == transfertool]
96
+ if len(transfs_tmp) != len(transfs):
97
+ logger(logging.INFO, 'Skipping %i transfers because of missmatched transfertool', len(transfs) - len(transfs_tmp))
98
+ transfs = transfs_tmp
99
+
100
+ if transfs:
101
+ logger(logging.DEBUG, 'Polling %i transfers for activity %s' % (len(transfs), activity))
102
+
103
+ must_sleep = False
104
+ if len(transfs) < db_bulk / 2:
105
+ logger(logging.INFO, "Only %s transfers for activity %s, which is less than half of the bulk %s" % (len(transfs), activity, db_bulk))
106
+ must_sleep = True
107
+
108
+ return must_sleep, transfs
109
+
110
+
111
+ def _handle_requests(
112
+ transfs,
113
+ fts_bulk,
114
+ multi_vo,
115
+ timeout,
116
+ transfertool,
117
+ oidc_account: Optional[str],
118
+ *,
119
+ logger=logging.log,
120
+ ):
121
+ transfs.sort(key=lambda t: (t['external_host'] or '',
122
+ t['scope'].vo if multi_vo else '',
123
+ t['external_id'] or '',
124
+ t['request_id'] or ''))
125
+ for (external_host, vo), transfers_for_host in groupby(transfs, key=lambda t: (t['external_host'],
126
+ t['scope'].vo if multi_vo else None)):
127
+ transfers_by_eid = {}
128
+ for external_id, xfers in groupby(transfers_for_host, key=lambda t: t['external_id']):
129
+ transfers_by_eid[external_id] = {t['request_id']: t for t in xfers}
130
+
131
+ for chunk in dict_chunks(transfers_by_eid, fts_bulk):
132
+ try:
133
+ if transfertool == 'mock':
134
+ transfertool_obj = MockTransfertool(external_host=MockTransfertool.external_name)
135
+ elif transfertool == 'globus':
136
+ transfertool_obj = GlobusTransferTool(external_host=GlobusTransferTool.external_name)
137
+ else:
138
+ account = None
139
+ if oidc_account:
140
+ if vo:
141
+ account = InternalAccount(oidc_account, vo=vo)
142
+ else:
143
+ account = InternalAccount(oidc_account)
144
+ transfertool_obj = FTS3Transfertool(external_host=external_host, vo=vo, oidc_account=account)
145
+ poll_transfers(transfertool_obj=transfertool_obj, transfers_by_eid=chunk, timeout=timeout, logger=logger)
146
+ except Exception:
147
+ logger(logging.ERROR, 'Exception', exc_info=True)
148
+
149
+
150
+ def poller(
151
+ once: bool = False,
152
+ activities: Optional[Sequence[str]] = None,
153
+ sleep_time: int = 60,
154
+ fts_bulk: int = 100,
155
+ db_bulk: int = 1000,
156
+ older_than: int = 60,
157
+ activity_shares: Optional[Mapping[str, float]] = None,
158
+ partition_wait_time: int = 10,
159
+ transfertool: Optional[str] = TRANSFER_TOOL,
160
+ filter_transfertool: Optional[str] = FILTER_TRANSFERTOOL,
161
+ cached_topology=None,
162
+ total_threads: int = 1,
163
+ ):
164
+ """
165
+ Main loop to check the status of a transfer primitive with a transfertool.
166
+ """
167
+
168
+ timeout = config_get('conveyor', 'poll_timeout', default=None, raise_exception=False)
169
+ if timeout:
170
+ timeout = float(timeout)
171
+
172
+ multi_vo = config_get_bool('common', 'multi_vo', False, None)
173
+ oidc_account = config_get('conveyor', 'poller_oidc_account', False, None)
174
+
175
+ executable = DAEMON_NAME
176
+
177
+ if activities:
178
+ activities = sorted(activities)
179
+ executable += '--activities ' + str(activities)
180
+ if activity_shares:
181
+ executable += '--activity_shares' + str(sorted(activity_shares))
182
+ if filter_transfertool:
183
+ executable += ' --filter-transfertool ' + filter_transfertool
184
+
185
+ @db_workqueue(
186
+ once=once,
187
+ graceful_stop=GRACEFUL_STOP,
188
+ executable=executable,
189
+ partition_wait_time=partition_wait_time,
190
+ sleep_time=sleep_time,
191
+ activities=activities,
192
+ )
193
+ def _db_producer(*, activity: str, heartbeat_handler: "HeartbeatHandler"):
194
+ return _fetch_requests(
195
+ db_bulk=db_bulk,
196
+ older_than=older_than,
197
+ activity_shares=activity_shares,
198
+ transfertool=transfertool,
199
+ filter_transfertool=filter_transfertool,
200
+ cached_topology=cached_topology,
201
+ activity=activity,
202
+ set_last_processed_by=not once,
203
+ heartbeat_handler=heartbeat_handler,
204
+ )
205
+
206
+ def _consumer(transfs):
207
+ return _handle_requests(
208
+ transfs=transfs,
209
+ fts_bulk=fts_bulk,
210
+ multi_vo=multi_vo,
211
+ timeout=timeout,
212
+ oidc_account=oidc_account,
213
+ transfertool=transfertool,
214
+ )
215
+
216
+ ProducerConsumerDaemon(
217
+ producers=[_db_producer],
218
+ consumers=[_consumer for _ in range(total_threads)],
219
+ graceful_stop=GRACEFUL_STOP,
220
+ ).run()
221
+
222
+
223
+ def stop(signum: Optional[int] = None, frame: Optional[FrameType] = None) -> None:
224
+ """
225
+ Graceful exit.
226
+ """
227
+
228
+ GRACEFUL_STOP.set()
229
+
230
+
231
+ def run(
232
+ once=False,
233
+ sleep_time=60,
234
+ activities=None,
235
+ fts_bulk=100,
236
+ db_bulk=1000,
237
+ older_than=60,
238
+ activity_shares: Optional[str] = None,
239
+ total_threads=1
240
+ ):
241
+ """
242
+ Starts up the conveyer threads.
243
+ """
244
+ setup_logging(process_name=DAEMON_NAME)
245
+
246
+ if rucio.db.sqla.util.is_old_db():
247
+ raise DatabaseException('Database was not updated, daemon won\'t start')
248
+
249
+ parsed_activity_shares = None
250
+ if activity_shares:
251
+
252
+ try:
253
+ parsed_activity_shares = {str(activity): float(share) for activity, share in json.loads(activity_shares).items()}
254
+ except Exception:
255
+ logging.critical('activity share is not a valid JSON dictionary')
256
+ return
257
+
258
+ try:
259
+ if round(sum(parsed_activity_shares.values()), 2) != 1:
260
+ logging.critical('activity shares do not sum up to 1, got %s - aborting' % round(sum(parsed_activity_shares.values()), 2))
261
+ return
262
+ except Exception:
263
+ logging.critical('activity shares are not numbers? - aborting')
264
+ return
265
+
266
+ parsed_activity_shares.update((share, int(percentage * db_bulk)) for share, percentage in parsed_activity_shares.items())
267
+ logging.info('activity shares enabled: %s' % parsed_activity_shares)
268
+
269
+ cached_topology = ExpiringObjectCache(ttl=300, new_obj_fnc=lambda: Topology())
270
+ poller(
271
+ once=once,
272
+ fts_bulk=fts_bulk,
273
+ db_bulk=db_bulk,
274
+ older_than=older_than,
275
+ sleep_time=sleep_time,
276
+ activities=activities,
277
+ activity_shares=parsed_activity_shares,
278
+ cached_topology=cached_topology,
279
+ total_threads=total_threads,
280
+ )
281
+
282
+
283
+ def poll_transfers(transfertool_obj, transfers_by_eid, timeout=None, logger=logging.log):
284
+ """
285
+ Poll a list of transfers from an FTS server
286
+
287
+ :param transfertool_obj: The Transfertool to use for query
288
+ :param transfers_by_eid: Dict of the form {external_id: list_of_transfers}
289
+ :param timeout: Timeout.
290
+ :param logger: Optional decorated logger that can be passed from the calling daemons or servers.
291
+ """
292
+
293
+ poll_individual_transfers = False
294
+ try:
295
+ _poll_transfers(transfertool_obj, transfers_by_eid, timeout, logger)
296
+ except TransferToolWrongAnswer:
297
+ poll_individual_transfers = True
298
+
299
+ if poll_individual_transfers:
300
+ logger(logging.ERROR, 'Problem querying %s on %s. All jobs are being checked individually' % (list(transfers_by_eid), transfertool_obj))
301
+ for external_id, transfers in transfers_by_eid.items():
302
+ logger(logging.DEBUG, 'Checking %s on %s' % (external_id, transfertool_obj))
303
+ try:
304
+ _poll_transfers(transfertool_obj, {external_id: transfers}, timeout, logger)
305
+ except Exception as err:
306
+ logger(logging.ERROR, 'Problem querying %s on %s . Error returned : %s' % (external_id, transfertool_obj, str(err)))
307
+
308
+
309
+ def _poll_transfers(transfertool_obj, transfers_by_eid, timeout, logger):
310
+ """
311
+ Helper function for poll_transfers which performs the actual polling and database update.
312
+ """
313
+ is_bulk = len(transfers_by_eid) > 1
314
+ try:
315
+ stopwatch = Stopwatch()
316
+ logger(logging.INFO, 'Polling %i transfers against %s with timeout %s' % (len(transfers_by_eid), transfertool_obj, timeout))
317
+ resps = transfertool_obj.bulk_query(requests_by_eid=transfers_by_eid, timeout=timeout)
318
+ stopwatch.stop()
319
+ METRICS.timer('bulk_query_transfers').observe(stopwatch.elapsed / (len(transfers_by_eid) or 1))
320
+ logger(logging.DEBUG, 'Polled %s transfer requests status in %s seconds' % (len(transfers_by_eid), stopwatch.elapsed))
321
+ except TransferToolTimeout as error:
322
+ logger(logging.ERROR, str(error))
323
+ return
324
+ except TransferToolWrongAnswer as error:
325
+ logger(logging.ERROR, str(error))
326
+ if is_bulk:
327
+ raise # The calling context will retry transfers one-by-one
328
+ else:
329
+ return
330
+ except RequestException as error:
331
+ logger(logging.ERROR, "Failed to contact FTS server: %s" % (str(error)))
332
+ return
333
+ except Exception:
334
+ logger(logging.ERROR, "Failed to query FTS info", exc_info=True)
335
+ return
336
+
337
+ tss = time.time()
338
+ logger(logging.DEBUG, 'Updating %s transfer requests status' % (len(transfers_by_eid)))
339
+ cnt = 0
340
+
341
+ request_ids = set(itertools.chain.from_iterable(transfers_by_eid.values()))
342
+ for transfer_id in resps:
343
+ try:
344
+ transf_resp = resps[transfer_id]
345
+ # transf_resp is None: Lost.
346
+ # is Exception: Failed to get fts job status.
347
+ # is {}: No terminated jobs.
348
+ # is {request_id: {file_status}}: terminated jobs.
349
+ if transf_resp is None:
350
+ for request_id, request in transfers_by_eid[transfer_id].items():
351
+ transfer_core.mark_transfer_lost(request, logger=logger)
352
+ METRICS.counter('transfer_lost').inc()
353
+ elif isinstance(transf_resp, Exception):
354
+ logger(logging.WARNING, "Failed to poll FTS(%s) job (%s): %s" % (transfertool_obj, transfer_id, transf_resp))
355
+ METRICS.counter('query_transfer_exception').inc()
356
+ else:
357
+ for request_id in request_ids.intersection(transf_resp):
358
+ ret = transfer_core.update_transfer_state(transf_resp[request_id], logger=logger)
359
+ # if True, really update request content; if False, only touch request
360
+ if ret:
361
+ cnt += 1
362
+ METRICS.counter('update_request_state.{updated}').labels(updated=ret).inc()
363
+
364
+ # should touch transfers.
365
+ # Otherwise if one bulk transfer includes many requests and one is not terminated, the transfer will be poll again.
366
+ transfer_core.touch_transfer(transfertool_obj.external_host, transfer_id)
367
+ except (DatabaseException, DatabaseError) as error:
368
+ if re.match('.*ORA-00054.*', error.args[0]) or re.match('.*ORA-00060.*', error.args[0]) or 'ERROR 1205 (HY000)' in error.args[0]:
369
+ logger(logging.WARNING, "Lock detected when handling request %s - skipping" % transfer_id)
370
+ else:
371
+ logger(logging.ERROR, 'Exception', exc_info=True)
372
+ 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,198 @@
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 logging
17
+ import threading
18
+ from time import time
19
+ from types import FrameType
20
+ from typing import TYPE_CHECKING, Optional
21
+
22
+ import rucio.db.sqla.util
23
+ from rucio.common import exception
24
+ from rucio.common.config import config_get_list
25
+ from rucio.common.exception import RucioException
26
+ from rucio.common.logging import setup_logging
27
+ from rucio.core import transfer as transfer_core
28
+ from rucio.core.request import set_requests_state_if_possible, list_and_mark_transfer_requests_and_source_replicas
29
+ from rucio.core.topology import Topology, ExpiringObjectCache
30
+ from rucio.core.transfer import prepare_transfers, list_transfer_admin_accounts, build_transfer_paths, ProtocolFactory
31
+ from rucio.daemons.common import db_workqueue, ProducerConsumerDaemon
32
+ from rucio.db.sqla.constants import RequestState, RequestType
33
+
34
+ if TYPE_CHECKING:
35
+ from sqlalchemy.orm import Session
36
+ from rucio.daemons.common import HeartbeatHandler
37
+
38
+ GRACEFUL_STOP = threading.Event()
39
+ DAEMON_NAME = 'conveyor-preparer'
40
+
41
+
42
+ def stop(signum: Optional[int] = None, frame: Optional[FrameType] = None) -> None:
43
+ """
44
+ Graceful exit.
45
+ """
46
+
47
+ GRACEFUL_STOP.set()
48
+
49
+
50
+ def run(
51
+ once=False,
52
+ threads=1,
53
+ sleep_time=10,
54
+ bulk=100,
55
+ ignore_availability: bool = False
56
+ ):
57
+ """
58
+ Running the preparer daemon either once or by default in a loop until stop is called.
59
+ """
60
+ setup_logging(process_name=DAEMON_NAME)
61
+
62
+ if rucio.db.sqla.util.is_old_db():
63
+ raise exception.DatabaseException('Database was not updated, daemon won\'t start')
64
+
65
+ cached_topology = ExpiringObjectCache(ttl=300, new_obj_fnc=lambda: Topology(ignore_availability=ignore_availability))
66
+
67
+ preparer(
68
+ once=once,
69
+ sleep_time=sleep_time,
70
+ bulk=bulk,
71
+ ignore_availability=ignore_availability,
72
+ cached_topology=cached_topology,
73
+ total_threads=threads
74
+ )
75
+
76
+
77
+ def preparer(
78
+ once,
79
+ sleep_time: int = 10,
80
+ bulk: int = 100,
81
+ ignore_availability: bool = False,
82
+ partition_wait_time: int = 10,
83
+ transfertools=None,
84
+ cached_topology=None,
85
+ total_threads=1
86
+ ):
87
+ # Make an initial heartbeat so that all instanced daemons have the correct worker number on the next try
88
+ executable = DAEMON_NAME
89
+ if not transfertools:
90
+ transfertools = config_get_list('conveyor', 'transfertool', False, None)
91
+
92
+ @db_workqueue(
93
+ once=once,
94
+ graceful_stop=GRACEFUL_STOP,
95
+ executable=executable,
96
+ partition_wait_time=partition_wait_time,
97
+ sleep_time=sleep_time)
98
+ def _db_producer(*, activity: str, heartbeat_handler: "HeartbeatHandler"):
99
+ return _fetch_requests(
100
+ bulk=bulk,
101
+ ignore_availability=ignore_availability,
102
+ cached_topology=cached_topology,
103
+ heartbeat_handler=heartbeat_handler,
104
+ set_last_processed_by=not once,
105
+ )
106
+
107
+ def _consumer(batch):
108
+ return _handle_requests(
109
+ batch,
110
+ transfertools=transfertools,
111
+ bulk=bulk,
112
+ )
113
+
114
+ ProducerConsumerDaemon(
115
+ producers=[_db_producer],
116
+ consumers=[_consumer for _ in range(total_threads)],
117
+ graceful_stop=GRACEFUL_STOP,
118
+ ).run()
119
+
120
+
121
+ def _fetch_requests(
122
+ bulk: int,
123
+ ignore_availability: bool,
124
+ cached_topology,
125
+ heartbeat_handler: "HeartbeatHandler",
126
+ set_last_processed_by: bool,
127
+ *,
128
+ session: "Optional[Session]" = None,
129
+ ):
130
+ worker_number, total_workers, logger = heartbeat_handler.live()
131
+ topology = cached_topology.get() if cached_topology else Topology(ignore_availability=ignore_availability)
132
+ topology.configure_multihop(logger=logger, session=session)
133
+ requests_with_sources = list_and_mark_transfer_requests_and_source_replicas(
134
+ rse_collection=topology,
135
+ processed_by=heartbeat_handler.short_executable if set_last_processed_by else None,
136
+ total_workers=total_workers,
137
+ worker_number=worker_number,
138
+ limit=bulk,
139
+ request_state=RequestState.PREPARING,
140
+ request_type=[RequestType.TRANSFER, RequestType.STAGEIN],
141
+ ignore_availability=ignore_availability,
142
+ session=session,
143
+ )
144
+ must_sleep = False
145
+ if len(requests_with_sources) < bulk / 2:
146
+ logger(logging.INFO, "Only %s transfers, which is less than half of the bulk %s", len(requests_with_sources), bulk)
147
+ must_sleep = True
148
+ return must_sleep, (topology, requests_with_sources)
149
+
150
+
151
+ def _handle_requests(
152
+ batch,
153
+ *,
154
+ transfertools: Optional[list[str]] = None,
155
+ bulk: int = 100,
156
+ logger=logging.log,
157
+ ):
158
+ topology, requests_with_sources = batch
159
+
160
+ if not transfertools:
161
+ transfertools = list(transfer_core.TRANSFERTOOL_CLASSES_BY_NAME)
162
+
163
+ start_time = time()
164
+ try:
165
+ admin_accounts = list_transfer_admin_accounts()
166
+
167
+ ret = build_transfer_paths(
168
+ topology=topology,
169
+ protocol_factory=ProtocolFactory(),
170
+ requests_with_sources=list(requests_with_sources.values()),
171
+ admin_accounts=admin_accounts,
172
+ preparer_mode=True,
173
+ logger=logger,
174
+ )
175
+ requests_handled = sum(len(i) for i in ret)
176
+ if not requests_handled:
177
+ updated_msg = 'had nothing to do'
178
+ else:
179
+ candidate_paths, reqs_no_source, reqs_scheme_mismatch, reqs_only_tape_source, _ = ret
180
+ updated_reqs, reqs_no_transfertool = prepare_transfers(candidate_paths, transfertools=transfertools, logger=logger)
181
+ updated_msg = f'updated {len(updated_reqs)}/{bulk} requests'
182
+
183
+ if reqs_no_transfertool:
184
+ logger(logging.INFO, "Ignoring request because of unsupported transfertool: %s", reqs_no_transfertool)
185
+ reqs_no_source.update(reqs_no_transfertool)
186
+ if reqs_no_source:
187
+ logger(logging.INFO, "Marking requests as no-sources: %s", reqs_no_source)
188
+ set_requests_state_if_possible(reqs_no_source, RequestState.NO_SOURCES, logger=logger)
189
+ if reqs_only_tape_source:
190
+ logger(logging.INFO, "Marking requests as only-tape-sources: %s", reqs_only_tape_source)
191
+ set_requests_state_if_possible(reqs_only_tape_source, RequestState.ONLY_TAPE_SOURCES, logger=logger)
192
+ if reqs_scheme_mismatch:
193
+ logger(logging.INFO, "Marking requests as scheme-mismatch: %s", reqs_scheme_mismatch)
194
+ set_requests_state_if_possible(reqs_scheme_mismatch, RequestState.MISMATCH_SCHEME, logger=logger)
195
+ except RucioException:
196
+ logger(logging.ERROR, 'errored with a RucioException, retrying later', exc_info=True)
197
+ updated_msg = 'errored'
198
+ logger(logging.INFO, '%s, taking %.3f seconds' % (updated_msg, time() - start_time))