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,81 @@
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
+ """Functions to manage decommissioning configurations."""
16
+
17
+ from enum import Enum
18
+ from typing import Any
19
+
20
+ from rucio.common.constants import RseAttr
21
+ from rucio.core.rse import add_rse_attribute, get_rse_attribute
22
+
23
+
24
+ class DecommissioningStatus(Enum):
25
+ """Decommissioning status flags."""
26
+
27
+ PROCESSING = 'processing'
28
+ DONE = 'done'
29
+ SUSPENDED = 'suspended'
30
+
31
+
32
+ class InvalidStatusName(Exception):
33
+ """Exception for invalid decommissioning status name set from command line."""
34
+
35
+
36
+ def config_to_attr(config: dict[str, Any]) -> str:
37
+ """Form the attribute string from a config dictionary.
38
+
39
+ :param config: Decommissioning configuration dictionary.
40
+ :returns: Comma-separated key-value string encoding the configuration.
41
+ """
42
+ attr = f'profile={config["profile"].value}'
43
+ if config.get('move_dest'):
44
+ attr += f',move_dest={config["move_dest"]}'
45
+ attr += f',status={config["status"].value}'
46
+
47
+ return attr
48
+
49
+
50
+ def attr_to_config(attr: str) -> dict[str, Any]:
51
+ """Form the config dictionary from an attribute string.
52
+
53
+ :param attr: Comma-separated key-value string encoding the configuration.
54
+ :returns: Decommissioning configuration dictionary.
55
+ """
56
+ # The decommission attribute is a comma-separated list of key=value settings
57
+ config: dict[str, Any] = dict(map(lambda s: s.split('='), attr.split(',')))
58
+ if 'status' in config:
59
+ try:
60
+ config['status'] = DecommissioningStatus[config['status'].upper()]
61
+ except KeyError as exc:
62
+ raise InvalidStatusName() from exc
63
+ else:
64
+ config['status'] = DecommissioningStatus.PROCESSING
65
+
66
+ return config
67
+
68
+
69
+ def set_status(
70
+ rse_id: str,
71
+ status: DecommissioningStatus
72
+ ) -> None:
73
+ """Update the decommission attribute of the RSE.
74
+
75
+ :param rse_id: RSE ID.
76
+ :param status: RSE decommissioning status.
77
+ """
78
+ config = attr_to_config(get_rse_attribute(rse_id, RseAttr.DECOMMISSION)) # type: ignore (get_rse_attribute could return None)
79
+ config['status'] = status
80
+ # add_rse_attribute can handle updating existing entries too
81
+ add_rse_attribute(rse_id, RseAttr.DECOMMISSION, config_to_attr(config))
@@ -0,0 +1,24 @@
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
+ """Decommissioning profile definitions."""
16
+
17
+ from .atlas import atlas_move
18
+ from .generic import generic_delete, generic_move
19
+
20
+ PROFILE_MAP = {
21
+ 'generic_delete': generic_delete,
22
+ 'generic_move': generic_move,
23
+ 'atlas_move': atlas_move
24
+ }
@@ -0,0 +1,60 @@
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
+ """ATLAS-specific decommissioning profiles."""
16
+
17
+ import logging
18
+ from typing import TYPE_CHECKING, Any
19
+
20
+ from rucio.core.did import get_metadata
21
+
22
+ from .generic import _call_for_attention, generic_move
23
+
24
+ if TYPE_CHECKING:
25
+ from rucio.common.types import LoggerFunction
26
+
27
+ from .types import DecommissioningProfile
28
+
29
+
30
+ def atlas_move(rse: dict[str, Any], config: dict[str, Any]) -> 'DecommissioningProfile':
31
+ """Return a profile for moving rules that satisfy conditions to a specific destination.
32
+
33
+ The "ATLAS move" profile lists out all rules that are locking replicas
34
+ at the given RSE, and moves them to the specified destination if either
35
+ one of the following is true:
36
+
37
+ - The RSE expression of the rule is trivial (the RSE name itself).
38
+ - There are no replicas locked by the rule that reside on another RSE.
39
+ - The datatype of the DID is not "log".
40
+
41
+ :param rse: RSE to decommission.
42
+ :param config: Decommissioning configuration dictionary.
43
+ :returns: A decommissioning profile dictionary.
44
+ """
45
+ profile = generic_move(rse, config)
46
+ # Insert before the trivial RSE expression handler
47
+ idx = next(pos for pos, handler in enumerate(profile.handlers)
48
+ if handler[0].__name__ == '_has_trivial_rse_expression')
49
+ profile.handlers.insert(idx, (_is_log_file, _call_for_attention))
50
+ return profile
51
+
52
+
53
+ def _is_log_file(
54
+ rule: dict[str, Any],
55
+ rse: dict[str, Any],
56
+ *,
57
+ logger: "LoggerFunction" = logging.log
58
+ ) -> bool:
59
+ """Check if the datatype metadata is 'log'."""
60
+ return get_metadata(rule['scope'], rule['name'])['datatype'] == 'log'
@@ -0,0 +1,452 @@
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
+ """Generic decommissioning profiles."""
16
+ import logging
17
+ from datetime import datetime, timedelta
18
+ from typing import TYPE_CHECKING, Any
19
+
20
+ from sqlalchemy.exc import NoResultFound
21
+
22
+ from rucio.common.constants import RseAttr
23
+ from rucio.common.exception import Duplicate, ReplicaNotFound, RequestNotFound, RucioException, RuleNotFound, RuleReplaceFailed, UnsupportedOperation
24
+ from rucio.core.lock import get_replica_locks, get_replica_locks_for_rule_id
25
+ from rucio.core.replica import list_replicas_per_rse, set_tombstone, update_replica_state
26
+ from rucio.core.request import get_request_by_did
27
+ from rucio.core.rse import add_rse_attribute, update_rse
28
+ from rucio.core.rule import list_rules_for_rse_decommissioning, move_rule, update_rule
29
+ from rucio.db.sqla.constants import ReplicaState
30
+
31
+ from .types import DecommissioningProfile, HandlerOutcome
32
+
33
+ if TYPE_CHECKING:
34
+ from collections.abc import Iterable
35
+
36
+ from rucio.common.types import LoggerFunction
37
+
38
+
39
+ def generic_delete(rse: dict[str, Any], config: dict[str, Any]) -> DecommissioningProfile:
40
+ """Return a profile for simply deleting rules.
41
+
42
+ The "generic delete" profile lists out all rules that are locking replicas at the given RSE,
43
+ and deletes them if either one of the following is true:
44
+
45
+ - The RSE expression of the rule is trivial (the RSE name itself).
46
+ - There are no replicas locked by the rule that reside on another RSE.
47
+
48
+ :param rse: RSE to decommission.
49
+ :param config: Decommissioning configuration dictionary.
50
+ :returns: A decommissioning profile.
51
+ """
52
+ return DecommissioningProfile(
53
+ rse=rse,
54
+ initializer=_generic_initialize,
55
+ discoverer=_generic_discover,
56
+ handlers=[
57
+ (_is_locked, _call_for_attention),
58
+ (_is_being_deleted, _count_as_processed),
59
+ (_has_trivial_rse_expression, _delete_rule),
60
+ (_has_all_replicas_on_rse, _delete_rule),
61
+ ],
62
+ finalizer=_generic_finalize
63
+ )
64
+
65
+
66
+ def generic_move(rse: dict[str, Any], config: dict[str, Any]) -> DecommissioningProfile:
67
+ """Return a profile for moving rules that satisfy conditions to a specific destination.
68
+
69
+ The "generic move" profile lists out all rules that are locking replicas at the given RSE,
70
+ and moves them to the specified destination if either one of the following is true:
71
+
72
+ - The RSE expression of the rule is trivial (the RSE name itself).
73
+ - There are no replicas locked by the rule that reside on another RSE.
74
+
75
+ :param rse: RSE to decommission.
76
+ :param config: Decommissioning configuration dictionary.
77
+ :returns: A decommissioning profile dictionary.
78
+ """
79
+ try:
80
+ destination = config['destination']
81
+ except KeyError as exc:
82
+ raise RucioException('Configuration parameter "destination" not set') from exc
83
+
84
+ move_to_destination = RuleMover(destination)
85
+ return DecommissioningProfile(
86
+ rse=rse,
87
+ initializer=_generic_initialize,
88
+ discoverer=_generic_discover,
89
+ handlers=[
90
+ (_is_locked, _call_for_attention),
91
+ (_is_being_deleted, _count_as_processed),
92
+ (_has_child_rule_id, _count_as_processed),
93
+ (_has_trivial_rse_expression, move_to_destination),
94
+ (_has_all_replicas_on_rse, move_to_destination),
95
+ ],
96
+ finalizer=_generic_finalize
97
+ )
98
+
99
+
100
+ def _generic_initialize(
101
+ rse: dict[str, Any],
102
+ *,
103
+ logger: "LoggerFunction" = logging.log,
104
+ ) -> None:
105
+ """Initializer function that sets the RSE availability flags and the decommissioning status.
106
+
107
+ When an RSE is initialized for decommissioning, the availability flags are set as follows:
108
+
109
+ - `availability_read=True`
110
+ - `availability_write=False`
111
+ - `availability_delete=True`
112
+
113
+ and the following attribute is set:
114
+
115
+ - `greedyDeletion=True`
116
+
117
+ :param rse: RSE table entry as a dictionary.
118
+ :param logger: Logging function.
119
+ """
120
+ logger(logging.INFO,
121
+ '(%s) Setting RSE availability flags of to read !write delete, greedyDeletion=true.',
122
+ rse['rse'])
123
+
124
+ parameters = {
125
+ 'availability_read': True,
126
+ 'availability_write': False,
127
+ 'availability_delete': True
128
+ }
129
+ update_rse(rse['id'], parameters)
130
+
131
+ try:
132
+ add_rse_attribute(rse['id'], RseAttr.GREEDYDELETION, True)
133
+ except Duplicate:
134
+ pass
135
+
136
+
137
+ def _generic_discover(
138
+ rse: dict[str, Any],
139
+ *,
140
+ logger: "LoggerFunction" = logging.log
141
+ ) -> 'Iterable[dict[str, Any]]':
142
+ """Discoverer function that calls the listing function from core.rule.
143
+
144
+ :param rse: RSE table entry as a dictionary.
145
+ :param logger: Logging function.
146
+ :returns: An iterable of rule dictionaries.
147
+ """
148
+ return list_rules_for_rse_decommissioning(rse['id'])
149
+
150
+
151
+ def _generic_finalize(
152
+ rse: dict[str, Any],
153
+ *,
154
+ logger: "LoggerFunction" = logging.log
155
+ ) -> bool:
156
+ """Check for remaining replicas at the RSE and resolve where possible.
157
+
158
+ If for some reason there are still a large number of replicas remaining at the RSE, this
159
+ function cuts off automatic processing attempts at a hard-coded 100.
160
+
161
+ :param rse: RSE table entry as a dictionary.
162
+ :param logger: Logging function.
163
+ :returns: A boolean flag indicating the completion status.
164
+ """
165
+ num_remaining_replicas = _process_replicas_with_no_locks(rse,
166
+ list_replicas_per_rse(rse['id']),
167
+ limit=100,
168
+ logger=logger)
169
+
170
+ if num_remaining_replicas == 0:
171
+ # The RSE is now really completely cleared.
172
+ logger(logging.INFO,
173
+ '(%s) Completed deleting the RSE contents. Updating the decommissioning status'
174
+ ' to "done".',
175
+ rse['rse'])
176
+ return True
177
+
178
+ logger(logging.WARNING,
179
+ '(%s) %d replicas remain on the RSE even though there are no more rules creating'
180
+ ' locks on them.',
181
+ rse['rse'], num_remaining_replicas)
182
+
183
+ # We now wait for reaper to pick the updated replicas (if there are any). Hopefully all
184
+ # replicas will be deleted at the next cycle.
185
+ return False
186
+
187
+
188
+ def _process_replicas_with_no_locks(
189
+ rse: dict[str, Any],
190
+ replicas: 'Iterable[dict[str, Any]]',
191
+ limit: int = 0,
192
+ *,
193
+ logger: "LoggerFunction" = logging.log,
194
+ ) -> int:
195
+ """Process replicas that remain at the RSE after the decommissioning.
196
+
197
+ Replicas that remain at the RSE at this point should be unlocked. While this is a situation
198
+ that should not happen, it can due to various errors. This function checks each such replica
199
+ and attempt to resolve the invalid state for known cases.
200
+
201
+ :param rse: RSE table entry as a dictionary.
202
+ :param replicas: Sequence or generator of replica objects.
203
+ :param logger: Logging function.
204
+ :returns: Number of processed replicas.
205
+ """
206
+ num_processed = 0
207
+ num_updated = 0
208
+ num_waiting_reap = 0
209
+
210
+ # Check if each replica satisfies the condition in list_and_mark_unlocked_replicas() (in
211
+ # core.replica).
212
+ # For each of the conditions, in case of failure, handle cases that can be handled.
213
+ for replica in replicas:
214
+ num_processed += 1
215
+ if limit > 0 and num_processed == limit:
216
+ break
217
+
218
+ updated = False
219
+
220
+ # If the replica fails any of the following three conditions, reaper won't pick it up.
221
+ reap_pending = True
222
+
223
+ # 1. Condition on the replica state & update time
224
+ in_stable_state = replica['state'] in [ReplicaState.AVAILABLE,
225
+ ReplicaState.UNAVAILABLE,
226
+ ReplicaState.BAD]
227
+
228
+ ten_minutes_ago = datetime.utcnow() - timedelta(seconds=600)
229
+ deleting_stuck = (replica['state'] == ReplicaState.BEING_DELETED
230
+ and replica['updated_at'] < ten_minutes_ago)
231
+
232
+ if not (in_stable_state or deleting_stuck):
233
+ # 1.1 If COPYING without a valid request
234
+ # -> Update the state to UNAVAILABLE
235
+ if replica['state'] == ReplicaState.COPYING:
236
+ # Should we allow requests in certain states? Depends on the details of the
237
+ # request state machine.
238
+ try:
239
+ get_request_by_did(replica['scope'], replica['name'], rse['id'])
240
+ except RequestNotFound:
241
+ logger(logging.INFO,
242
+ '(%s) Replica %s:%s is in COPYING state without a valid request.'
243
+ ' Changing state to UNAVAILABLE.',
244
+ rse['rse'], replica['scope'], replica['name'])
245
+
246
+ try:
247
+ update_replica_state(rse['id'], replica['scope'], replica['name'],
248
+ ReplicaState.UNAVAILABLE)
249
+ except ReplicaNotFound:
250
+ logger(logging.WARNING,
251
+ '(%s) Replica %s:%s disappeared during cleanup',
252
+ rse['rse'], replica['scope'], replica['name'])
253
+ except UnsupportedOperation as error:
254
+ logger(logging.ERROR, '(%s) %s', rse['rse'], str(error))
255
+ else:
256
+ updated = True
257
+
258
+ reap_pending = False
259
+
260
+ # 2. Condition on the lock count
261
+ if replica['lock_cnt'] != 0:
262
+ # 2.1 No actual lock -> Reset the lock count
263
+ try:
264
+ locks = get_replica_locks(replica['scope'], replica['name'],
265
+ restrict_rses=[rse['id']])
266
+ except NoResultFound:
267
+ logger(logging.WARNING,
268
+ '(%s) Replica %s:%s disappeared during cleanup',
269
+ rse['rse'], replica['scope'], replica['name'])
270
+ else:
271
+ if len(locks) == 0:
272
+ logger(logging.WARNING,
273
+ '(%s) Replica %s:%s has lock count %s but zero actual locks. Please'
274
+ ' fix the counts.',
275
+ rse['rse'], replica['scope'], replica['name'], replica['lock_cnt'])
276
+
277
+ reap_pending = False
278
+
279
+ # 3. Tombstone missing or in the future -> RIP now
280
+ if replica['tombstone'] is None or replica['tombstone'] >= datetime.utcnow():
281
+ logger(logging.INFO, '(%s) Marking tombstone of replica %s:%s as UTCNOW.',
282
+ rse['rse'], replica['scope'], replica['name'])
283
+
284
+ try:
285
+ set_tombstone(rse['id'], replica['scope'], replica['name'],
286
+ tombstone=datetime.utcnow())
287
+ except ReplicaNotFound as error:
288
+ logger(logging.WARNING, '(%s) %s', rse['rse'], str(error))
289
+ else:
290
+ updated = True
291
+
292
+ reap_pending = False
293
+
294
+ if updated:
295
+ num_updated += 1
296
+
297
+ if reap_pending:
298
+ num_waiting_reap += 1
299
+
300
+ logger(logging.INFO, '(%s) %s replicas have been updated. %s replicas are pending deletion.'
301
+ ' >=%s replicas remain unhandled.',
302
+ rse['rse'], num_updated, num_waiting_reap,
303
+ num_processed - num_updated - num_waiting_reap)
304
+
305
+ return num_processed
306
+
307
+
308
+ # Condition functions
309
+
310
+ def _is_locked(
311
+ rule: dict[str, Any],
312
+ rse: dict[str, Any],
313
+ *,
314
+ logger: "LoggerFunction" = logging.log
315
+ ) -> bool:
316
+ logger(logging.INFO,
317
+ '(%s) Rule %s for %s:%s is locked',
318
+ rse['rse'], rule['id'], rule['scope'], rule['name'])
319
+ return rule['locked']
320
+
321
+
322
+ def _is_being_deleted(
323
+ rule: dict[str, Any],
324
+ rse: dict[str, Any],
325
+ *,
326
+ logger: "LoggerFunction" = logging.log
327
+ ) -> bool:
328
+ """Check if the rule is already set to be deleted."""
329
+ if rule['expires_at'] is not None and rule['expires_at'] < datetime.utcnow():
330
+ logger(logging.DEBUG,
331
+ '(%s) Rule %s for %s:%s is bound for deletion',
332
+ rse['rse'], rule['id'], rule['scope'], rule['name'])
333
+ return True
334
+ return False
335
+
336
+
337
+ def _has_trivial_rse_expression(
338
+ rule: dict[str, Any],
339
+ rse: dict[str, Any],
340
+ *,
341
+ logger: "LoggerFunction" = logging.log
342
+ ) -> bool:
343
+ """Check for a trivial rse_expression."""
344
+ return rule['rse_expression'] == rse['rse']
345
+
346
+
347
+ def _has_all_replicas_on_rse(
348
+ rule: dict[str, Any],
349
+ rse: dict[str, Any],
350
+ *,
351
+ logger: "LoggerFunction" = logging.log
352
+ ) -> bool:
353
+ """Check if the all the replicas are on the RSE."""
354
+ # Check the list of RSEs that the replicas locked by this rule reside on.
355
+ try:
356
+ locks = get_replica_locks_for_rule_id(rule['id'])
357
+ except NoResultFound:
358
+ # No replica is locked to begin with -> treat as having the last replica on this RSE
359
+ return True
360
+
361
+ replica_rse_ids = set(lock['rse_id'] for lock in locks)
362
+
363
+ return len(replica_rse_ids) == 1 and list(replica_rse_ids)[0] == rse['id']
364
+
365
+
366
+ def _has_child_rule_id(
367
+ rule: dict[str, Any],
368
+ rse: dict[str, Any],
369
+ *,
370
+ logger: "LoggerFunction" = logging.log
371
+ ) -> bool:
372
+ """Check for non-empty child_rule_id."""
373
+ if rule['child_rule_id']:
374
+ logger(logging.DEBUG, '(%s) Rule %s for %s:%s is being moved',
375
+ rse['rse'], rule['id'], rule['scope'], rule['name'])
376
+ return True
377
+ return False
378
+
379
+
380
+ # Action functions
381
+
382
+ def _call_for_attention(
383
+ rule: dict[str, Any],
384
+ rse: dict[str, Any],
385
+ *,
386
+ logger: "LoggerFunction" = logging.log
387
+ ) -> HandlerOutcome:
388
+ return HandlerOutcome.NEED_ATTENTION
389
+
390
+
391
+ def _count_as_processed(
392
+ rule: dict[str, Any],
393
+ rse: dict[str, Any],
394
+ *,
395
+ logger: "LoggerFunction" = logging.log
396
+ ) -> HandlerOutcome:
397
+ """Do nothing but increment the limit checker."""
398
+ return HandlerOutcome.UNTOUCHED
399
+
400
+
401
+ def _delete_rule(
402
+ rule: dict[str, Any],
403
+ rse: dict[str, Any],
404
+ *,
405
+ logger: "LoggerFunction" = logging.log
406
+ ) -> HandlerOutcome:
407
+ """Delete the rule."""
408
+ logger(logging.DEBUG, '(%s) Deleting rule %s for %s:%s',
409
+ rse['rse'], rule['id'], rule['scope'], rule['name'])
410
+
411
+ try:
412
+ update_rule(rule['id'], {'lifetime': 0})
413
+ except RuleNotFound:
414
+ logger(logging.WARNING, '(%s) Rule %s for %s:%s disappeared before deleting',
415
+ rse['rse'], rule['id'], rule['scope'], rule['name'])
416
+ return HandlerOutcome.UNTOUCHED
417
+
418
+ return HandlerOutcome.REMOVED
419
+
420
+
421
+ class RuleMover:
422
+ """Callable object with a destination attribute."""
423
+ def __init__(self, destination: str) -> None:
424
+ self.destination = destination
425
+
426
+ def __call__(
427
+ self,
428
+ rule: dict[str, Any],
429
+ rse: dict[str, Any],
430
+ *,
431
+ logger: "LoggerFunction" = logging.log
432
+ ) -> HandlerOutcome:
433
+ """Move the rule."""
434
+ # Move the rule.
435
+ logger(logging.DEBUG, '(%s) Moving rule %s for %s:%s to %s',
436
+ rse['rse'], rule['id'], rule['scope'], rule['name'],
437
+ self.destination)
438
+
439
+ try:
440
+ move_rule(rule['id'], self.destination,
441
+ override={'weight': None, 'source_replica_expression': None})
442
+ except RuleNotFound:
443
+ logger(logging.WARNING, '(%s) Rule %s for %s:%s disappeared before moving',
444
+ rse['rse'], rule['id'], rule['scope'], rule['name'])
445
+ return HandlerOutcome.UNTOUCHED
446
+ except RuleReplaceFailed:
447
+ logger(logging.ERROR,
448
+ '(%s) Failed to move rule %s for %s:%s to %s',
449
+ rse['rse'], rule['id'], rule['scope'], rule['name'],
450
+ self.destination)
451
+ return HandlerOutcome.NEED_ATTENTION
452
+ return HandlerOutcome.REMOVED