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,198 @@
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
+ OAuth Manager is a daemon which is responsible for:
17
+ - deletion of expired access tokens (in case there is a valid refresh token,
18
+ expired access tokens will be kept until refresh_token expires as well.)
19
+ - deletion of expired OAuth session parameters
20
+ - refreshing access tokens via their refresh tokens.
21
+
22
+ These 3 actions run consequently one after another in a loop with a sleeptime of 'looprate' seconds.
23
+ The maximum number of DB rows (tokens, parameters, refresh tokens) on which the script will operate
24
+ can be specified by 'max_rows' parameter.
25
+
26
+ """
27
+
28
+ import functools
29
+ import logging
30
+ import threading
31
+ import traceback
32
+ from re import match
33
+ from typing import TYPE_CHECKING
34
+
35
+ from sqlalchemy.exc import DatabaseError
36
+
37
+ import rucio.db.sqla.util
38
+ from rucio.common.exception import DatabaseException
39
+ from rucio.common.logging import setup_logging
40
+ from rucio.common.stopwatch import Stopwatch
41
+ from rucio.core.authentication import delete_expired_tokens
42
+ from rucio.core.monitor import MetricManager
43
+ from rucio.core.oidc import delete_expired_oauthrequests, refresh_jwt_tokens
44
+ from rucio.daemons.common import HeartbeatHandler, run_daemon
45
+ from rucio.db.sqla.constants import ORACLE_CONNECTION_LOST_CONTACT_REGEX
46
+
47
+ if TYPE_CHECKING:
48
+ from types import FrameType
49
+ from typing import Optional
50
+
51
+ METRICS = MetricManager(module=__name__)
52
+ graceful_stop = threading.Event()
53
+ DAEMON_NAME = 'oauth-manager'
54
+
55
+
56
+ def oauth_manager(once: bool = False, max_rows: int = 100, sleep_time: int = 300) -> None:
57
+ """
58
+ Main loop to delete all expired tokens, refresh tokens eligible
59
+ for refresh and delete all expired OAuth session parameters.
60
+ It was decided to have only 1 daemon for all 3 of these cleanup activities.
61
+
62
+ :param once: If True, the loop is run just once, otherwise the daemon continues looping until stopped.
63
+ :param max_rows: Max number of DB rows to deal with per operation.
64
+ :param sleep_time: The number of seconds the daemon will wait before running next loop of operations.
65
+
66
+ :returns: None
67
+ """
68
+
69
+ run_daemon(
70
+ once=once,
71
+ graceful_stop=graceful_stop,
72
+ executable=DAEMON_NAME,
73
+ partition_wait_time=1,
74
+ sleep_time=sleep_time,
75
+ run_once_fnc=functools.partial(
76
+ run_once,
77
+ max_rows=max_rows,
78
+ sleep_time=sleep_time
79
+ ),
80
+ )
81
+
82
+
83
+ def run_once(heartbeat_handler: HeartbeatHandler, max_rows: int, sleep_time: int, **_kwargs) -> None:
84
+
85
+ # make an initial heartbeat
86
+ heartbeat_handler.live()
87
+
88
+ stopwatch = Stopwatch()
89
+
90
+ ndeleted = 0
91
+ ndeletedreq = 0
92
+ nrefreshed = 0
93
+
94
+ # make a heartbeat
95
+ worker_number, total_workers, logger = heartbeat_handler.live()
96
+ try:
97
+ # ACCESS TOKEN REFRESH - better to run first (in case some of the refreshed tokens needed deletion after this step)
98
+ logger(logging.INFO, '----- START ----- ACCESS TOKEN REFRESH ----- ')
99
+ logger(logging.INFO, 'starting to query tokens for automatic refresh')
100
+ nrefreshed = refresh_jwt_tokens(total_workers, worker_number, refreshrate=int(sleep_time), limit=max_rows)
101
+ logger(logging.INFO, 'successfully refreshed %i tokens', nrefreshed)
102
+ logger(logging.INFO, '----- END ----- ACCESS TOKEN REFRESH ----- ')
103
+ METRICS.counter(name='oauth_manager.tokens.refreshed').inc(nrefreshed)
104
+
105
+ except (DatabaseException, DatabaseError) as err:
106
+ if match('.*QueuePool.*', str(err.args[0])):
107
+ logger(logging.WARNING, traceback.format_exc())
108
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
109
+ elif match(ORACLE_CONNECTION_LOST_CONTACT_REGEX, str(err.args[0])):
110
+ logger(logging.WARNING, traceback.format_exc())
111
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
112
+ else:
113
+ logger(logging.CRITICAL, traceback.format_exc())
114
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
115
+
116
+ try:
117
+ # waiting 1 sec as DBs does not store millisecond and tokens
118
+ # eligible for deletion after refresh might not get deleted otherwise
119
+ graceful_stop.wait(1)
120
+
121
+ # make a heartbeat
122
+ worker_number, total_workers, logger = heartbeat_handler.live()
123
+
124
+ # EXPIRED TOKEN DELETION
125
+ logger(logging.INFO, '----- START ----- DELETION OF EXPIRED TOKENS ----- ')
126
+ logger(logging.INFO, 'starting to delete expired tokens')
127
+ ndeleted += delete_expired_tokens(total_workers, worker_number, limit=max_rows)
128
+ logger(logging.INFO, 'deleted %i expired tokens', ndeleted)
129
+ logger(logging.INFO, '----- END ----- DELETION OF EXPIRED TOKENS ----- ')
130
+ METRICS.counter(name='oauth_manager.tokens.deleted').inc(ndeleted)
131
+
132
+ except (DatabaseException, DatabaseError) as err:
133
+ if match('.*QueuePool.*', str(err.args[0])):
134
+ logger(logging.WARNING, traceback.format_exc())
135
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
136
+ elif match(ORACLE_CONNECTION_LOST_CONTACT_REGEX, str(err.args[0])):
137
+ logger(logging.WARNING, traceback.format_exc())
138
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
139
+ else:
140
+ logger(logging.CRITICAL, traceback.format_exc())
141
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
142
+
143
+ try:
144
+ # make a heartbeat
145
+ worker_number, total_workers, logger = heartbeat_handler.live()
146
+
147
+ # DELETING EXPIRED OAUTH SESSION PARAMETERS
148
+ logger(logging.INFO, '----- START ----- DELETION OF EXPIRED OAUTH SESSION REQUESTS ----- ')
149
+ logger(logging.INFO, 'starting deletion of expired OAuth session requests')
150
+ ndeletedreq += delete_expired_oauthrequests(total_workers, worker_number, limit=max_rows)
151
+ logger(logging.INFO, 'expired parameters of %i authentication requests were deleted', ndeletedreq)
152
+ logger(logging.INFO, '----- END ----- DELETION OF EXPIRED OAUTH SESSION REQUESTS ----- ')
153
+ METRICS.counter(name='oauth_manager.oauthreq.deleted').inc(ndeletedreq)
154
+
155
+ except (DatabaseException, DatabaseError) as err:
156
+ if match('.*QueuePool.*', str(err.args[0])):
157
+ logger(logging.WARNING, traceback.format_exc())
158
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
159
+ elif match(ORACLE_CONNECTION_LOST_CONTACT_REGEX, str(err.args[0])):
160
+ logger(logging.WARNING, traceback.format_exc())
161
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
162
+ else:
163
+ logger(logging.CRITICAL, traceback.format_exc())
164
+ METRICS.counter('exceptions.{exception}').labels(exception=err.__class__.__name__).inc()
165
+
166
+ stopwatch.stop()
167
+ logger(logging.INFO, 'took %f seconds to delete %i tokens, %i session parameters and refreshed %i tokens', stopwatch.elapsed, ndeleted, ndeletedreq, nrefreshed)
168
+ METRICS.timer('duration').observe(stopwatch.elapsed)
169
+
170
+
171
+ def run(once: bool = False, threads: int = 1, max_rows: int = 100, sleep_time: int = 300) -> None:
172
+ """
173
+ Starts up the OAuth Manager threads.
174
+ """
175
+ setup_logging(process_name=DAEMON_NAME)
176
+
177
+ if rucio.db.sqla.util.is_old_db():
178
+ raise DatabaseException('Database was not updated, daemon won\'t start')
179
+
180
+ if once:
181
+ oauth_manager(once, max_rows, sleep_time)
182
+ else:
183
+ logging.info('OAuth Manager starting %s threads', str(threads))
184
+ threads = [threading.Thread(target=oauth_manager,
185
+ kwargs={'once': once,
186
+ 'max_rows': max_rows,
187
+ 'sleep_time': sleep_time}) for i in range(0, threads)]
188
+ _ = [t.start() for t in threads]
189
+ # Interruptible joins require a timeout.
190
+ while threads[0].is_alive():
191
+ _ = [t.join(timeout=3.14) for t in threads]
192
+
193
+
194
+ def stop(signum: "Optional[int]" = None, frame: "Optional[FrameType]" = None) -> None:
195
+ """
196
+ Graceful exit.
197
+ """
198
+ graceful_stop.set()
@@ -0,0 +1,13 @@
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.
@@ -0,0 +1,282 @@
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
+ Dark Reaper is a daemon to manage quarantined file deletion.
17
+ '''
18
+
19
+ import functools
20
+ import logging
21
+ import random
22
+ import sys
23
+ import threading
24
+ import time
25
+ import traceback
26
+ from typing import TYPE_CHECKING
27
+
28
+ import rucio.core.rse as rse_core
29
+ import rucio.db.sqla.util
30
+ from rucio.common import exception
31
+ from rucio.common.config import config_get_bool
32
+ from rucio.common.exception import ResourceTemporaryUnavailable, RSEAccessDenied, RSENotFound, ServiceUnavailable, SourceNotFound, VONotFound
33
+ from rucio.common.logging import setup_logging
34
+ from rucio.core.message import add_message
35
+ from rucio.core.monitor import MetricManager
36
+ from rucio.core.quarantined_replica import delete_quarantined_replicas, list_quarantined_replicas, list_rses_with_quarantined_replicas
37
+ from rucio.core.rse_expression_parser import parse_expression
38
+ from rucio.core.vo import list_vos
39
+ from rucio.daemons.common import run_daemon
40
+ from rucio.rse import rsemanager as rsemgr
41
+
42
+ if TYPE_CHECKING:
43
+ from collections.abc import Sequence
44
+ from types import FrameType
45
+ from typing import Optional
46
+
47
+ from rucio.common.types import LFNDict
48
+ from rucio.daemons.common import HeartbeatHandler
49
+
50
+ logging.getLogger("requests").setLevel(logging.CRITICAL)
51
+
52
+ METRICS = MetricManager(module=__name__)
53
+ GRACEFUL_STOP = threading.Event()
54
+ DAEMON_NAME = 'dark-reaper'
55
+
56
+
57
+ def reaper(
58
+ rses: "Sequence[str]",
59
+ chunk_size: int = 100,
60
+ once: bool = False,
61
+ scheme: "Optional[str]" = None,
62
+ sleep_time: int = 300,
63
+ ):
64
+ executable = DAEMON_NAME
65
+ if rses:
66
+ executable += ' '.join(sys.argv[1:])
67
+ run_daemon(
68
+ once=once,
69
+ graceful_stop=GRACEFUL_STOP,
70
+ executable=executable,
71
+ partition_wait_time=10,
72
+ sleep_time=sleep_time,
73
+ run_once_fnc=functools.partial(
74
+ run_once,
75
+ rses=rses,
76
+ chunk_size=chunk_size,
77
+ scheme=scheme,
78
+ ),
79
+ )
80
+
81
+
82
+ def run_once(
83
+ rses: "Sequence[str]",
84
+ heartbeat_handler: "HeartbeatHandler",
85
+ chunk_size: int = 100,
86
+ scheme: "Optional[str]" = None,
87
+ **_kwargs,
88
+ ):
89
+ """
90
+ Main loop to select and delete files.
91
+
92
+ :param rses: List of RSEs the reaper should work against.
93
+ :param chunk_size: the size of chunk for deletion.
94
+ :param scheme: Force the reaper to use a particular protocol, e.g., mock.
95
+ """
96
+ worker_number, total_workers, logger = heartbeat_handler.live()
97
+ logger(logging.INFO, 'Starting Dark Reaper on RSEs: %s', ', '.join(rses))
98
+
99
+ nothing_to_do = True
100
+ rses_to_process = list(set(rses) & set(list_rses_with_quarantined_replicas()))
101
+ random.shuffle(rses_to_process)
102
+ for rse_id in rses_to_process:
103
+ worker_number, total_workers, logger = heartbeat_handler.live()
104
+ # The following query returns the list of real replicas (deleted_replicas) and list of dark replicas (dark_replicas)
105
+ # Real replicas can be directly removed from the quarantine table
106
+ deleted_replicas, dark_replicas = list_quarantined_replicas(rse_id=rse_id,
107
+ limit=chunk_size,
108
+ worker_number=worker_number,
109
+ total_workers=total_workers)
110
+
111
+ rse_info = rsemgr.get_rse_info(rse_id=rse_id)
112
+ rse = rse_info['rse']
113
+ prot = rsemgr.create_protocol(rse_info, 'delete', scheme=scheme)
114
+
115
+ try:
116
+ prot.connect()
117
+ for replica in dark_replicas:
118
+ worker_number, total_workers, logger = heartbeat_handler.live()
119
+ nothing_to_do = False
120
+ scope = ''
121
+ if replica['scope']:
122
+ scope = replica['scope'].external
123
+ try:
124
+ lfn: "LFNDict" = {
125
+ 'scope': scope,
126
+ 'name': replica['name'],
127
+ 'path': replica['path']
128
+ }
129
+ pfn = str(list(rsemgr.lfns2pfns(rse_settings=rse_info,
130
+ lfns=[lfn],
131
+ operation='delete',
132
+ scheme=scheme).values())[0])
133
+ logger(logging.INFO, 'Deletion ATTEMPT of %s:%s as %s on %s', scope, replica['name'], pfn, rse)
134
+ start = time.time()
135
+ prot.delete(pfn)
136
+ METRICS.counter('deleted_replicas').inc()
137
+ duration = time.time() - start
138
+ logger(logging.INFO, 'Deletion SUCCESS of %s:%s as %s on %s in %s seconds', scope, replica['name'], pfn, rse, duration)
139
+ payload = {'scope': scope,
140
+ 'name': replica['name'],
141
+ 'rse': rse,
142
+ 'rse_id': rse_id,
143
+ 'file-size': replica.get('bytes') or 0,
144
+ 'bytes': replica.get('bytes') or 0,
145
+ 'url': pfn,
146
+ 'duration': duration,
147
+ 'protocol': prot.attributes['scheme']}
148
+ if replica['scope'].vo != 'def':
149
+ payload['vo'] = replica['scope'].vo
150
+ add_message('deletion-done', payload)
151
+ deleted_replicas.append(replica)
152
+ except SourceNotFound:
153
+ err_msg = ('Deletion NOTFOUND of %s:%s as %s on %s'
154
+ % (scope, replica['name'], pfn, rse))
155
+ logger(logging.WARNING, err_msg)
156
+ deleted_replicas.append(replica)
157
+ except (ServiceUnavailable, RSEAccessDenied, ResourceTemporaryUnavailable) as error:
158
+ err_msg = ('Deletion NOACCESS of %s:%s as %s on %s: %s'
159
+ % (scope, replica['name'], pfn, rse, str(error)))
160
+ logger(logging.WARNING, err_msg)
161
+ payload = {'scope': scope,
162
+ 'name': replica['name'],
163
+ 'rse': rse,
164
+ 'rse_id': rse_id,
165
+ 'file-size': replica['bytes'] or 0,
166
+ 'bytes': replica['bytes'] or 0,
167
+ 'url': pfn,
168
+ 'reason': str(error),
169
+ 'protocol': prot.attributes['scheme']}
170
+ if replica['scope'].vo != 'def':
171
+ payload['vo'] = replica['scope'].vo
172
+ add_message('deletion-failed', payload)
173
+
174
+ except Exception:
175
+ logging.critical(traceback.format_exc())
176
+ finally:
177
+ prot.close()
178
+
179
+ delete_quarantined_replicas(rse_id=rse_id, replicas=deleted_replicas)
180
+
181
+ must_sleep = False
182
+ if nothing_to_do:
183
+ logger(logging.INFO, 'Nothing to do')
184
+ must_sleep = True
185
+ return must_sleep
186
+
187
+
188
+ def stop(signum: "Optional[int]" = None, frame: "Optional[FrameType]" = None) -> None:
189
+ """
190
+ Graceful exit.
191
+ """
192
+ GRACEFUL_STOP.set()
193
+
194
+
195
+ def run(
196
+ total_workers: int = 1,
197
+ chunk_size: int = 100,
198
+ once: bool = False,
199
+ rses: "Optional[list[str]]" = None,
200
+ scheme: "Optional[str]" = None,
201
+ exclude_rses: "Optional[str]" = None,
202
+ include_rses: "Optional[str]" = None,
203
+ vos: "Optional[list[str]]" = None,
204
+ delay_seconds: int = 0,
205
+ sleep_time: int = 300
206
+ ) -> None:
207
+ """
208
+ Starts up the reaper threads.
209
+
210
+ :param total_workers: The total number of workers.
211
+ :param chunk_size: the size of chunk for deletion.
212
+ :param once: If True, only runs one iteration of the main loop.
213
+ :param rses: List of RSEs the reaper should work against. If empty, it considers all RSEs (Single-VO only).
214
+ :param scheme: Force the reaper to use a particular protocol/scheme, e.g., mock.
215
+ :param exclude_rses: RSE expression to exclude RSEs from the Reaper.
216
+ :param include_rses: RSE expression to include RSEs.
217
+ :param vos: VOs on which to look for RSEs. Only used in multi-VO mode.
218
+ If None, we either use all VOs if run from "def", or the current VO otherwise.
219
+ """
220
+ rses = rses or []
221
+ setup_logging(process_name=DAEMON_NAME)
222
+
223
+ if rucio.db.sqla.util.is_old_db():
224
+ raise exception.DatabaseException('Database was not updated, daemon won\'t start')
225
+
226
+ logging.info('main: starting processes')
227
+
228
+ multi_vo = config_get_bool('common', 'multi_vo', raise_exception=False, default=False)
229
+ if not multi_vo:
230
+ if vos:
231
+ logging.warning('Ignoring argument vos, this is only applicable in a multi-VO setup.')
232
+ vos = ['def']
233
+ else:
234
+ if vos:
235
+ invalid = set(vos) - set([v['vo'] for v in list_vos()])
236
+ if invalid:
237
+ msg = 'VO{} {} cannot be found'.format('s' if len(invalid) > 1 else '',
238
+ ', '.join([repr(v) for v in invalid]))
239
+ raise VONotFound(msg)
240
+ else:
241
+ vos = [v['vo'] for v in list_vos()]
242
+ logging.info('Dark Reaper: This instance will work on VO%s: %s'
243
+ % ('s' if len(vos) > 1 else '', ', '.join([v for v in vos])))
244
+
245
+ all_rses = []
246
+ for vo in vos:
247
+ all_rses.extend([rse['id'] for rse in rse_core.list_rses(filters={'vo': vo})])
248
+
249
+ if rses:
250
+ invalid = set(rses) - set([rse['rse'] for rse in all_rses])
251
+ if invalid:
252
+ msg = 'RSE{} {} cannot be found'.format('s' if len(invalid) > 1 else '',
253
+ ', '.join([repr(rse) for rse in invalid]))
254
+ raise RSENotFound(msg)
255
+ rses = [rse for rse in all_rses if rse['rse'] in rses]
256
+ else:
257
+ rses = all_rses
258
+
259
+ if exclude_rses:
260
+ excluded_rses = [rse['id'] for rse in parse_expression(exclude_rses)]
261
+ rses = [rse for rse in rses if rse not in excluded_rses]
262
+
263
+ if include_rses:
264
+ included_rses = [rse['id'] for rse in parse_expression(include_rses)]
265
+ rses = [rse for rse in rses if rse in included_rses]
266
+
267
+ if not rses:
268
+ logging.error('Dark Reaper: No RSEs found. Exiting.')
269
+ return
270
+
271
+ threads = []
272
+ for worker in range(total_workers):
273
+ kwargs = {'rses': rses,
274
+ 'once': once,
275
+ 'chunk_size': chunk_size,
276
+ 'scheme': scheme,
277
+ 'sleep_time': sleep_time}
278
+ threads.append(threading.Thread(target=reaper, kwargs=kwargs,
279
+ name='Worker: %s, Total_Workers: %s' % (worker, total_workers)))
280
+ [t.start() for t in threads]
281
+ while threads[0].is_alive():
282
+ [t.join(timeout=3.14) for t in threads]