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,159 @@
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
+ Judge-Cleaner is a daemon to clean expired replication rules.
17
+ """
18
+ import functools
19
+ import logging
20
+ import threading
21
+ import time
22
+ from copy import deepcopy
23
+ from datetime import datetime, timedelta
24
+ from random import randint
25
+ from re import match
26
+ from typing import TYPE_CHECKING, Optional
27
+
28
+ from sqlalchemy.exc import DatabaseError
29
+
30
+ import rucio.db.sqla.util
31
+ from rucio.common import exception
32
+ from rucio.common.exception import DatabaseException, RuleNotFound, UnsupportedOperation
33
+ from rucio.common.logging import setup_logging
34
+ from rucio.core.monitor import MetricManager
35
+ from rucio.core.rule import delete_rule, get_expired_rules
36
+ from rucio.daemons.common import HeartbeatHandler, run_daemon
37
+ from rucio.db.sqla.constants import ORACLE_CONNECTION_LOST_CONTACT_REGEX, ORACLE_RESOURCE_BUSY_REGEX
38
+ from rucio.db.sqla.util import get_db_time
39
+
40
+ if TYPE_CHECKING:
41
+ from types import FrameType
42
+
43
+ METRICS = MetricManager(module=__name__)
44
+ graceful_stop = threading.Event()
45
+ DAEMON_NAME = 'judge-cleaner'
46
+
47
+
48
+ def rule_cleaner(
49
+ once: bool = False,
50
+ sleep_time: int = 60
51
+ ) -> None:
52
+ """
53
+ Main loop to check for expired replication rules
54
+ """
55
+ paused_rules = {} # {rule_id: datetime}
56
+ run_daemon(
57
+ once=once,
58
+ graceful_stop=graceful_stop,
59
+ executable=DAEMON_NAME,
60
+ partition_wait_time=1,
61
+ sleep_time=sleep_time,
62
+ run_once_fnc=functools.partial(
63
+ run_once,
64
+ paused_rules=paused_rules,
65
+ )
66
+ )
67
+
68
+
69
+ def run_once(
70
+ paused_rules: dict[str, datetime],
71
+ heartbeat_handler: HeartbeatHandler,
72
+ **_kwargs
73
+ ) -> None:
74
+ worker_number, total_workers, logger = heartbeat_handler.live()
75
+
76
+ start = time.time()
77
+
78
+ # Refresh paused rules
79
+ iter_paused_rules = deepcopy(paused_rules)
80
+ for key in iter_paused_rules:
81
+ if datetime.utcnow() > paused_rules[key]:
82
+ del paused_rules[key]
83
+
84
+ rules = get_expired_rules(total_workers=total_workers,
85
+ worker_number=worker_number,
86
+ limit=200,
87
+ blocked_rules=[key for key in paused_rules])
88
+ logger(logging.DEBUG, 'index query time %f fetch size is %d' % (time.time() - start, len(rules)))
89
+
90
+ if not rules:
91
+ logger(logging.DEBUG, 'did not get any work (paused_rules=%s)' % str(len(paused_rules)))
92
+ return
93
+
94
+ for rule in rules:
95
+ _, _, logger = heartbeat_handler.live()
96
+ rule_id = rule[0]
97
+ rule_expression = rule[1]
98
+ logger(logging.INFO, 'Deleting rule %s with expression %s' % (rule_id, rule_expression))
99
+ if graceful_stop.is_set():
100
+ break
101
+ try:
102
+ start = time.time()
103
+ delete_rule(rule_id=rule_id, nowait=True)
104
+ logger(logging.DEBUG, 'deletion of %s took %f' % (rule_id, time.time() - start))
105
+ except (DatabaseException, DatabaseError, UnsupportedOperation) as e:
106
+ if match(ORACLE_RESOURCE_BUSY_REGEX, str(e.args[0])):
107
+ paused_rules[rule_id] = datetime.utcnow() + timedelta(seconds=randint(600, 2400)) # noqa: S311
108
+ METRICS.counter('exceptions.{exception}').labels(exception='LocksDetected').inc()
109
+ logger(logging.WARNING, 'Locks detected for %s' % rule_id)
110
+ elif match('.*QueuePool.*', str(e.args[0])):
111
+ logger(logging.WARNING, 'DatabaseException', exc_info=True)
112
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
113
+ elif match(ORACLE_CONNECTION_LOST_CONTACT_REGEX, str(e.args[0])):
114
+ logger(logging.WARNING, 'DatabaseException', exc_info=True)
115
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
116
+ else:
117
+ logger(logging.ERROR, 'DatabaseException', exc_info=True)
118
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
119
+ except RuleNotFound:
120
+ pass
121
+
122
+
123
+ def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
124
+ """
125
+ Graceful exit.
126
+ """
127
+ graceful_stop.set()
128
+
129
+
130
+ def run(
131
+ once: bool = False,
132
+ threads: int = 1,
133
+ sleep_time: int = 60
134
+ ) -> None:
135
+ """
136
+ Starts up the Judge-Clean threads.
137
+ """
138
+ setup_logging(process_name=DAEMON_NAME)
139
+
140
+ if rucio.db.sqla.util.is_old_db():
141
+ raise exception.DatabaseException('Database was not updated, daemon won\'t start')
142
+
143
+ client_time, db_time = datetime.utcnow(), get_db_time()
144
+ max_offset = timedelta(hours=1, seconds=10)
145
+ if type(db_time) is datetime:
146
+ if db_time - client_time > max_offset or client_time - db_time > max_offset:
147
+ logging.critical('Offset between client and db time too big. Stopping Cleaner')
148
+ return
149
+
150
+ if once:
151
+ rule_cleaner(once)
152
+ else:
153
+ logging.info('Cleaner starting %s threads' % str(threads))
154
+ thread_list = [threading.Thread(target=rule_cleaner, kwargs={'once': once,
155
+ 'sleep_time': sleep_time}) for i in range(0, threads)]
156
+ [t.start() for t in thread_list]
157
+ # Interruptible joins require a timeout.
158
+ while thread_list[0].is_alive():
159
+ [t.join(timeout=3.14) for t in thread_list]
@@ -0,0 +1,185 @@
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
+ Judge-Evaluator is a daemon to re-evaluate and execute replication rules.
17
+ """
18
+ import copy
19
+ import functools
20
+ import logging
21
+ import threading
22
+ import time
23
+ import traceback
24
+ from datetime import datetime, timedelta
25
+ from random import randint
26
+ from re import match
27
+ from typing import TYPE_CHECKING, Optional
28
+
29
+ from sqlalchemy.exc import DatabaseError
30
+ from sqlalchemy.orm.exc import FlushError
31
+
32
+ import rucio.db.sqla.util
33
+ from rucio.common.exception import DatabaseException, DataIdentifierNotFound, ReplicationRuleCreationTemporaryFailed
34
+ from rucio.common.logging import setup_logging
35
+ from rucio.common.types import InternalScope
36
+ from rucio.core.monitor import MetricManager
37
+ from rucio.core.rule import delete_updated_did, get_updated_dids, re_evaluate_did
38
+ from rucio.daemons.common import HeartbeatHandler, run_daemon
39
+ from rucio.db.sqla.constants import ORACLE_CONNECTION_LOST_CONTACT_REGEX, ORACLE_RESOURCE_BUSY_REGEX, ORACLE_UNIQUE_CONSTRAINT_VIOLATED_REGEX
40
+
41
+ if TYPE_CHECKING:
42
+ from types import FrameType
43
+
44
+ METRICS = MetricManager(module=__name__)
45
+ graceful_stop = threading.Event()
46
+ DAEMON_NAME = 'judge-evaluator'
47
+
48
+
49
+ def re_evaluator(
50
+ once: bool = False,
51
+ sleep_time: int = 30,
52
+ did_limit: int = 100
53
+ ) -> None:
54
+ """
55
+ Main loop to check the re-evaluation of dids.
56
+ """
57
+
58
+ paused_dids = {} # {(scope, name): datetime}
59
+ run_daemon(
60
+ once=once,
61
+ graceful_stop=graceful_stop,
62
+ executable=DAEMON_NAME,
63
+ partition_wait_time=1,
64
+ sleep_time=sleep_time,
65
+ run_once_fnc=functools.partial(
66
+ run_once,
67
+ did_limit=did_limit,
68
+ paused_dids=paused_dids,
69
+ )
70
+ )
71
+
72
+
73
+ def run_once(
74
+ paused_dids: dict[tuple[str, str], datetime],
75
+ did_limit: int,
76
+ heartbeat_handler: HeartbeatHandler,
77
+ **_kwargs
78
+ ) -> None:
79
+ worker_number, total_workers, logger = heartbeat_handler.live()
80
+
81
+ # heartbeat
82
+ start = time.time() # NOQA
83
+
84
+ # Refresh paused dids
85
+ iter_paused_dids = copy.copy(paused_dids)
86
+ for key in iter_paused_dids:
87
+ if datetime.utcnow() > paused_dids[key]:
88
+ del paused_dids[key]
89
+
90
+ # Select a bunch of dids for re evaluation for this worker
91
+ dids = get_updated_dids(total_workers=total_workers,
92
+ worker_number=worker_number,
93
+ limit=did_limit,
94
+ blocked_dids=[(InternalScope(key[0], from_external=False), key[1]) for key in paused_dids])
95
+ logger(logging.DEBUG, 'index query time %f fetch size is %d (%d blocked)', time.time() - start, len(dids),
96
+ len([(InternalScope(key[0], from_external=False), key[1]) for key in paused_dids]))
97
+
98
+ # If the list is empty, sent the worker to sleep
99
+ if not dids:
100
+ logger(logging.DEBUG, 'did not get any work (paused_dids=%s)', str(len(paused_dids)))
101
+ return
102
+
103
+ done_dids = {}
104
+ for did in dids:
105
+ _, _, logger = heartbeat_handler.live()
106
+ if graceful_stop.is_set():
107
+ break
108
+
109
+ # Check if this did has already been operated on
110
+ did_tag = '%s:%s' % (did.scope.internal, did.name)
111
+ if did_tag in done_dids:
112
+ if did.rule_evaluation_action in done_dids[did_tag]:
113
+ logger(logging.DEBUG, 'evaluation of %s:%s already done', did.scope, did.name)
114
+ delete_updated_did(id_=did.id)
115
+ continue
116
+ else:
117
+ done_dids[did_tag] = []
118
+
119
+ # Jump paused dids
120
+ if (did.scope.internal, did.name) in paused_dids:
121
+ continue
122
+
123
+ try:
124
+ start_time = time.time()
125
+ re_evaluate_did(scope=did.scope, name=did.name, rule_evaluation_action=did.rule_evaluation_action)
126
+ logger(logging.DEBUG, 'evaluation of %s:%s took %f', did.scope, did.name, time.time() - start_time)
127
+ delete_updated_did(id_=did.id)
128
+ done_dids[did_tag].append(did.rule_evaluation_action)
129
+ except DataIdentifierNotFound:
130
+ delete_updated_did(id_=did.id)
131
+ except (DatabaseException, DatabaseError) as e:
132
+ if match(ORACLE_UNIQUE_CONSTRAINT_VIOLATED_REGEX, str(e.args[0])) or match(ORACLE_RESOURCE_BUSY_REGEX, str(e.args[0])):
133
+ paused_dids[(did.scope.internal, did.name)] = datetime.utcnow() + timedelta(seconds=randint(60, 600)) # noqa: S311
134
+ logger(logging.WARNING, 'Locks detected for %s:%s', did.scope, did.name)
135
+ METRICS.counter('exceptions.{exception}').labels(exception='LocksDetected').inc()
136
+ elif match('.*QueuePool.*', str(e.args[0])):
137
+ logger(logging.WARNING, traceback.format_exc())
138
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
139
+ elif match(ORACLE_CONNECTION_LOST_CONTACT_REGEX, str(e.args[0])):
140
+ logger(logging.WARNING, traceback.format_exc())
141
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
142
+ else:
143
+ logger(logging.ERROR, traceback.format_exc())
144
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
145
+ except ReplicationRuleCreationTemporaryFailed as e:
146
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
147
+ logger(logging.WARNING, 'Replica Creation temporary failed, retrying later for %s:%s', did.scope, did.name)
148
+ except FlushError as e:
149
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
150
+ logger(logging.WARNING, 'Flush error for %s:%s', did.scope, did.name)
151
+
152
+
153
+ def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
154
+ """
155
+ Graceful exit.
156
+ """
157
+
158
+ graceful_stop.set()
159
+
160
+
161
+ def run(
162
+ once: bool = False,
163
+ threads: int = 1,
164
+ sleep_time: int = 30,
165
+ did_limit: int = 100
166
+ ) -> None:
167
+ """
168
+ Starts up the Judge-Eval threads.
169
+ """
170
+ setup_logging(process_name=DAEMON_NAME)
171
+
172
+ if rucio.db.sqla.util.is_old_db():
173
+ raise DatabaseException('Database was not updated, daemon won\'t start')
174
+
175
+ if once:
176
+ re_evaluator(once=once, did_limit=did_limit)
177
+ else:
178
+ logging.info('Evaluator starting %s threads' % str(threads))
179
+ thread_list = [threading.Thread(target=re_evaluator, kwargs={'once': once,
180
+ 'sleep_time': sleep_time,
181
+ 'did_limit': did_limit}) for i in range(0, threads)]
182
+ [t.start() for t in thread_list]
183
+ # Interruptible joins require a timeout.
184
+ while thread_list[0].is_alive():
185
+ [t.join(timeout=3.14) for t in thread_list]
@@ -0,0 +1,162 @@
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
+ Judge-Injector is a daemon to asynchronously create replication rules
17
+ """
18
+ import functools
19
+ import logging
20
+ import threading
21
+ import time
22
+ from copy import deepcopy
23
+ from datetime import datetime, timedelta
24
+ from random import randint
25
+ from re import match
26
+ from typing import TYPE_CHECKING, Optional
27
+
28
+ from sqlalchemy.exc import DatabaseError
29
+
30
+ import rucio.db.sqla.util
31
+ from rucio.common.exception import DatabaseException, InsufficientAccountLimit, ReplicationRuleCreationTemporaryFailed, RSEWriteBlocked, RuleNotFound
32
+ from rucio.common.logging import setup_logging
33
+ from rucio.core.monitor import MetricManager
34
+ from rucio.core.rule import get_injected_rules, inject_rule, update_rule
35
+ from rucio.daemons.common import HeartbeatHandler, run_daemon
36
+ from rucio.db.sqla.constants import ORACLE_CONNECTION_LOST_CONTACT_REGEX, ORACLE_RESOURCE_BUSY_REGEX
37
+
38
+ if TYPE_CHECKING:
39
+ from types import FrameType
40
+
41
+ METRICS = MetricManager(module=__name__)
42
+ graceful_stop = threading.Event()
43
+ DAEMON_NAME = 'judge-injector'
44
+
45
+
46
+ def rule_injector(
47
+ once: bool = False,
48
+ sleep_time: int = 60
49
+ ) -> None:
50
+ """
51
+ Main loop to check for asynchronous creation of replication rules
52
+ """
53
+ paused_rules = {} # {rule_id: datetime}
54
+ run_daemon(
55
+ once=once,
56
+ graceful_stop=graceful_stop,
57
+ executable=DAEMON_NAME,
58
+ partition_wait_time=1,
59
+ sleep_time=sleep_time,
60
+ run_once_fnc=functools.partial(
61
+ run_once,
62
+ paused_rules=paused_rules,
63
+ )
64
+ )
65
+
66
+
67
+ def run_once(
68
+ paused_rules: dict[str, datetime],
69
+ heartbeat_handler: HeartbeatHandler,
70
+ **_kwargs
71
+ ) -> None:
72
+ worker_number, total_workers, logger = heartbeat_handler.live()
73
+
74
+ start = time.time()
75
+
76
+ # Refresh paused rules
77
+ iter_paused_rules = deepcopy(paused_rules)
78
+ for key in iter_paused_rules:
79
+ if datetime.utcnow() > paused_rules[key]:
80
+ del paused_rules[key]
81
+
82
+ rules = get_injected_rules(total_workers=total_workers,
83
+ worker_number=worker_number,
84
+ limit=100,
85
+ blocked_rules=[key for key in paused_rules])
86
+ logger(logging.DEBUG, 'index query time %f fetch size is %d' % (time.time() - start, len(rules)))
87
+
88
+ if not rules:
89
+ logger(logging.DEBUG, 'did not get any work (paused_rules=%s)' % str(len(paused_rules)))
90
+ return
91
+
92
+ for rule_id in rules:
93
+ _, _, logger = heartbeat_handler.live()
94
+ logger(logging.INFO, 'Injecting rule %s' % rule_id)
95
+ if graceful_stop.is_set():
96
+ break
97
+ try:
98
+ start = time.time()
99
+ inject_rule(rule_id=rule_id, logger=logger)
100
+ logger(logging.DEBUG, 'injection of %s took %f' % (rule_id, time.time() - start))
101
+ except (DatabaseException, DatabaseError) as e:
102
+ if match(ORACLE_RESOURCE_BUSY_REGEX, str(e.args[0])):
103
+ paused_rules[rule_id] = datetime.utcnow() + timedelta(seconds=randint(60, 600)) # noqa: S311
104
+ METRICS.counter('exceptions.{exception}').labels(exception='LocksDetected').inc()
105
+ logger(logging.WARNING, 'Locks detected for %s' % rule_id)
106
+ elif match('.*QueuePool.*', str(e.args[0])):
107
+ logger(logging.WARNING, 'DatabaseException', exc_info=True)
108
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
109
+ elif match(ORACLE_CONNECTION_LOST_CONTACT_REGEX, str(e.args[0])):
110
+ logger(logging.WARNING, 'DatabaseException', exc_info=True)
111
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
112
+ else:
113
+ logger(logging.ERROR, 'DatabaseException', exc_info=True)
114
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
115
+ except (RSEWriteBlocked) as e:
116
+ paused_rules[rule_id] = datetime.utcnow() + timedelta(seconds=randint(60, 600)) # noqa: S311
117
+ logger(logging.WARNING, 'RSEWriteBlocked for rule %s' % rule_id)
118
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
119
+ except ReplicationRuleCreationTemporaryFailed as e:
120
+ paused_rules[rule_id] = datetime.utcnow() + timedelta(seconds=randint(60, 600)) # noqa: S311
121
+ logger(logging.WARNING, 'ReplicationRuleCreationTemporaryFailed for rule %s' % rule_id)
122
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
123
+ except RuleNotFound:
124
+ pass
125
+ except InsufficientAccountLimit:
126
+ # A rule with InsufficientAccountLimit on injection hangs there potentially forever
127
+ # It should be marked as SUSPENDED
128
+ logger(logging.INFO, 'Marking rule %s as SUSPENDED due to InsufficientAccountLimit' % rule_id)
129
+ update_rule(rule_id=rule_id, options={'state': 'SUSPENDED'})
130
+
131
+
132
+ def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
133
+ """
134
+ Graceful exit.
135
+ """
136
+
137
+ graceful_stop.set()
138
+
139
+
140
+ def run(
141
+ once: bool = False,
142
+ threads: int = 1,
143
+ sleep_time: int = 60
144
+ ) -> None:
145
+ """
146
+ Starts up the Judge-Injector threads.
147
+ """
148
+ setup_logging(process_name=DAEMON_NAME)
149
+
150
+ if rucio.db.sqla.util.is_old_db():
151
+ raise DatabaseException('Database was not updated, daemon won\'t start')
152
+
153
+ if once:
154
+ rule_injector(once)
155
+ else:
156
+ logging.info('Injector starting %s threads' % str(threads))
157
+ thread_list = [threading.Thread(target=rule_injector, kwargs={'once': once,
158
+ 'sleep_time': sleep_time}) for i in range(0, threads)]
159
+ [t.start() for t in thread_list]
160
+ # Interruptible joins require a timeout.
161
+ while thread_list[0].is_alive():
162
+ [t.join(timeout=3.14) for t in thread_list]
@@ -0,0 +1,154 @@
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
+ Judge-Repairer is a daemon to repair stuck replication rules.
17
+ """
18
+ import functools
19
+ import logging
20
+ import threading
21
+ import time
22
+ import traceback
23
+ from copy import deepcopy
24
+ from datetime import datetime, timedelta
25
+ from random import randint
26
+ from re import match
27
+ from typing import TYPE_CHECKING, Optional
28
+
29
+ from sqlalchemy.exc import DatabaseError
30
+
31
+ import rucio.db.sqla.util
32
+ from rucio.common import exception
33
+ from rucio.common.exception import DatabaseException
34
+ from rucio.common.logging import setup_logging
35
+ from rucio.core.monitor import MetricManager
36
+ from rucio.core.rule import get_stuck_rules, repair_rule
37
+ from rucio.daemons.common import HeartbeatHandler, run_daemon
38
+ from rucio.db.sqla.constants import ORACLE_CONNECTION_LOST_CONTACT_REGEX, ORACLE_RESOURCE_BUSY_REGEX
39
+
40
+ if TYPE_CHECKING:
41
+ from types import FrameType
42
+
43
+ METRICS = MetricManager(module=__name__)
44
+ graceful_stop = threading.Event()
45
+ DAEMON_NAME = 'judge-repairer'
46
+
47
+
48
+ def rule_repairer(
49
+ once: bool = False,
50
+ sleep_time: int = 60
51
+ ) -> None:
52
+ """
53
+ Main loop to check for STUCK replication rules
54
+ """
55
+ paused_rules = {} # {rule_id: datetime}
56
+ run_daemon(
57
+ once=once,
58
+ graceful_stop=graceful_stop,
59
+ executable=DAEMON_NAME,
60
+ partition_wait_time=1,
61
+ sleep_time=sleep_time,
62
+ run_once_fnc=functools.partial(
63
+ run_once,
64
+ paused_rules=paused_rules,
65
+ delta=-1 if once else 1800,
66
+ )
67
+ )
68
+
69
+
70
+ def run_once(
71
+ paused_rules: dict[str, datetime],
72
+ delta: int,
73
+ heartbeat_handler: HeartbeatHandler,
74
+ **_kwargs
75
+ ) -> None:
76
+ worker_number, total_workers, logger = heartbeat_handler.live()
77
+
78
+ start = time.time()
79
+
80
+ # Refresh paused rules
81
+ iter_paused_rules = deepcopy(paused_rules)
82
+ for key in iter_paused_rules:
83
+ if datetime.utcnow() > paused_rules[key]:
84
+ del paused_rules[key]
85
+
86
+ # Select a bunch of rules for this worker to repair
87
+ rules = get_stuck_rules(total_workers=total_workers,
88
+ worker_number=worker_number,
89
+ delta=delta,
90
+ limit=100,
91
+ blocked_rules=[key for key in paused_rules])
92
+
93
+ logger(logging.DEBUG, 'index query time %f fetch size is %d' % (time.time() - start, len(rules)))
94
+
95
+ if not rules:
96
+ logger(logging.DEBUG, 'did not get any work (paused_rules=%s)' % (str(len(paused_rules))))
97
+ return
98
+
99
+ for rule_id in rules:
100
+ _, _, logger = heartbeat_handler.live()
101
+ logger(logging.INFO, 'Repairing rule %s' % (rule_id))
102
+ if graceful_stop.is_set():
103
+ break
104
+ try:
105
+ start = time.time()
106
+ repair_rule(rule_id=rule_id)
107
+ logger(logging.DEBUG, 'repairing of %s took %f' % (rule_id, time.time() - start))
108
+ except (DatabaseException, DatabaseError) as e:
109
+ if match(ORACLE_RESOURCE_BUSY_REGEX, str(e.args[0])):
110
+ paused_rules[rule_id] = datetime.utcnow() + timedelta(seconds=randint(600, 2400)) # noqa: S311
111
+ logger(logging.WARNING, 'Locks detected for %s' % (rule_id))
112
+ METRICS.counter('exceptions.{exception}').labels(exception='LocksDetected').inc()
113
+ elif match('.*QueuePool.*', str(e.args[0])):
114
+ logger(logging.WARNING, traceback.format_exc())
115
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
116
+ elif match(ORACLE_CONNECTION_LOST_CONTACT_REGEX, str(e.args[0])):
117
+ logger(logging.WARNING, traceback.format_exc())
118
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
119
+ else:
120
+ logger(logging.ERROR, traceback.format_exc())
121
+ METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
122
+
123
+
124
+ def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
125
+ """
126
+ Graceful exit.
127
+ """
128
+
129
+ graceful_stop.set()
130
+
131
+
132
+ def run(
133
+ once: bool = False,
134
+ threads: int = 1,
135
+ sleep_time: int = 60
136
+ ) -> None:
137
+ """
138
+ Starts up the Judge-Repairer threads.
139
+ """
140
+ setup_logging(process_name=DAEMON_NAME)
141
+
142
+ if rucio.db.sqla.util.is_old_db():
143
+ raise exception.DatabaseException('Database was not updated, daemon won\'t start')
144
+
145
+ if once:
146
+ rule_repairer(once)
147
+ else:
148
+ logging.info('Repairer starting %s threads' % str(threads))
149
+ thread_list = [threading.Thread(target=rule_repairer, kwargs={'once': once,
150
+ 'sleep_time': sleep_time}) for i in range(0, threads)]
151
+ [t.start() for t in thread_list]
152
+ # Interruptible joins require a timeout.
153
+ while thread_list[0].is_alive():
154
+ [t.join(timeout=3.14) for t in thread_list]
@@ -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.