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,236 @@
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
+ import datetime
15
+ from typing import TYPE_CHECKING
16
+
17
+ from sqlalchemy import and_, delete, insert, literal, select
18
+ from sqlalchemy.exc import NoResultFound
19
+
20
+ from rucio.db.sqla import filter_thread_work, models
21
+ from rucio.db.sqla.session import read_session, transactional_session
22
+
23
+ if TYPE_CHECKING:
24
+ from sqlalchemy.orm import Session
25
+
26
+ from rucio.common.types import InternalAccount, RSEAccountCounterDict
27
+
28
+ MAX_COUNTERS = 10
29
+
30
+
31
+ @transactional_session
32
+ def add_counter(
33
+ rse_id: str,
34
+ account: "InternalAccount",
35
+ *,
36
+ session: "Session"
37
+ ) -> None:
38
+ """
39
+ Creates the specified counter for a rse_id and account.
40
+
41
+ :param rse_id: The id of the RSE.
42
+ :param account: The account name.
43
+ :param session: The database session in use
44
+ """
45
+
46
+ models.AccountUsage(rse_id=rse_id, account=account, files=0, bytes=0).save(session=session)
47
+
48
+
49
+ @transactional_session
50
+ def increase(
51
+ rse_id: str,
52
+ account: "InternalAccount",
53
+ files: int,
54
+ bytes_: int,
55
+ *,
56
+ session: "Session"
57
+ ) -> None:
58
+ """
59
+ Increments the specified counter by the specified amount.
60
+
61
+ :param rse_id: The id of the RSE.
62
+ :param account: The account name.
63
+ :param files: The number of added/removed files.
64
+ :param bytes_: The corresponding amount in bytes.
65
+ :param session: The database session in use.
66
+ """
67
+ models.UpdatedAccountCounter(account=account, rse_id=rse_id, files=files, bytes=bytes_).save(session=session)
68
+
69
+
70
+ @transactional_session
71
+ def decrease(
72
+ rse_id: str,
73
+ account: "InternalAccount",
74
+ files: int,
75
+ bytes_: int,
76
+ *,
77
+ session: "Session"
78
+ ) -> None:
79
+ """
80
+ Decreases the specified counter by the specified amount.
81
+
82
+ :param rse_id: The id of the RSE.
83
+ :param account: The account name.
84
+ :param files: The amount of files.
85
+ :param bytes_: The amount of bytes.
86
+ :param session: The database session in use.
87
+ """
88
+ return increase(rse_id=rse_id, account=account, files=-files, bytes_=-bytes_, session=session)
89
+
90
+
91
+ @transactional_session
92
+ def del_counter(
93
+ rse_id: str,
94
+ account: "InternalAccount",
95
+ *,
96
+ session: "Session"
97
+ ) -> None:
98
+ """
99
+ Resets the specified counter and initializes it by the specified amounts.
100
+
101
+ :param rse_id: The id of the RSE.
102
+ :param account: The account name.
103
+ :param session: The database session in use.
104
+ """
105
+
106
+ stmt = delete(
107
+ models.AccountUsage
108
+ ).where(
109
+ and_(models.AccountUsage.rse_id == rse_id,
110
+ models.AccountUsage.account == account)
111
+ ).execution_options(
112
+ synchronize_session=False
113
+ )
114
+ session.execute(stmt)
115
+
116
+
117
+ @read_session
118
+ def get_updated_account_counters(
119
+ total_workers: int,
120
+ worker_number: int,
121
+ *,
122
+ session: "Session"
123
+ ) -> list["RSEAccountCounterDict"]:
124
+ """
125
+ Get updated rse_counters.
126
+
127
+ :param total_workers: Number of total workers.
128
+ :param worker_number: id of the executing worker.
129
+ :param session: Database session in use.
130
+ :returns: List of rse_ids whose rse_counters need to be updated.
131
+ """
132
+
133
+ query = select(
134
+ models.UpdatedAccountCounter.account,
135
+ models.UpdatedAccountCounter.rse_id,
136
+ ).distinct(
137
+ )
138
+
139
+ query = filter_thread_work(session=session, query=query, total_threads=total_workers, thread_id=worker_number, hash_variable='CONCAT(account, rse_id)')
140
+
141
+ return [row._asdict() for row in session.execute(query).all()] # type: ignore (pending SQLA2.1: https://github.com/rucio/rucio/discussions/6615)
142
+
143
+
144
+ @transactional_session
145
+ def update_account_counter(
146
+ account: "InternalAccount",
147
+ rse_id: str,
148
+ *,
149
+ session: "Session"
150
+ ) -> None:
151
+ """
152
+ Read the updated_account_counters and update the account_counter.
153
+
154
+ :param account: The account to update.
155
+ :param rse_id: The rse_id to update.
156
+ :param session: Database session in use.
157
+ """
158
+
159
+ stmt = select(
160
+ models.UpdatedAccountCounter
161
+ ).where(
162
+ and_(models.UpdatedAccountCounter.account == account,
163
+ models.UpdatedAccountCounter.rse_id == rse_id)
164
+ )
165
+ updated_account_counters = session.execute(stmt).scalars().all()
166
+
167
+ try:
168
+ stmt = select(
169
+ models.AccountUsage
170
+ ).where(
171
+ and_(models.AccountUsage.account == account,
172
+ models.AccountUsage.rse_id == rse_id)
173
+ )
174
+ account_counter = session.execute(stmt).scalar_one()
175
+ account_counter.bytes += sum([updated_account_counter.bytes for updated_account_counter in updated_account_counters])
176
+ account_counter.files += sum([updated_account_counter.files for updated_account_counter in updated_account_counters])
177
+ except NoResultFound:
178
+ models.AccountUsage(rse_id=rse_id,
179
+ account=account,
180
+ files=sum([updated_account_counter.files for updated_account_counter in updated_account_counters]),
181
+ bytes=sum([updated_account_counter.bytes for updated_account_counter in updated_account_counters])).save(session=session)
182
+
183
+ for update in updated_account_counters:
184
+ update.delete(flush=False, session=session)
185
+
186
+
187
+ @transactional_session
188
+ def update_account_counter_history(
189
+ account: "InternalAccount",
190
+ rse_id: str,
191
+ *,
192
+ session: "Session"
193
+ ) -> None:
194
+ """
195
+ Read the AccountUsage and update the AccountUsageHistory.
196
+
197
+ :param account: The account to update.
198
+ :param rse_id: The rse_id to update.
199
+ :param session: Database session in use.
200
+ """
201
+ stmt = select(
202
+ models.AccountUsage
203
+ ).where(
204
+ and_(models.AccountUsage.account == account,
205
+ models.AccountUsage.rse_id == rse_id)
206
+ )
207
+ counter = session.execute(stmt).scalar_one_or_none()
208
+ if counter:
209
+ models.AccountUsageHistory(rse_id=rse_id, account=account, files=counter.files, bytes=counter.bytes).save(session=session)
210
+ else:
211
+ models.AccountUsageHistory(rse_id=rse_id, account=account, files=0, bytes=0).save(session=session)
212
+
213
+
214
+ @transactional_session
215
+ def fill_account_counter_history_table(*, session: "Session") -> None:
216
+ """
217
+ Make a snapshot of current counters
218
+
219
+ :param session: Database session in use.
220
+ """
221
+
222
+ select_counters_stmt = select(
223
+ models.AccountUsage.rse_id,
224
+ models.AccountUsage.account,
225
+ models.AccountUsage.files,
226
+ models.AccountUsage.bytes,
227
+ literal(datetime.datetime.utcnow()),
228
+ )
229
+
230
+ stmt = insert(
231
+ models.AccountUsageHistory
232
+ ).from_select(
233
+ ['rse_id', 'account', 'files', 'bytes', 'updated_at'],
234
+ select_counters_stmt
235
+ )
236
+ session.execute(stmt)
@@ -0,0 +1,425 @@
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
+ from typing import TYPE_CHECKING, Optional, Union
16
+
17
+ from sqlalchemy.exc import NoResultFound
18
+ from sqlalchemy.sql import func, literal, select
19
+ from sqlalchemy.sql.expression import and_, or_
20
+
21
+ from rucio.core.account import get_all_rse_usages_per_account
22
+ from rucio.core.rse import get_rse_name
23
+ from rucio.core.rse_expression_parser import parse_expression
24
+ from rucio.db.sqla import models
25
+ from rucio.db.sqla.session import read_session, transactional_session
26
+
27
+ if TYPE_CHECKING:
28
+ from sqlalchemy.orm import Session
29
+
30
+ from rucio.common.types import InternalAccount, RSEAccountUsageDict, RSEGlobalAccountUsageDict, RSELocalAccountUsageDict, RSEResolvedGlobalAccountLimitDict
31
+
32
+
33
+ @read_session
34
+ def get_rse_account_usage(rse_id: str, *, session: "Session") -> list["RSEAccountUsageDict"]:
35
+ """
36
+ Returns the account limit and usage for all accounts on a RSE.
37
+
38
+ :param rse_id: The id of the RSE.
39
+ :param session: Database session in use.
40
+ :return: List of dictionaries.
41
+ """
42
+ result = []
43
+ stmt = select(
44
+ models.RSE.id.label('rse_id'),
45
+ models.RSE.vo.label('rse_vo'),
46
+ models.RSE.rse.label('rse_name'),
47
+ models.Account.account,
48
+ models.AccountUsage.files.label('used_files'),
49
+ models.AccountUsage.bytes.label('used_bytes'),
50
+ models.AccountLimit.bytes.label('quota_bytes'),
51
+ ).where(
52
+ models.RSE.id == rse_id
53
+ ).join_from(
54
+ models.RSE,
55
+ models.Account,
56
+ or_(
57
+ and_(
58
+ models.RSE.vo == 'def',
59
+ models.Account.account.notlike('%@%')
60
+ ),
61
+ and_(
62
+ models.RSE.vo != 'def',
63
+ models.Account.account.like(literal('%@') + models.RSE.vo)
64
+ )
65
+ )
66
+ ).outerjoin(
67
+ models.AccountUsage,
68
+ and_(
69
+ models.AccountUsage.account == models.Account.account,
70
+ models.AccountUsage.rse_id == models.RSE.id
71
+ )
72
+ ).outerjoin(
73
+ models.AccountLimit,
74
+ and_(
75
+ models.AccountLimit.account == models.Account.account,
76
+ models.AccountLimit.rse_id == models.RSE.id
77
+ )
78
+ )
79
+ for row in session.execute(stmt):
80
+ if row.rse_vo != row.account.vo:
81
+ continue
82
+ result.append({
83
+ 'rse_id': row.rse_id,
84
+ 'rse': row.rse_name,
85
+ 'account': row.account,
86
+ 'used_files': row.used_files if row.used_files is not None else 0,
87
+ 'used_bytes': row.used_bytes if row.used_bytes is not None else 0,
88
+ 'quota_bytes': row.quota_bytes
89
+ })
90
+ return result
91
+
92
+
93
+ @read_session
94
+ def get_global_account_limits(account: Optional["InternalAccount"] = None, *, session: "Session") -> dict[str, "RSEResolvedGlobalAccountLimitDict"]:
95
+ """
96
+ Returns the global account limits for the account.
97
+
98
+ :param account: Account to check the limit for.
99
+ :param session: Database session in use.
100
+ :return: Dict {'MOCK': {'resolved_rses': ['MOCK'], 'limit': 10, 'resolved_rse_ids': [123]}}.
101
+ """
102
+ if account:
103
+ stmt = select(
104
+ models.AccountGlobalLimit
105
+ ).where(
106
+ models.AccountGlobalLimit.account == account
107
+ )
108
+ global_account_limits = session.execute(stmt).scalars().all()
109
+ else:
110
+ stmt = select(
111
+ models.AccountGlobalLimit
112
+ )
113
+ global_account_limits = session.execute(stmt).scalars().all()
114
+
115
+ resolved_global_account_limits = {}
116
+ for limit in global_account_limits:
117
+ if account:
118
+ resolved_rses = parse_expression(limit['rse_expression'], filter_={'vo': account.vo}, session=session)
119
+ else:
120
+ resolved_rses = parse_expression(limit['rse_expression'], session=session)
121
+ limit_in_bytes = limit['bytes']
122
+ if limit_in_bytes == -1:
123
+ limit_in_bytes = float('inf')
124
+ resolved_global_account_limits[limit['rse_expression']] = {
125
+ 'resolved_rses': [resolved_rse['rse'] for resolved_rse in resolved_rses],
126
+ 'resolved_rse_ids': [resolved_rse['id'] for resolved_rse in resolved_rses],
127
+ 'limit': limit_in_bytes
128
+ }
129
+ return resolved_global_account_limits
130
+
131
+
132
+ @read_session
133
+ def get_global_account_limit(account: "InternalAccount", rse_expression: str, *, session: "Session") -> Union[int, float, None]:
134
+ """
135
+ Returns the global account limit for the account on the rse expression.
136
+
137
+ :param account: Account to check the limit for.
138
+ :param rse_expression: RSE expression to check the limit for.
139
+ :param session: Database session in use.
140
+ :return: Limit in Bytes.
141
+ """
142
+ try:
143
+ stmt = select(
144
+ models.AccountGlobalLimit
145
+ ).where(
146
+ and_(models.AccountGlobalLimit.account == account,
147
+ models.AccountGlobalLimit.rse_expression == rse_expression)
148
+ )
149
+ global_account_limit = session.execute(stmt).scalar_one()
150
+ if global_account_limit.bytes == -1:
151
+ return float("inf")
152
+ else:
153
+ return global_account_limit.bytes
154
+ except NoResultFound:
155
+ return None
156
+
157
+
158
+ @read_session
159
+ def get_local_account_limit(account: "InternalAccount", rse_id: str, *, session: "Session") -> Union[int, float, None]:
160
+ """
161
+ Returns the account limit for the account on the rse.
162
+
163
+ :param account: Account to check the limit for.
164
+ :param rse_id: RSE id to check the limit for.
165
+ :param session: Database session in use.
166
+ :return: Limit in Bytes.
167
+ """
168
+ try:
169
+ stmt = select(
170
+ models.AccountLimit
171
+ ).where(
172
+ and_(models.AccountLimit.account == account,
173
+ models.AccountLimit.rse_id == rse_id)
174
+ )
175
+ account_limit = session.execute(stmt).scalar_one()
176
+ if account_limit.bytes == -1:
177
+ return float("inf")
178
+ else:
179
+ return account_limit.bytes
180
+ except NoResultFound:
181
+ return None
182
+
183
+
184
+ @read_session
185
+ def get_local_account_limits(account: "InternalAccount", rse_ids: Optional[list[str]] = None, *, session: "Session") -> dict[str, int]:
186
+ """
187
+ Returns the account limits for the account on the list of rses.
188
+
189
+ :param account: Account to check the limit for.
190
+ :param rse_ids: List of RSE ids to check the limit for.
191
+ :param session: Database session in use.
192
+ :return: Dictionary {'rse_id': bytes, ...}.
193
+ """
194
+
195
+ account_limits = {}
196
+ if rse_ids:
197
+ rse_id_clauses = []
198
+ for rse_id in rse_ids:
199
+ rse_id_clauses.append(and_(models.AccountLimit.rse_id == rse_id,
200
+ models.AccountLimit.account == account))
201
+ rse_id_clause_chunks = [rse_id_clauses[x:x + 10] for x in range(0, len(rse_id_clauses), 10)]
202
+ for rse_id_chunk in rse_id_clause_chunks:
203
+ stmt = select(
204
+ models.AccountLimit
205
+ ).where(
206
+ or_(*rse_id_chunk)
207
+ )
208
+ tmp_limits = session.execute(stmt).scalars().all()
209
+ for limit in tmp_limits:
210
+ if limit.bytes == -1:
211
+ account_limits[limit.rse_id] = float("inf")
212
+ else:
213
+ account_limits[limit.rse_id] = limit.bytes
214
+ else:
215
+ stmt = select(
216
+ models.AccountLimit
217
+ ).where(
218
+ models.AccountLimit.account == account
219
+ )
220
+ account_limits_tmp = session.execute(stmt).scalars().all()
221
+ for limit in account_limits_tmp:
222
+ if limit.bytes == -1:
223
+ account_limits[limit.rse_id] = float("inf")
224
+ else:
225
+ account_limits[limit.rse_id] = limit.bytes
226
+ return account_limits
227
+
228
+
229
+ @transactional_session
230
+ def set_local_account_limit(account: "InternalAccount", rse_id: str, bytes_: int, *, session: "Session") -> None:
231
+ """
232
+ Returns the limits for the account on the rse.
233
+
234
+ :param account: Account to check the limit for.
235
+ :param rse_id: RSE id to check the limit for.
236
+ :param bytes_: The limit value, in bytes, to set.
237
+ :param session: Database session in use.
238
+ """
239
+ try:
240
+ stmt = select(
241
+ models.AccountLimit
242
+ ).where(
243
+ and_(models.AccountLimit.account == account,
244
+ models.AccountLimit.rse_id == rse_id)
245
+ )
246
+ account_limit = session.execute(stmt).scalar_one()
247
+ account_limit.bytes = bytes_
248
+ except NoResultFound:
249
+ models.AccountLimit(account=account, rse_id=rse_id, bytes=bytes_).save(session=session)
250
+
251
+
252
+ @transactional_session
253
+ def set_global_account_limit(account: "InternalAccount", rse_expression: str, bytes_: int, *, session: "Session") -> None:
254
+ """
255
+ Sets the global limit for the account on a RSE expression.
256
+
257
+ :param account: Account to check the limit for.
258
+ :param rse_expression: RSE expression to check the limit for.
259
+ :param bytes_: The limit value, in bytes, to set.
260
+ :param session: Database session in use.
261
+ """
262
+ try:
263
+ stmt = select(
264
+ models.AccountGlobalLimit
265
+ ).where(
266
+ and_(models.AccountGlobalLimit.account == account,
267
+ models.AccountGlobalLimit.rse_expression == rse_expression)
268
+ )
269
+ account_limit = session.execute(stmt).scalar_one()
270
+ account_limit.bytes = bytes_
271
+ except NoResultFound:
272
+ models.AccountGlobalLimit(account=account, rse_expression=rse_expression, bytes=bytes_).save(session=session)
273
+
274
+
275
+ @transactional_session
276
+ def delete_local_account_limit(account: "InternalAccount", rse_id: str, *, session: "Session") -> bool:
277
+ """
278
+ Deletes a local account limit.
279
+
280
+ :param account: Account to delete the limit for.
281
+ :param rse_id: RSE id to delete the limit for.
282
+ :param session: Database session in use.
283
+ :returns: True if something was deleted; False otherwise.
284
+ """
285
+ try:
286
+ stmt = select(
287
+ models.AccountLimit
288
+ ).where(
289
+ and_(models.AccountLimit.account == account,
290
+ models.AccountLimit.rse_id == rse_id)
291
+ )
292
+ result = session.execute(stmt).scalar_one()
293
+ result.delete(session=session)
294
+ return True
295
+ except NoResultFound:
296
+ return False
297
+
298
+
299
+ @transactional_session
300
+ def delete_global_account_limit(account: "InternalAccount", rse_expression: str, *, session: "Session") -> bool:
301
+ """
302
+ Deletes a global account limit.
303
+
304
+ :param account: Account to delete the limit for.
305
+ :param rse_expression: RSE expression to delete the limit for.
306
+ :param session: Database session in use.
307
+ :returns: True if something was deleted; False otherwise.
308
+ """
309
+ try:
310
+ stmt = select(
311
+ models.AccountGlobalLimit
312
+ ).where(
313
+ and_(models.AccountGlobalLimit.account == account,
314
+ models.AccountGlobalLimit.rse_expression == rse_expression)
315
+ )
316
+ result = session.execute(stmt).scalar_one()
317
+ result.delete(session=session)
318
+ return True
319
+ except NoResultFound:
320
+ return False
321
+
322
+
323
+ @transactional_session
324
+ def get_local_account_usage(account: "InternalAccount", rse_id: Optional[str] = None, *, session: "Session") -> list["RSELocalAccountUsageDict"]:
325
+ """
326
+ Read the account usage and connect it with (if available) the account limits of the account.
327
+
328
+ :param account: The account to read.
329
+ :param rse_id: The rse_id to read (If none, get all).
330
+ :param session: Database session in use.
331
+
332
+ :returns: List of dicts {'rse_id', 'rse', 'bytes', 'files', 'bytes_limit', 'bytes_remaining'}
333
+ """
334
+
335
+ stmt = select(
336
+ models.AccountUsage
337
+ ).where(
338
+ models.AccountUsage.account == account
339
+ )
340
+ if not rse_id:
341
+ # All RSESs
342
+ limits = get_local_account_limits(account=account, session=session)
343
+ counters = {c.rse_id: c for c in session.execute(stmt).scalars().all()}
344
+ else:
345
+ # One RSE
346
+ stmt.where(
347
+ models.AccountUsage.rse_id == rse_id
348
+ )
349
+ limits = get_local_account_limits(account=account, rse_ids=[rse_id], session=session)
350
+ counters = {c.rse_id: c for c in session.execute(stmt).scalars().all()}
351
+ result_list = []
352
+
353
+ for rse_id in set(limits).union(counters):
354
+ counter = counters.get(rse_id)
355
+ if counter:
356
+ counter_files = counter.files
357
+ counter_bytes = counter.bytes
358
+ else:
359
+ counter_files = 0
360
+ counter_bytes = 0
361
+
362
+ if counter_bytes > 0 or counter_files > 0 or rse_id in limits.keys():
363
+ result_list.append({
364
+ 'rse_id': rse_id,
365
+ 'rse': get_rse_name(rse_id=rse_id, session=session),
366
+ 'bytes': counter_bytes,
367
+ 'files': counter_files,
368
+ 'bytes_limit': limits.get(rse_id, 0),
369
+ 'bytes_remaining': limits.get(rse_id, 0) - counter_bytes,
370
+ })
371
+ return result_list
372
+
373
+
374
+ @transactional_session
375
+ def get_global_account_usage(account: "InternalAccount", rse_expression: Optional[str] = None, *, session: "Session") -> list["RSEGlobalAccountUsageDict"]:
376
+ """
377
+ Read the account usage and connect it with the global account limits of the account.
378
+
379
+ :param account: The account to read.
380
+ :param rse_expression: The RSE expression (If none, get all).
381
+ :param session: Database session in use.
382
+
383
+ :returns: List of dicts {'rse_expression', 'bytes', 'files' 'bytes_limit', 'bytes_remaining'}
384
+ """
385
+ result_list = []
386
+ if not rse_expression:
387
+ # All RSE Expressions
388
+ limits = get_global_account_limits(account=account, session=session)
389
+ all_rse_usages = {usage['rse_id']: (usage['bytes'], usage['files']) for usage in get_all_rse_usages_per_account(account=account, session=session)}
390
+ for rse_expression, limit in limits.items():
391
+ usage = 0
392
+ files = 0
393
+ for rse in limit['resolved_rse_ids']:
394
+ usage += all_rse_usages.get(rse, [0])[0]
395
+ files += all_rse_usages.get(rse, [0, 0])[1]
396
+ result_list.append({'rse_expression': rse_expression,
397
+ 'bytes': usage, 'files': files,
398
+ 'bytes_limit': limit['limit'],
399
+ 'bytes_remaining': limit['limit'] - usage})
400
+ else:
401
+ # One RSE Expression
402
+ limit = get_global_account_limit(account=account, rse_expression=rse_expression, session=session)
403
+ vo = account.vo
404
+ resolved_rses = [resolved_rse['id'] for resolved_rse in parse_expression(rse_expression, filter_={'vo': vo}, session=session)]
405
+ stmt = select(
406
+ func.sum(models.AccountUsage.bytes),
407
+ func.sum(models.AccountUsage.files)
408
+ ).where(
409
+ and_(models.AccountUsage.account == account,
410
+ models.AccountUsage.rse_id.in_(resolved_rses))
411
+ ).group_by(
412
+ models.AccountUsage.account
413
+ )
414
+ usage = session.execute(stmt).first()
415
+ if limit is None:
416
+ limit = 0
417
+ if usage is None:
418
+ usage = 0, 0
419
+ result_list.append({
420
+ 'rse_expression': rse_expression,
421
+ 'bytes': usage[0], 'files': usage[1],
422
+ 'bytes_limit': limit,
423
+ 'bytes_remaining': limit - usage[0]
424
+ })
425
+ return result_list