rucio 32.8.6__py3-none-any.whl → 35.8.0__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 (502) hide show
  1. rucio/__init__.py +0 -1
  2. rucio/alembicrevision.py +1 -2
  3. rucio/client/__init__.py +0 -1
  4. rucio/client/accountclient.py +45 -25
  5. rucio/client/accountlimitclient.py +37 -9
  6. rucio/client/baseclient.py +199 -154
  7. rucio/client/client.py +2 -3
  8. rucio/client/configclient.py +19 -6
  9. rucio/client/credentialclient.py +9 -4
  10. rucio/client/didclient.py +238 -63
  11. rucio/client/diracclient.py +13 -5
  12. rucio/client/downloadclient.py +162 -51
  13. rucio/client/exportclient.py +4 -4
  14. rucio/client/fileclient.py +3 -4
  15. rucio/client/importclient.py +4 -4
  16. rucio/client/lifetimeclient.py +21 -5
  17. rucio/client/lockclient.py +18 -8
  18. rucio/client/{metaclient.py → metaconventionsclient.py} +18 -15
  19. rucio/client/pingclient.py +0 -1
  20. rucio/client/replicaclient.py +15 -5
  21. rucio/client/requestclient.py +35 -19
  22. rucio/client/rseclient.py +133 -51
  23. rucio/client/ruleclient.py +29 -22
  24. rucio/client/scopeclient.py +8 -6
  25. rucio/client/subscriptionclient.py +47 -35
  26. rucio/client/touchclient.py +8 -4
  27. rucio/client/uploadclient.py +166 -82
  28. rucio/common/__init__.py +0 -1
  29. rucio/common/cache.py +4 -4
  30. rucio/common/config.py +52 -47
  31. rucio/common/constants.py +69 -2
  32. rucio/common/constraints.py +0 -1
  33. rucio/common/didtype.py +24 -22
  34. rucio/common/dumper/__init__.py +70 -41
  35. rucio/common/dumper/consistency.py +26 -22
  36. rucio/common/dumper/data_models.py +16 -23
  37. rucio/common/dumper/path_parsing.py +0 -1
  38. rucio/common/exception.py +281 -222
  39. rucio/common/extra.py +0 -1
  40. rucio/common/logging.py +54 -38
  41. rucio/common/pcache.py +122 -101
  42. rucio/common/plugins.py +153 -0
  43. rucio/common/policy.py +4 -4
  44. rucio/common/schema/__init__.py +17 -10
  45. rucio/common/schema/atlas.py +7 -5
  46. rucio/common/schema/belleii.py +7 -5
  47. rucio/common/schema/domatpc.py +7 -5
  48. rucio/common/schema/escape.py +7 -5
  49. rucio/common/schema/generic.py +8 -6
  50. rucio/common/schema/generic_multi_vo.py +7 -5
  51. rucio/common/schema/icecube.py +7 -5
  52. rucio/common/stomp_utils.py +0 -1
  53. rucio/common/stopwatch.py +0 -1
  54. rucio/common/test_rucio_server.py +2 -2
  55. rucio/common/types.py +262 -17
  56. rucio/common/utils.py +743 -451
  57. rucio/core/__init__.py +0 -1
  58. rucio/core/account.py +99 -29
  59. rucio/core/account_counter.py +89 -24
  60. rucio/core/account_limit.py +90 -24
  61. rucio/core/authentication.py +86 -29
  62. rucio/core/config.py +108 -38
  63. rucio/core/credential.py +14 -7
  64. rucio/core/did.py +680 -782
  65. rucio/core/did_meta_plugins/__init__.py +8 -6
  66. rucio/core/did_meta_plugins/did_column_meta.py +17 -12
  67. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +60 -11
  68. rucio/core/did_meta_plugins/filter_engine.py +90 -50
  69. rucio/core/did_meta_plugins/json_meta.py +41 -16
  70. rucio/core/did_meta_plugins/mongo_meta.py +25 -8
  71. rucio/core/did_meta_plugins/postgres_meta.py +3 -4
  72. rucio/core/dirac.py +46 -17
  73. rucio/core/distance.py +66 -43
  74. rucio/core/exporter.py +5 -5
  75. rucio/core/heartbeat.py +181 -81
  76. rucio/core/identity.py +22 -12
  77. rucio/core/importer.py +23 -12
  78. rucio/core/lifetime_exception.py +32 -32
  79. rucio/core/lock.py +244 -142
  80. rucio/core/message.py +79 -38
  81. rucio/core/{meta.py → meta_conventions.py} +57 -44
  82. rucio/core/monitor.py +19 -13
  83. rucio/core/naming_convention.py +68 -27
  84. rucio/core/nongrid_trace.py +17 -5
  85. rucio/core/oidc.py +151 -29
  86. rucio/core/permission/__init__.py +18 -6
  87. rucio/core/permission/atlas.py +50 -35
  88. rucio/core/permission/belleii.py +6 -5
  89. rucio/core/permission/escape.py +8 -6
  90. rucio/core/permission/generic.py +82 -80
  91. rucio/core/permission/generic_multi_vo.py +9 -7
  92. rucio/core/quarantined_replica.py +91 -58
  93. rucio/core/replica.py +1303 -772
  94. rucio/core/replica_sorter.py +10 -12
  95. rucio/core/request.py +1133 -285
  96. rucio/core/rse.py +142 -102
  97. rucio/core/rse_counter.py +49 -18
  98. rucio/core/rse_expression_parser.py +6 -7
  99. rucio/core/rse_selector.py +41 -16
  100. rucio/core/rule.py +1538 -474
  101. rucio/core/rule_grouping.py +213 -68
  102. rucio/core/scope.py +50 -22
  103. rucio/core/subscription.py +92 -44
  104. rucio/core/topology.py +66 -24
  105. rucio/core/trace.py +42 -28
  106. rucio/core/transfer.py +543 -259
  107. rucio/core/vo.py +36 -18
  108. rucio/core/volatile_replica.py +59 -32
  109. rucio/daemons/__init__.py +0 -1
  110. rucio/daemons/abacus/__init__.py +0 -1
  111. rucio/daemons/abacus/account.py +29 -19
  112. rucio/daemons/abacus/collection_replica.py +21 -10
  113. rucio/daemons/abacus/rse.py +22 -12
  114. rucio/daemons/atropos/__init__.py +0 -1
  115. rucio/daemons/atropos/atropos.py +1 -2
  116. rucio/daemons/auditor/__init__.py +56 -28
  117. rucio/daemons/auditor/hdfs.py +17 -6
  118. rucio/daemons/auditor/srmdumps.py +116 -45
  119. rucio/daemons/automatix/__init__.py +0 -1
  120. rucio/daemons/automatix/automatix.py +30 -18
  121. rucio/daemons/badreplicas/__init__.py +0 -1
  122. rucio/daemons/badreplicas/minos.py +29 -18
  123. rucio/daemons/badreplicas/minos_temporary_expiration.py +5 -7
  124. rucio/daemons/badreplicas/necromancer.py +9 -13
  125. rucio/daemons/bb8/__init__.py +0 -1
  126. rucio/daemons/bb8/bb8.py +10 -13
  127. rucio/daemons/bb8/common.py +151 -154
  128. rucio/daemons/bb8/nuclei_background_rebalance.py +15 -9
  129. rucio/daemons/bb8/t2_background_rebalance.py +15 -8
  130. rucio/daemons/c3po/__init__.py +0 -1
  131. rucio/daemons/c3po/algorithms/__init__.py +0 -1
  132. rucio/daemons/c3po/algorithms/simple.py +8 -5
  133. rucio/daemons/c3po/algorithms/t2_free_space.py +10 -7
  134. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +10 -7
  135. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +30 -15
  136. rucio/daemons/c3po/c3po.py +81 -52
  137. rucio/daemons/c3po/collectors/__init__.py +0 -1
  138. rucio/daemons/c3po/collectors/agis.py +17 -17
  139. rucio/daemons/c3po/collectors/free_space.py +32 -13
  140. rucio/daemons/c3po/collectors/jedi_did.py +14 -5
  141. rucio/daemons/c3po/collectors/mock_did.py +11 -6
  142. rucio/daemons/c3po/collectors/network_metrics.py +12 -4
  143. rucio/daemons/c3po/collectors/workload.py +21 -19
  144. rucio/daemons/c3po/utils/__init__.py +0 -1
  145. rucio/daemons/c3po/utils/dataset_cache.py +15 -5
  146. rucio/daemons/c3po/utils/expiring_dataset_cache.py +16 -5
  147. rucio/daemons/c3po/utils/expiring_list.py +6 -7
  148. rucio/daemons/c3po/utils/popularity.py +5 -2
  149. rucio/daemons/c3po/utils/timeseries.py +25 -12
  150. rucio/daemons/cache/__init__.py +0 -1
  151. rucio/daemons/cache/consumer.py +21 -15
  152. rucio/daemons/common.py +42 -18
  153. rucio/daemons/conveyor/__init__.py +0 -1
  154. rucio/daemons/conveyor/common.py +69 -37
  155. rucio/daemons/conveyor/finisher.py +83 -46
  156. rucio/daemons/conveyor/poller.py +101 -69
  157. rucio/daemons/conveyor/preparer.py +35 -28
  158. rucio/daemons/conveyor/receiver.py +64 -21
  159. rucio/daemons/conveyor/stager.py +33 -28
  160. rucio/daemons/conveyor/submitter.py +71 -47
  161. rucio/daemons/conveyor/throttler.py +99 -35
  162. rucio/daemons/follower/__init__.py +0 -1
  163. rucio/daemons/follower/follower.py +12 -8
  164. rucio/daemons/hermes/__init__.py +0 -1
  165. rucio/daemons/hermes/hermes.py +57 -21
  166. rucio/daemons/judge/__init__.py +0 -1
  167. rucio/daemons/judge/cleaner.py +27 -17
  168. rucio/daemons/judge/evaluator.py +31 -18
  169. rucio/daemons/judge/injector.py +31 -23
  170. rucio/daemons/judge/repairer.py +28 -18
  171. rucio/daemons/oauthmanager/__init__.py +0 -1
  172. rucio/daemons/oauthmanager/oauthmanager.py +7 -8
  173. rucio/daemons/reaper/__init__.py +0 -1
  174. rucio/daemons/reaper/dark_reaper.py +15 -9
  175. rucio/daemons/reaper/reaper.py +109 -67
  176. rucio/daemons/replicarecoverer/__init__.py +0 -1
  177. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +255 -116
  178. rucio/{api → daemons/rsedecommissioner}/__init__.py +0 -1
  179. rucio/daemons/rsedecommissioner/config.py +81 -0
  180. rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
  181. rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
  182. rucio/daemons/rsedecommissioner/profiles/generic.py +451 -0
  183. rucio/daemons/rsedecommissioner/profiles/types.py +92 -0
  184. rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
  185. rucio/daemons/storage/__init__.py +0 -1
  186. rucio/daemons/storage/consistency/__init__.py +0 -1
  187. rucio/daemons/storage/consistency/actions.py +152 -59
  188. rucio/daemons/tracer/__init__.py +0 -1
  189. rucio/daemons/tracer/kronos.py +47 -24
  190. rucio/daemons/transmogrifier/__init__.py +0 -1
  191. rucio/daemons/transmogrifier/transmogrifier.py +35 -26
  192. rucio/daemons/undertaker/__init__.py +0 -1
  193. rucio/daemons/undertaker/undertaker.py +10 -10
  194. rucio/db/__init__.py +0 -1
  195. rucio/db/sqla/__init__.py +16 -2
  196. rucio/db/sqla/constants.py +10 -1
  197. rucio/db/sqla/migrate_repo/__init__.py +0 -1
  198. rucio/db/sqla/migrate_repo/env.py +0 -1
  199. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +0 -1
  200. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +0 -3
  201. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +1 -3
  202. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +0 -3
  203. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +1 -3
  204. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +1 -3
  205. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +0 -3
  206. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +1 -4
  207. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +0 -1
  208. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +0 -2
  209. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +0 -1
  210. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +0 -1
  211. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +0 -2
  212. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +0 -1
  213. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +1 -3
  214. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +0 -1
  215. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +0 -3
  216. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +0 -1
  217. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +1 -2
  218. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +0 -1
  219. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +0 -3
  220. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +1 -3
  221. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +1 -4
  222. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +0 -2
  223. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +0 -3
  224. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +0 -3
  225. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +1 -2
  226. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +0 -1
  227. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +0 -1
  228. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +0 -2
  229. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +0 -3
  230. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +1 -3
  231. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +0 -2
  232. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +1 -4
  233. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +0 -3
  234. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +1 -4
  235. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +0 -1
  236. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +1 -3
  237. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +0 -2
  238. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +1 -3
  239. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +1 -3
  240. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +1 -2
  241. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +1 -3
  242. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +1 -3
  243. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +0 -2
  244. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +1 -3
  245. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +2 -3
  246. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +0 -3
  247. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +1 -4
  248. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +0 -1
  249. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +0 -1
  250. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +0 -3
  251. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +0 -1
  252. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +0 -2
  253. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +0 -3
  254. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +0 -2
  255. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +2 -4
  256. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +0 -2
  257. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +1 -3
  258. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +1 -4
  259. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +0 -3
  260. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +0 -3
  261. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +0 -2
  262. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +1 -3
  263. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +0 -3
  264. rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
  265. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +0 -2
  266. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +0 -2
  267. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +0 -3
  268. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +0 -3
  269. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +0 -3
  270. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +1 -2
  271. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +0 -3
  272. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +1 -3
  273. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +1 -3
  274. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +1 -2
  275. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +0 -3
  276. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +0 -3
  277. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +1 -2
  278. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +2 -4
  279. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +0 -1
  280. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +1 -4
  281. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +0 -2
  282. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +0 -3
  283. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +1 -2
  284. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +0 -3
  285. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +1 -3
  286. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +0 -3
  287. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +0 -1
  288. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +1 -2
  289. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +0 -2
  290. rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
  291. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +1 -3
  292. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +0 -2
  293. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +1 -4
  294. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +0 -1
  295. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +0 -1
  296. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +1 -3
  297. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +1 -4
  298. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +0 -1
  299. rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
  300. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +0 -3
  301. rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
  302. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +1 -2
  303. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +1 -3
  304. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +0 -3
  305. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +1 -5
  306. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +1 -3
  307. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +0 -3
  308. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +1 -3
  309. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +1 -2
  310. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +0 -3
  311. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +1 -4
  312. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +1 -2
  313. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +1 -4
  314. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +1 -3
  315. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +1 -4
  316. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +0 -2
  317. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +1 -3
  318. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +0 -3
  319. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +1 -3
  320. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +0 -1
  321. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +1 -2
  322. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +1 -3
  323. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +0 -2
  324. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +0 -1
  325. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +1 -2
  326. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +0 -3
  327. rucio/db/sqla/models.py +122 -216
  328. rucio/db/sqla/sautils.py +12 -5
  329. rucio/db/sqla/session.py +71 -43
  330. rucio/db/sqla/types.py +3 -4
  331. rucio/db/sqla/util.py +91 -69
  332. rucio/gateway/__init__.py +13 -0
  333. rucio/{api → gateway}/account.py +119 -46
  334. rucio/{api → gateway}/account_limit.py +12 -13
  335. rucio/{api → gateway}/authentication.py +106 -33
  336. rucio/{api → gateway}/config.py +12 -13
  337. rucio/{api → gateway}/credential.py +15 -4
  338. rucio/{api → gateway}/did.py +384 -140
  339. rucio/{api → gateway}/dirac.py +16 -6
  340. rucio/{api → gateway}/exporter.py +3 -4
  341. rucio/{api → gateway}/heartbeat.py +17 -5
  342. rucio/{api → gateway}/identity.py +63 -19
  343. rucio/{api → gateway}/importer.py +3 -4
  344. rucio/{api → gateway}/lifetime_exception.py +35 -10
  345. rucio/{api → gateway}/lock.py +34 -12
  346. rucio/{api/meta.py → gateway/meta_conventions.py} +18 -16
  347. rucio/{api → gateway}/permission.py +4 -5
  348. rucio/{api → gateway}/quarantined_replica.py +13 -4
  349. rucio/{api → gateway}/replica.py +12 -11
  350. rucio/{api → gateway}/request.py +129 -28
  351. rucio/{api → gateway}/rse.py +11 -12
  352. rucio/{api → gateway}/rule.py +117 -35
  353. rucio/{api → gateway}/scope.py +24 -14
  354. rucio/{api → gateway}/subscription.py +65 -43
  355. rucio/{api → gateway}/vo.py +17 -7
  356. rucio/rse/__init__.py +3 -4
  357. rucio/rse/protocols/__init__.py +0 -1
  358. rucio/rse/protocols/bittorrent.py +184 -0
  359. rucio/rse/protocols/cache.py +1 -2
  360. rucio/rse/protocols/dummy.py +1 -2
  361. rucio/rse/protocols/gfal.py +12 -10
  362. rucio/rse/protocols/globus.py +7 -7
  363. rucio/rse/protocols/gsiftp.py +2 -3
  364. rucio/rse/protocols/http_cache.py +1 -2
  365. rucio/rse/protocols/mock.py +1 -2
  366. rucio/rse/protocols/ngarc.py +1 -2
  367. rucio/rse/protocols/posix.py +12 -13
  368. rucio/rse/protocols/protocol.py +116 -52
  369. rucio/rse/protocols/rclone.py +6 -7
  370. rucio/rse/protocols/rfio.py +4 -5
  371. rucio/rse/protocols/srm.py +9 -10
  372. rucio/rse/protocols/ssh.py +8 -9
  373. rucio/rse/protocols/storm.py +2 -3
  374. rucio/rse/protocols/webdav.py +17 -14
  375. rucio/rse/protocols/xrootd.py +23 -17
  376. rucio/rse/rsemanager.py +19 -7
  377. rucio/tests/__init__.py +0 -1
  378. rucio/tests/common.py +43 -17
  379. rucio/tests/common_server.py +3 -3
  380. rucio/transfertool/__init__.py +0 -1
  381. rucio/transfertool/bittorrent.py +199 -0
  382. rucio/transfertool/bittorrent_driver.py +52 -0
  383. rucio/transfertool/bittorrent_driver_qbittorrent.py +133 -0
  384. rucio/transfertool/fts3.py +250 -138
  385. rucio/transfertool/fts3_plugins.py +152 -0
  386. rucio/transfertool/globus.py +9 -8
  387. rucio/transfertool/globus_library.py +1 -2
  388. rucio/transfertool/mock.py +21 -12
  389. rucio/transfertool/transfertool.py +33 -24
  390. rucio/vcsversion.py +4 -4
  391. rucio/version.py +5 -13
  392. rucio/web/__init__.py +0 -1
  393. rucio/web/rest/__init__.py +0 -1
  394. rucio/web/rest/flaskapi/__init__.py +0 -1
  395. rucio/web/rest/flaskapi/authenticated_bp.py +0 -1
  396. rucio/web/rest/flaskapi/v1/__init__.py +0 -1
  397. rucio/web/rest/flaskapi/v1/accountlimits.py +15 -13
  398. rucio/web/rest/flaskapi/v1/accounts.py +49 -48
  399. rucio/web/rest/flaskapi/v1/archives.py +12 -10
  400. rucio/web/rest/flaskapi/v1/auth.py +146 -144
  401. rucio/web/rest/flaskapi/v1/common.py +82 -41
  402. rucio/web/rest/flaskapi/v1/config.py +5 -6
  403. rucio/web/rest/flaskapi/v1/credentials.py +7 -8
  404. rucio/web/rest/flaskapi/v1/dids.py +158 -28
  405. rucio/web/rest/flaskapi/v1/dirac.py +8 -8
  406. rucio/web/rest/flaskapi/v1/export.py +3 -5
  407. rucio/web/rest/flaskapi/v1/heartbeats.py +3 -5
  408. rucio/web/rest/flaskapi/v1/identities.py +3 -5
  409. rucio/web/rest/flaskapi/v1/import.py +3 -4
  410. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +6 -9
  411. rucio/web/rest/flaskapi/v1/locks.py +2 -4
  412. rucio/web/rest/flaskapi/v1/main.py +10 -2
  413. rucio/web/rest/flaskapi/v1/{meta.py → meta_conventions.py} +26 -11
  414. rucio/web/rest/flaskapi/v1/metrics.py +1 -2
  415. rucio/web/rest/flaskapi/v1/nongrid_traces.py +4 -4
  416. rucio/web/rest/flaskapi/v1/ping.py +6 -7
  417. rucio/web/rest/flaskapi/v1/redirect.py +8 -9
  418. rucio/web/rest/flaskapi/v1/replicas.py +43 -19
  419. rucio/web/rest/flaskapi/v1/requests.py +178 -21
  420. rucio/web/rest/flaskapi/v1/rses.py +61 -26
  421. rucio/web/rest/flaskapi/v1/rules.py +48 -18
  422. rucio/web/rest/flaskapi/v1/scopes.py +3 -5
  423. rucio/web/rest/flaskapi/v1/subscriptions.py +22 -18
  424. rucio/web/rest/flaskapi/v1/traces.py +4 -4
  425. rucio/web/rest/flaskapi/v1/types.py +20 -0
  426. rucio/web/rest/flaskapi/v1/vos.py +3 -5
  427. rucio/web/rest/main.py +0 -1
  428. rucio/web/rest/metrics.py +0 -1
  429. rucio/web/rest/ping.py +27 -0
  430. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/ldap.cfg.template +1 -1
  431. rucio-35.8.0.data/data/rucio/requirements.server.txt +268 -0
  432. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/bootstrap.py +3 -3
  433. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/merge_rucio_configs.py +2 -5
  434. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/reset_database.py +3 -3
  435. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio +87 -85
  436. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-account +0 -1
  437. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-collection-replica +0 -1
  438. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-rse +0 -1
  439. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-admin +45 -32
  440. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-atropos +0 -1
  441. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-auditor +13 -7
  442. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-automatix +1 -2
  443. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-bb8 +0 -1
  444. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-c3po +0 -1
  445. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-client +2 -3
  446. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-consumer +0 -1
  447. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-finisher +1 -2
  448. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-poller +0 -1
  449. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-preparer +0 -1
  450. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-receiver +0 -1
  451. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-stager +0 -1
  452. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-submitter +2 -3
  453. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-throttler +0 -1
  454. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dark-reaper +0 -1
  455. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dumper +11 -10
  456. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-follower +0 -1
  457. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-hermes +0 -1
  458. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-cleaner +0 -1
  459. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-evaluator +2 -3
  460. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-injector +0 -1
  461. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-repairer +0 -1
  462. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-kronos +1 -3
  463. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos +0 -1
  464. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos-temporary-expiration +0 -1
  465. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-necromancer +1 -2
  466. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-oauth-manager +2 -3
  467. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-reaper +0 -1
  468. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-replica-recoverer +6 -7
  469. rucio-35.8.0.data/scripts/rucio-rse-decommissioner +66 -0
  470. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-storage-consistency-actions +0 -1
  471. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-transmogrifier +0 -1
  472. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-undertaker +1 -2
  473. rucio-35.8.0.dist-info/METADATA +72 -0
  474. rucio-35.8.0.dist-info/RECORD +493 -0
  475. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/WHEEL +1 -1
  476. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/AUTHORS.rst +3 -0
  477. rucio/api/temporary_did.py +0 -49
  478. rucio/common/schema/cms.py +0 -478
  479. rucio/common/schema/lsst.py +0 -423
  480. rucio/core/permission/cms.py +0 -1166
  481. rucio/core/temporary_did.py +0 -188
  482. rucio/daemons/reaper/light_reaper.py +0 -255
  483. rucio/web/rest/flaskapi/v1/tmp_dids.py +0 -115
  484. rucio-32.8.6.data/data/rucio/requirements.txt +0 -55
  485. rucio-32.8.6.data/scripts/rucio-light-reaper +0 -53
  486. rucio-32.8.6.dist-info/METADATA +0 -83
  487. rucio-32.8.6.dist-info/RECORD +0 -481
  488. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic.ini.template +0 -0
  489. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
  490. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
  491. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  492. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  493. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  494. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  495. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  496. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  497. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  498. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
  499. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
  500. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
  501. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/LICENSE +0 -0
  502. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/top_level.txt +0 -0
rucio/core/scope.py CHANGED
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright European Organization for Nuclear Research (CERN) since 2012
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +14,13 @@
15
14
 
16
15
  from re import match
17
16
  from traceback import format_exc
18
- from typing import TYPE_CHECKING
17
+ from typing import TYPE_CHECKING, Any, Optional
19
18
 
19
+ from sqlalchemy import and_, select
20
20
  from sqlalchemy.exc import IntegrityError
21
21
 
22
22
  from rucio.common.exception import AccountNotFound, Duplicate, RucioException, VONotFound
23
+ from rucio.common.types import InternalScope
23
24
  from rucio.core.vo import vo_exists
24
25
  from rucio.db.sqla import models
25
26
  from rucio.db.sqla.constants import AccountStatus, ScopeStatus
@@ -41,8 +42,13 @@ def add_scope(scope, account, *, session: "Session"):
41
42
  if not vo_exists(vo=scope.vo, session=session):
42
43
  raise VONotFound('VO {} not found'.format(scope.vo))
43
44
 
44
- result = session.query(models.Account).filter_by(account=account, status=AccountStatus.ACTIVE).first()
45
- if result is None:
45
+ stmt = select(
46
+ models.Account
47
+ ).where(
48
+ and_(models.Account.account == account,
49
+ models.Account.status == AccountStatus.ACTIVE)
50
+ )
51
+ if session.execute(stmt).first() is None:
46
52
  raise AccountNotFound('Account ID \'%s\' does not exist' % account)
47
53
 
48
54
  new_scope = models.Scope(scope=scope, account=account, status=ScopeStatus.OPEN)
@@ -80,7 +86,7 @@ def bulk_add_scopes(scopes, account, skipExisting=False, *, session: "Session"):
80
86
 
81
87
 
82
88
  @read_session
83
- def list_scopes(filter_={}, *, session: "Session"):
89
+ def list_scopes(filter_: Optional[dict[str, Any]] = None, *, session: "Session") -> list[InternalScope]:
84
90
  """
85
91
  Lists all scopes.
86
92
  :param filter_: Dictionary of attributes by which the input data should be filtered
@@ -88,19 +94,25 @@ def list_scopes(filter_={}, *, session: "Session"):
88
94
 
89
95
  :returns: A list containing all scopes.
90
96
  """
91
- scope_list = []
92
- query = session.query(models.Scope).filter(models.Scope.status != ScopeStatus.DELETED)
97
+ filter_ = filter_ or {}
98
+ stmt = select(
99
+ models.Scope.scope
100
+ ).where(
101
+ models.Scope.status != ScopeStatus.DELETED
102
+ )
93
103
  for filter_type in filter_:
94
104
  if filter_type == 'scope':
95
105
  if '*' in filter_['scope'].internal:
96
106
  scope_str = filter_['scope'].internal.replace('*', '%')
97
- query = query.filter(models.Scope.scope.like(scope_str))
107
+ stmt = stmt.where(
108
+ models.Scope.scope.like(scope_str)
109
+ )
98
110
  else:
99
- query = query.filter_by(scope=filter_['scope'])
111
+ stmt = stmt.where(
112
+ models.Scope.scope == filter_['scope']
113
+ )
100
114
 
101
- for s in query:
102
- scope_list.append(s.scope)
103
- return scope_list
115
+ return list(session.execute(stmt).scalars().all())
104
116
 
105
117
 
106
118
  @read_session
@@ -113,17 +125,22 @@ def get_scopes(account, *, session: "Session"):
113
125
  :returns: a list of all scope names for this account.
114
126
  """
115
127
 
116
- result = session.query(models.Account).filter_by(account=account).first()
128
+ stmt = select(
129
+ models.Account
130
+ ).where(
131
+ models.Account.account == account
132
+ )
117
133
 
118
- if result is None:
134
+ if session.execute(stmt).first() is None:
119
135
  raise AccountNotFound('Account ID \'%s\' does not exist' % account)
120
136
 
121
- scope_list = []
122
-
123
- for s in session.query(models.Scope).filter_by(account=account).filter(models.Scope.status != ScopeStatus.DELETED):
124
- scope_list.append(s.scope)
125
-
126
- return scope_list
137
+ stmt = select(
138
+ models.Scope.scope
139
+ ).where(
140
+ and_(models.Scope.account == account,
141
+ models.Scope.status != ScopeStatus.DELETED)
142
+ )
143
+ return session.execute(stmt).scalars().all()
127
144
 
128
145
 
129
146
  @read_session
@@ -136,7 +153,12 @@ def check_scope(scope_to_check, *, session: "Session"):
136
153
  :returns: True or false
137
154
  """
138
155
 
139
- return True if session.query(models.Scope).filter_by(scope=scope_to_check).first() else False
156
+ stmt = select(
157
+ models.Scope
158
+ ).where(
159
+ models.Scope.scope == scope_to_check
160
+ )
161
+ return bool(session.execute(stmt).scalar())
140
162
 
141
163
 
142
164
  @read_session
@@ -149,4 +171,10 @@ def is_scope_owner(scope, account, *, session: "Session"):
149
171
 
150
172
  :returns: True or false
151
173
  """
152
- return True if session.query(models.Scope).filter_by(scope=scope, account=account).first() else False
174
+ stmt = select(
175
+ models.Scope
176
+ ).where(
177
+ and_(models.Scope.scope == scope,
178
+ models.Scope.account == account)
179
+ )
180
+ return bool(session.execute(stmt).scalar())
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright European Organization for Nuclear Research (CERN) since 2012
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,23 +17,23 @@ import logging
18
17
  import re
19
18
  from configparser import NoOptionError, NoSectionError
20
19
  from json import dumps
21
- from typing import TYPE_CHECKING
20
+ from typing import TYPE_CHECKING, Any, Optional
22
21
 
23
- from sqlalchemy import func
24
- from sqlalchemy.exc import IntegrityError, StatementError
22
+ from sqlalchemy import and_, delete, func, select
23
+ from sqlalchemy.exc import IntegrityError, NoResultFound, StatementError
25
24
  from sqlalchemy.orm import aliased
26
- from sqlalchemy.orm.exc import NoResultFound
27
25
 
28
- from rucio.common.config import config_get
29
- from rucio.common.exception import SubscriptionNotFound, SubscriptionDuplicate, RucioException
26
+ from rucio.common.config import config_get_bool
27
+ from rucio.common.exception import RucioException, SubscriptionDuplicate, SubscriptionNotFound
30
28
  from rucio.db.sqla import models
31
- from rucio.db.sqla.constants import SubscriptionState
32
- from rucio.db.sqla.session import transactional_session, stream_session, read_session
29
+ from rucio.db.sqla.constants import RuleState, SubscriptionState
30
+ from rucio.db.sqla.session import read_session, stream_session, transactional_session
33
31
 
34
32
  if TYPE_CHECKING:
35
33
  from collections.abc import Callable, Iterator
36
- from typing import Any, Optional
34
+
37
35
  from sqlalchemy.orm import Session
36
+
38
37
  from rucio.common.types import InternalAccount
39
38
  LoggerFunction = Callable[..., Any]
40
39
  SubscriptionType = dict
@@ -46,10 +45,10 @@ def add_subscription(name: str,
46
45
  filter_: str,
47
46
  replication_rules: str,
48
47
  comments: str,
49
- lifetime: "Optional[int]" = None,
50
- retroactive: "Optional[bool]" = False,
51
- dry_run: "Optional[bool]" = False,
52
- priority: "Optional[int]" = 3,
48
+ lifetime: Optional[int] = None,
49
+ retroactive: Optional[bool] = False,
50
+ dry_run: Optional[bool] = False,
51
+ priority: Optional[int] = 3,
53
52
  *, session: "Session") -> str:
54
53
  """
55
54
  Adds a new subscription which will be verified against every new added file and dataset
@@ -78,7 +77,7 @@ def add_subscription(name: str,
78
77
  :returns: The subscriptionid
79
78
  """
80
79
  try:
81
- keep_history = config_get('subscriptions', 'keep_history')
80
+ keep_history = config_get_bool('subscriptions', 'keep_history')
82
81
  except (NoOptionError, NoSectionError, RuntimeError):
83
82
  keep_history = False
84
83
 
@@ -109,7 +108,9 @@ def add_subscription(name: str,
109
108
  lifetime=new_subscription.lifetime,
110
109
  retroactive=new_subscription.retroactive,
111
110
  policyid=new_subscription.policyid,
112
- comments=new_subscription.comments)
111
+ comments=new_subscription.comments,
112
+ created_at=datetime.datetime.utcnow(),
113
+ updated_at=datetime.datetime.utcnow())
113
114
  try:
114
115
  new_subscription.save(session=session)
115
116
  if keep_history:
@@ -146,10 +147,10 @@ def update_subscription(name: str,
146
147
  :raises: SubscriptionNotFound if subscription is not found
147
148
  """
148
149
  try:
149
- keep_history = config_get('subscriptions', 'keep_history')
150
+ keep_history = config_get_bool('subscriptions', 'keep_history')
150
151
  except (NoOptionError, NoSectionError, RuntimeError):
151
152
  keep_history = False
152
- values = {'state': SubscriptionState.UPDATED}
153
+ values: dict[str, Any] = {'state': SubscriptionState.UPDATED}
153
154
  if 'filter' in metadata and metadata['filter']:
154
155
  values['filter'] = dumps(metadata['filter'])
155
156
  if 'replication_rules' in metadata and metadata['replication_rules']:
@@ -172,7 +173,13 @@ def update_subscription(name: str,
172
173
 
173
174
  SubscriptionHistory = models.SubscriptionHistory
174
175
  try:
175
- subscription = session.query(models.Subscription).filter_by(account=account, name=name).one()
176
+ stmt = select(
177
+ models.Subscription
178
+ ).where(
179
+ and_(models.Subscription.name == name,
180
+ models.Subscription.account == account)
181
+ )
182
+ subscription = session.execute(stmt).scalar_one()
176
183
 
177
184
  # To avoid update in the subscription history table whenever last processed field is changed
178
185
  current_subscription_state = subscription.to_dict()
@@ -196,7 +203,7 @@ def update_subscription(name: str,
196
203
  comments=subscription.comments,
197
204
  last_processed=subscription.last_processed,
198
205
  expired_at=subscription.expired_at,
199
- updated_at=subscription.updated_at,
206
+ updated_at=datetime.datetime.utcnow(),
200
207
  created_at=subscription.created_at)
201
208
  subscription_history.save(session=session)
202
209
  except NoResultFound:
@@ -204,9 +211,9 @@ def update_subscription(name: str,
204
211
 
205
212
 
206
213
  @stream_session
207
- def list_subscriptions(name: "Optional[str]" = None,
214
+ def list_subscriptions(name: Optional[str] = None,
208
215
  account: "Optional[InternalAccount]" = None,
209
- state: "Optional[SubscriptionState]" = None,
216
+ state: Optional[SubscriptionState] = None,
210
217
  *, session: "Session",
211
218
  logger: "LoggerFunction" = logging.log) -> "Iterator[SubscriptionType]":
212
219
  """
@@ -224,23 +231,33 @@ def list_subscriptions(name: "Optional[str]" = None,
224
231
  :rtype: Dict
225
232
  :raises: exception.NotFound if subscription is not found
226
233
  """
227
- query = session.query(models.Subscription)
234
+ stmt = select(
235
+ models.Subscription
236
+ )
228
237
  try:
229
238
  if name:
230
- query = query.filter_by(name=name)
239
+ stmt = stmt.where(
240
+ models.Subscription.name == name
241
+ )
231
242
  if account:
232
- if '*' in account.internal:
243
+ if account.internal is not None and '*' in account.internal:
233
244
  account_str = account.internal.replace('*', '%')
234
- query = query.filter(models.Subscription.account.like(account_str))
245
+ stmt = stmt.where(
246
+ models.Subscription.account.like(account_str)
247
+ )
235
248
  else:
236
- query = query.filter_by(account=account)
249
+ stmt = stmt.where(
250
+ models.Subscription.account == account
251
+ )
237
252
  if state:
238
- query = query.filter_by(state=state)
253
+ stmt = stmt.where(
254
+ models.Subscription.state == state
255
+ )
239
256
  except IntegrityError as error:
240
257
  logger(logging.ERROR, str(error))
241
258
  raise RucioException(error.args)
242
259
  found = False
243
- for row in query:
260
+ for row in session.execute(stmt).scalars().all():
244
261
  found = True
245
262
  yield row.to_dict()
246
263
  if not found:
@@ -255,11 +272,22 @@ def delete_subscription(subscription_id: str, *, session: "Session") -> None:
255
272
  :param subscription_id: Subscription identifier
256
273
  :type subscription_id: String
257
274
  """
258
- session.query(models.Subscription).filter_by(id=subscription_id).delete()
275
+ stmt = delete(
276
+ models.Subscription
277
+ ).where(
278
+ models.Subscription.id == subscription_id
279
+ )
280
+ session.execute(stmt)
259
281
 
260
282
 
261
283
  @stream_session
262
- def list_subscription_rule_states(name=None, account=None, *, session: "Session", logger=logging.log):
284
+ def list_subscription_rule_states(
285
+ name: Optional[str] = None,
286
+ account: Optional["InternalAccount"] = None,
287
+ *,
288
+ session: "Session",
289
+ logger: "LoggerFunction" = logging.log
290
+ ) -> "Iterator[tuple[InternalAccount, str, RuleState, int]]":
263
291
  """Returns a list of with the number of rules per state for a subscription.
264
292
 
265
293
  :param name: Name of the subscription
@@ -271,33 +299,49 @@ def list_subscription_rule_states(name=None, account=None, *, session: "Session"
271
299
  subscription = aliased(models.Subscription)
272
300
  rule = aliased(models.ReplicationRule)
273
301
  # count needs a label to allow conversion to dict (label name can be changed)
274
- query = session.query(
275
- subscription.account, subscription.name, rule.state, func.count().label('count')).join(
276
- rule, subscription.id == rule.subscription_id)
302
+ stmt = select(
303
+ subscription.account,
304
+ subscription.name,
305
+ rule.state,
306
+ func.count().label('count')
307
+ ).join(
308
+ rule,
309
+ subscription.id == rule.subscription_id
310
+ )
277
311
 
278
312
  try:
279
313
  if name:
280
- query = query.filter(subscription.name == name)
314
+ stmt = stmt.where(
315
+ subscription.name == name
316
+ )
281
317
 
282
318
  if account:
283
- if '*' in account.internal:
319
+ if account.internal and '*' in account.internal:
284
320
  account_str = account.internal.replace('*', '%')
285
- query = query.filter(subscription.account.like(account_str))
321
+ stmt = stmt.where(
322
+ subscription.account.like(account_str)
323
+ )
286
324
  else:
287
- query = query.filter(subscription.account == account)
325
+ stmt = stmt.where(
326
+ subscription.account == account
327
+ )
288
328
 
289
329
  except IntegrityError as error:
290
330
  logger(logging.ERROR, str(error))
291
331
  raise RucioException(error.args)
292
332
 
293
- query = query.group_by(subscription.account, subscription.name, rule.state)
333
+ stmt = stmt.group_by(
334
+ subscription.account,
335
+ subscription.name,
336
+ rule.state
337
+ )
294
338
 
295
- for row in query:
296
- yield row
339
+ for row in session.execute(stmt).all():
340
+ yield row._tuple()
297
341
 
298
342
 
299
343
  @read_session
300
- def get_subscription_by_id(subscription_id, *, session: "Session"):
344
+ def get_subscription_by_id(subscription_id: str, *, session: "Session") -> "SubscriptionType":
301
345
  """
302
346
  Get a specific subscription by id.
303
347
 
@@ -308,8 +352,12 @@ def get_subscription_by_id(subscription_id, *, session: "Session"):
308
352
  """
309
353
 
310
354
  try:
311
- subscription = session.query(models.Subscription).filter_by(id=subscription_id).one()
312
- return subscription.to_dict()
355
+ stmt = select(
356
+ models.Subscription
357
+ ).where(
358
+ models.Subscription.id == subscription_id
359
+ )
360
+ return session.execute(stmt).scalar_one().to_dict()
313
361
  except NoResultFound:
314
362
  raise SubscriptionNotFound('No subscription with the id %s found' % (subscription_id))
315
363
  except StatementError:
rucio/core/topology.py CHANGED
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright European Organization for Nuclear Research (CERN) since 2012
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,6 +11,7 @@
12
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
12
  # See the License for the specific language governing permissions and
14
13
  # limitations under the License.
14
+ import copy
15
15
  import datetime
16
16
  import itertools
17
17
  import logging
@@ -19,12 +19,12 @@ import threading
19
19
  import weakref
20
20
  from collections.abc import Callable, Iterable, Iterator
21
21
  from decimal import Decimal
22
- from typing import TYPE_CHECKING, cast, Any, Generic, Optional, TypeVar, Union
22
+ from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast
23
23
 
24
24
  from sqlalchemy import and_, select
25
25
 
26
- from rucio.common.config import config_get_int, config_get
27
- from rucio.common.exception import NoDistance, RSEProtocolNotSupported, InvalidRSEExpression
26
+ from rucio.common.config import config_get, config_get_int
27
+ from rucio.common.exception import InvalidRSEExpression, NoDistance, RSEProtocolNotSupported
28
28
  from rucio.common.utils import PriorityQueue
29
29
  from rucio.core.rse import RseCollection, RseData
30
30
  from rucio.core.rse_expression_parser import parse_expression
@@ -32,15 +32,18 @@ from rucio.db.sqla import models
32
32
  from rucio.db.sqla.session import read_session, transactional_session
33
33
  from rucio.rse import rsemanager as rsemgr
34
34
 
35
- LoggerFunction = Callable[..., Any]
36
35
  _Number = Union[int, Decimal]
37
36
  TN = TypeVar("TN", bound="Node")
38
37
  TE = TypeVar("TE", bound="Edge")
38
+ ExpiringObjectCacheNewObject = TypeVar("ExpiringObjectCacheNewObject")
39
39
 
40
40
  if TYPE_CHECKING:
41
+ from typing import Protocol
42
+
41
43
  from sqlalchemy.orm import Session
44
+ from typing_extensions import Self
42
45
 
43
- from typing import Protocol
46
+ from rucio.common.types import HopDict, LoggerFunction
44
47
 
45
48
  class _StateProvider(Protocol):
46
49
  @property
@@ -81,11 +84,11 @@ class Edge(Generic[TN]):
81
84
 
82
85
  self.add_to_nodes()
83
86
 
84
- def add_to_nodes(self):
87
+ def add_to_nodes(self) -> None:
85
88
  self.src_node.out_edges[self.dst_node] = self
86
89
  self.dst_node.in_edges[self.src_node] = self
87
90
 
88
- def remove_from_nodes(self):
91
+ def remove_from_nodes(self) -> None:
89
92
  self.src_node.out_edges.pop(self.dst_node, None)
90
93
  self.dst_node.in_edges.pop(self.src_node, None)
91
94
 
@@ -105,12 +108,12 @@ class Edge(Generic[TN]):
105
108
  raise ReferenceError("weak reference returned None")
106
109
  return node
107
110
 
108
- def __eq__(self, other):
111
+ def __eq__(self, other: object) -> bool:
109
112
  if not isinstance(other, self.__class__):
110
113
  return False
111
114
  return self._src_node == other._src_node and self._dst_node == other._dst_node
112
115
 
113
- def __str__(self):
116
+ def __str__(self) -> str:
114
117
  return f'{self._src_node}-->{self._dst_node}'
115
118
 
116
119
 
@@ -127,7 +130,7 @@ class Topology(RseCollection, Generic[TN, TE]):
127
130
  ):
128
131
  super().__init__(rse_ids=rse_ids, rse_data_cls=node_cls)
129
132
  self._edge_cls = edge_cls
130
- self._edges = {}
133
+ self._edges: dict[tuple[TN, TN], TE] = {}
131
134
  self._edges_loaded = False
132
135
  self._multihop_nodes = set()
133
136
  self._hop_penalty = DEFAULT_HOP_PENALTY
@@ -135,6 +138,36 @@ class Topology(RseCollection, Generic[TN, TE]):
135
138
 
136
139
  self._lock = threading.RLock()
137
140
 
141
+ @transactional_session
142
+ def ensure_loaded(
143
+ self,
144
+ rse_ids: "Optional[Iterable[str]]" = None,
145
+ load_name: bool = False,
146
+ load_columns: bool = False,
147
+ load_attributes: bool = False,
148
+ load_info: bool = False,
149
+ load_usage: bool = False,
150
+ load_limits: bool = False,
151
+ include_deleted: bool = False,
152
+ *,
153
+ session: "Session",
154
+ ) -> None:
155
+
156
+ if not rse_ids:
157
+ with self._lock:
158
+ rse_ids = list(self.rse_id_to_data_map)
159
+ super().ensure_loaded(
160
+ rse_ids=rse_ids,
161
+ load_name=load_name,
162
+ load_columns=load_columns,
163
+ load_attributes=load_attributes,
164
+ load_info=load_info,
165
+ load_usage=load_usage,
166
+ load_limits=load_limits,
167
+ include_deleted=include_deleted,
168
+ session=session,
169
+ )
170
+
138
171
  def get_or_create(self, rse_id: str) -> "TN":
139
172
  rse_data = self.rse_id_to_data_map.get(rse_id)
140
173
  if rse_data is None:
@@ -146,6 +179,11 @@ class Topology(RseCollection, Generic[TN, TE]):
146
179
  self._edges_loaded = False
147
180
  return rse_data
148
181
 
182
+ @property
183
+ def edges(self) -> dict[tuple[TN, TN], TE]:
184
+ with self._lock:
185
+ return copy.copy(self._edges)
186
+
149
187
  def edge(self, src_node: TN, dst_node: TN) -> "Optional[TE]":
150
188
  return self._edges.get((src_node, dst_node))
151
189
 
@@ -158,7 +196,7 @@ class Topology(RseCollection, Generic[TN, TE]):
158
196
  self._edges[src_node, dst_node] = edge = self._edge_cls(src_node, dst_node)
159
197
  return edge
160
198
 
161
- def delete_edge(self, src_node: TN, dst_node: TN):
199
+ def delete_edge(self, src_node: TN, dst_node: TN) -> None:
162
200
  with self._lock:
163
201
  edge = self._edges[src_node, dst_node]
164
202
  edge.remove_from_nodes()
@@ -168,11 +206,11 @@ class Topology(RseCollection, Generic[TN, TE]):
168
206
  return True if self._multihop_nodes else False
169
207
 
170
208
  @read_session
171
- def configure_multihop(self, multihop_rse_ids: Optional[set[str]] = None, *, session: "Session", logger: LoggerFunction = logging.log):
209
+ def configure_multihop(self, multihop_rse_ids: Optional[set[str]] = None, *, session: "Session", logger: "LoggerFunction" = logging.log) -> "Self":
172
210
  with self._lock:
173
211
  return self._configure_multihop(multihop_rse_ids=multihop_rse_ids, session=session, logger=logger)
174
212
 
175
- def _configure_multihop(self, multihop_rse_ids: Optional[set[str]] = None, *, session: "Session", logger: LoggerFunction = logging.log):
213
+ def _configure_multihop(self, multihop_rse_ids: Optional[set[str]] = None, *, session: "Session", logger: "LoggerFunction" = logging.log) -> "Self":
176
214
 
177
215
  if multihop_rse_ids is None:
178
216
  multihop_rse_expression = config_get('transfers', 'multihop_rse_expression', default='available_for_multihop=true', expiration_time=600, session=session)
@@ -201,7 +239,7 @@ class Topology(RseCollection, Generic[TN, TE]):
201
239
  return self
202
240
 
203
241
  @read_session
204
- def ensure_edges_loaded(self, *, session: "Session"):
242
+ def ensure_edges_loaded(self, *, session: "Session") -> None:
205
243
  """
206
244
  Ensure that all edges are loaded for the (sub-)set of nodes known by this topology object
207
245
  """
@@ -211,7 +249,7 @@ class Topology(RseCollection, Generic[TN, TE]):
211
249
  with self._lock:
212
250
  return self._ensure_edges_loaded(session=session)
213
251
 
214
- def _ensure_edges_loaded(self, *, session: "Session"):
252
+ def _ensure_edges_loaded(self, *, session: "Session") -> None:
215
253
  stmt = select(
216
254
  models.Distance
217
255
  ).where(
@@ -246,7 +284,7 @@ class Topology(RseCollection, Generic[TN, TE]):
246
284
  @read_session
247
285
  def search_shortest_paths(
248
286
  self,
249
- src_nodes: list[TN],
287
+ src_nodes: Iterable[TN],
250
288
  dst_node: TN,
251
289
  operation_src: str,
252
290
  operation_dest: str,
@@ -320,7 +358,7 @@ class Topology(RseCollection, Generic[TN, TE]):
320
358
  node_state_provider=_NodeStateProvider,
321
359
  edge_state_provider=_EdgeStateProvider):
322
360
  nh_node = edge_to_next_hop.dst_node
323
- edge_state = cast(_EdgeStateProvider, edge_state)
361
+ edge_state = cast("_EdgeStateProvider", edge_state)
324
362
  hop = {
325
363
  'source_rse': node,
326
364
  'dest_rse': nh_node,
@@ -386,20 +424,24 @@ class Topology(RseCollection, Generic[TN, TE]):
386
424
  priority_q[adjacent_node] = new_adjacent_dist
387
425
 
388
426
 
389
- class ExpiringObjectCache:
427
+ class ExpiringObjectCache(Generic[ExpiringObjectCacheNewObject]):
390
428
  """
391
429
  Thread-safe container which builds and object with the function passed in parameter and
392
430
  caches it for the TTL duration.
393
431
  """
394
432
 
395
- def __init__(self, ttl, new_obj_fnc):
433
+ def __init__(
434
+ self,
435
+ ttl: int,
436
+ new_obj_fnc: Callable[[], ExpiringObjectCacheNewObject]
437
+ ):
396
438
  self._lock = threading.Lock()
397
- self._object = None
398
- self._creation_time = None
439
+ self._object: Optional[ExpiringObjectCacheNewObject] = None
440
+ self._creation_time: Optional[datetime.datetime] = None
399
441
  self._new_obj_fnc = new_obj_fnc
400
442
  self._ttl = ttl
401
443
 
402
- def get(self, logger=logging.log):
444
+ def get(self, logger: "LoggerFunction" = logging.log) -> ExpiringObjectCacheNewObject:
403
445
  with self._lock:
404
446
  if not self._object \
405
447
  or not self._creation_time \
@@ -417,7 +459,7 @@ def get_hops(
417
459
  multihop_rse_ids: Optional[set[str]] = None,
418
460
  limit_dest_schemes: Optional[list[str]] = None,
419
461
  *, session: "Session",
420
- ):
462
+ ) -> list["HopDict"]:
421
463
  """
422
464
  Get a list of hops needed to transfer date from source_rse_id to dest_rse_id.
423
465
  Ideally, the list will only include one item (dest_rse_id) since no hops are needed.