rucio 32.8.6__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 (481) hide show
  1. rucio/__init__.py +18 -0
  2. rucio/alembicrevision.py +16 -0
  3. rucio/api/__init__.py +14 -0
  4. rucio/api/account.py +266 -0
  5. rucio/api/account_limit.py +287 -0
  6. rucio/api/authentication.py +302 -0
  7. rucio/api/config.py +218 -0
  8. rucio/api/credential.py +60 -0
  9. rucio/api/did.py +726 -0
  10. rucio/api/dirac.py +71 -0
  11. rucio/api/exporter.py +60 -0
  12. rucio/api/heartbeat.py +62 -0
  13. rucio/api/identity.py +160 -0
  14. rucio/api/importer.py +46 -0
  15. rucio/api/lifetime_exception.py +95 -0
  16. rucio/api/lock.py +131 -0
  17. rucio/api/meta.py +85 -0
  18. rucio/api/permission.py +72 -0
  19. rucio/api/quarantined_replica.py +69 -0
  20. rucio/api/replica.py +528 -0
  21. rucio/api/request.py +220 -0
  22. rucio/api/rse.py +601 -0
  23. rucio/api/rule.py +335 -0
  24. rucio/api/scope.py +89 -0
  25. rucio/api/subscription.py +255 -0
  26. rucio/api/temporary_did.py +49 -0
  27. rucio/api/vo.py +112 -0
  28. rucio/client/__init__.py +16 -0
  29. rucio/client/accountclient.py +413 -0
  30. rucio/client/accountlimitclient.py +155 -0
  31. rucio/client/baseclient.py +929 -0
  32. rucio/client/client.py +77 -0
  33. rucio/client/configclient.py +113 -0
  34. rucio/client/credentialclient.py +54 -0
  35. rucio/client/didclient.py +691 -0
  36. rucio/client/diracclient.py +48 -0
  37. rucio/client/downloadclient.py +1674 -0
  38. rucio/client/exportclient.py +44 -0
  39. rucio/client/fileclient.py +51 -0
  40. rucio/client/importclient.py +42 -0
  41. rucio/client/lifetimeclient.py +74 -0
  42. rucio/client/lockclient.py +99 -0
  43. rucio/client/metaclient.py +137 -0
  44. rucio/client/pingclient.py +45 -0
  45. rucio/client/replicaclient.py +444 -0
  46. rucio/client/requestclient.py +109 -0
  47. rucio/client/rseclient.py +664 -0
  48. rucio/client/ruleclient.py +287 -0
  49. rucio/client/scopeclient.py +88 -0
  50. rucio/client/subscriptionclient.py +161 -0
  51. rucio/client/touchclient.py +78 -0
  52. rucio/client/uploadclient.py +871 -0
  53. rucio/common/__init__.py +14 -0
  54. rucio/common/cache.py +74 -0
  55. rucio/common/config.py +796 -0
  56. rucio/common/constants.py +92 -0
  57. rucio/common/constraints.py +18 -0
  58. rucio/common/didtype.py +187 -0
  59. rucio/common/dumper/__init__.py +306 -0
  60. rucio/common/dumper/consistency.py +449 -0
  61. rucio/common/dumper/data_models.py +325 -0
  62. rucio/common/dumper/path_parsing.py +65 -0
  63. rucio/common/exception.py +1092 -0
  64. rucio/common/extra.py +37 -0
  65. rucio/common/logging.py +404 -0
  66. rucio/common/pcache.py +1387 -0
  67. rucio/common/policy.py +84 -0
  68. rucio/common/schema/__init__.py +143 -0
  69. rucio/common/schema/atlas.py +411 -0
  70. rucio/common/schema/belleii.py +406 -0
  71. rucio/common/schema/cms.py +478 -0
  72. rucio/common/schema/domatpc.py +399 -0
  73. rucio/common/schema/escape.py +424 -0
  74. rucio/common/schema/generic.py +431 -0
  75. rucio/common/schema/generic_multi_vo.py +410 -0
  76. rucio/common/schema/icecube.py +404 -0
  77. rucio/common/schema/lsst.py +423 -0
  78. rucio/common/stomp_utils.py +160 -0
  79. rucio/common/stopwatch.py +56 -0
  80. rucio/common/test_rucio_server.py +148 -0
  81. rucio/common/types.py +158 -0
  82. rucio/common/utils.py +1946 -0
  83. rucio/core/__init__.py +14 -0
  84. rucio/core/account.py +426 -0
  85. rucio/core/account_counter.py +171 -0
  86. rucio/core/account_limit.py +357 -0
  87. rucio/core/authentication.py +563 -0
  88. rucio/core/config.py +386 -0
  89. rucio/core/credential.py +218 -0
  90. rucio/core/did.py +3102 -0
  91. rucio/core/did_meta_plugins/__init__.py +250 -0
  92. rucio/core/did_meta_plugins/did_column_meta.py +326 -0
  93. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +116 -0
  94. rucio/core/did_meta_plugins/filter_engine.py +573 -0
  95. rucio/core/did_meta_plugins/json_meta.py +215 -0
  96. rucio/core/did_meta_plugins/mongo_meta.py +199 -0
  97. rucio/core/did_meta_plugins/postgres_meta.py +317 -0
  98. rucio/core/dirac.py +208 -0
  99. rucio/core/distance.py +164 -0
  100. rucio/core/exporter.py +59 -0
  101. rucio/core/heartbeat.py +263 -0
  102. rucio/core/identity.py +290 -0
  103. rucio/core/importer.py +248 -0
  104. rucio/core/lifetime_exception.py +377 -0
  105. rucio/core/lock.py +474 -0
  106. rucio/core/message.py +241 -0
  107. rucio/core/meta.py +190 -0
  108. rucio/core/monitor.py +441 -0
  109. rucio/core/naming_convention.py +154 -0
  110. rucio/core/nongrid_trace.py +124 -0
  111. rucio/core/oidc.py +1339 -0
  112. rucio/core/permission/__init__.py +107 -0
  113. rucio/core/permission/atlas.py +1333 -0
  114. rucio/core/permission/belleii.py +1076 -0
  115. rucio/core/permission/cms.py +1166 -0
  116. rucio/core/permission/escape.py +1076 -0
  117. rucio/core/permission/generic.py +1128 -0
  118. rucio/core/permission/generic_multi_vo.py +1148 -0
  119. rucio/core/quarantined_replica.py +190 -0
  120. rucio/core/replica.py +3627 -0
  121. rucio/core/replica_sorter.py +368 -0
  122. rucio/core/request.py +2241 -0
  123. rucio/core/rse.py +1835 -0
  124. rucio/core/rse_counter.py +155 -0
  125. rucio/core/rse_expression_parser.py +460 -0
  126. rucio/core/rse_selector.py +277 -0
  127. rucio/core/rule.py +3419 -0
  128. rucio/core/rule_grouping.py +1473 -0
  129. rucio/core/scope.py +152 -0
  130. rucio/core/subscription.py +316 -0
  131. rucio/core/temporary_did.py +188 -0
  132. rucio/core/topology.py +448 -0
  133. rucio/core/trace.py +361 -0
  134. rucio/core/transfer.py +1233 -0
  135. rucio/core/vo.py +151 -0
  136. rucio/core/volatile_replica.py +123 -0
  137. rucio/daemons/__init__.py +14 -0
  138. rucio/daemons/abacus/__init__.py +14 -0
  139. rucio/daemons/abacus/account.py +106 -0
  140. rucio/daemons/abacus/collection_replica.py +113 -0
  141. rucio/daemons/abacus/rse.py +107 -0
  142. rucio/daemons/atropos/__init__.py +14 -0
  143. rucio/daemons/atropos/atropos.py +243 -0
  144. rucio/daemons/auditor/__init__.py +261 -0
  145. rucio/daemons/auditor/hdfs.py +86 -0
  146. rucio/daemons/auditor/srmdumps.py +284 -0
  147. rucio/daemons/automatix/__init__.py +14 -0
  148. rucio/daemons/automatix/automatix.py +281 -0
  149. rucio/daemons/badreplicas/__init__.py +14 -0
  150. rucio/daemons/badreplicas/minos.py +311 -0
  151. rucio/daemons/badreplicas/minos_temporary_expiration.py +173 -0
  152. rucio/daemons/badreplicas/necromancer.py +200 -0
  153. rucio/daemons/bb8/__init__.py +14 -0
  154. rucio/daemons/bb8/bb8.py +356 -0
  155. rucio/daemons/bb8/common.py +762 -0
  156. rucio/daemons/bb8/nuclei_background_rebalance.py +147 -0
  157. rucio/daemons/bb8/t2_background_rebalance.py +146 -0
  158. rucio/daemons/c3po/__init__.py +14 -0
  159. rucio/daemons/c3po/algorithms/__init__.py +14 -0
  160. rucio/daemons/c3po/algorithms/simple.py +131 -0
  161. rucio/daemons/c3po/algorithms/t2_free_space.py +125 -0
  162. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +127 -0
  163. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +279 -0
  164. rucio/daemons/c3po/c3po.py +342 -0
  165. rucio/daemons/c3po/collectors/__init__.py +14 -0
  166. rucio/daemons/c3po/collectors/agis.py +108 -0
  167. rucio/daemons/c3po/collectors/free_space.py +62 -0
  168. rucio/daemons/c3po/collectors/jedi_did.py +48 -0
  169. rucio/daemons/c3po/collectors/mock_did.py +46 -0
  170. rucio/daemons/c3po/collectors/network_metrics.py +63 -0
  171. rucio/daemons/c3po/collectors/workload.py +110 -0
  172. rucio/daemons/c3po/utils/__init__.py +14 -0
  173. rucio/daemons/c3po/utils/dataset_cache.py +40 -0
  174. rucio/daemons/c3po/utils/expiring_dataset_cache.py +45 -0
  175. rucio/daemons/c3po/utils/expiring_list.py +63 -0
  176. rucio/daemons/c3po/utils/popularity.py +82 -0
  177. rucio/daemons/c3po/utils/timeseries.py +76 -0
  178. rucio/daemons/cache/__init__.py +14 -0
  179. rucio/daemons/cache/consumer.py +191 -0
  180. rucio/daemons/common.py +391 -0
  181. rucio/daemons/conveyor/__init__.py +14 -0
  182. rucio/daemons/conveyor/common.py +530 -0
  183. rucio/daemons/conveyor/finisher.py +492 -0
  184. rucio/daemons/conveyor/poller.py +372 -0
  185. rucio/daemons/conveyor/preparer.py +198 -0
  186. rucio/daemons/conveyor/receiver.py +206 -0
  187. rucio/daemons/conveyor/stager.py +127 -0
  188. rucio/daemons/conveyor/submitter.py +379 -0
  189. rucio/daemons/conveyor/throttler.py +468 -0
  190. rucio/daemons/follower/__init__.py +14 -0
  191. rucio/daemons/follower/follower.py +97 -0
  192. rucio/daemons/hermes/__init__.py +14 -0
  193. rucio/daemons/hermes/hermes.py +738 -0
  194. rucio/daemons/judge/__init__.py +14 -0
  195. rucio/daemons/judge/cleaner.py +149 -0
  196. rucio/daemons/judge/evaluator.py +172 -0
  197. rucio/daemons/judge/injector.py +154 -0
  198. rucio/daemons/judge/repairer.py +144 -0
  199. rucio/daemons/oauthmanager/__init__.py +14 -0
  200. rucio/daemons/oauthmanager/oauthmanager.py +199 -0
  201. rucio/daemons/reaper/__init__.py +14 -0
  202. rucio/daemons/reaper/dark_reaper.py +272 -0
  203. rucio/daemons/reaper/light_reaper.py +255 -0
  204. rucio/daemons/reaper/reaper.py +701 -0
  205. rucio/daemons/replicarecoverer/__init__.py +14 -0
  206. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +487 -0
  207. rucio/daemons/storage/__init__.py +14 -0
  208. rucio/daemons/storage/consistency/__init__.py +14 -0
  209. rucio/daemons/storage/consistency/actions.py +753 -0
  210. rucio/daemons/tracer/__init__.py +14 -0
  211. rucio/daemons/tracer/kronos.py +513 -0
  212. rucio/daemons/transmogrifier/__init__.py +14 -0
  213. rucio/daemons/transmogrifier/transmogrifier.py +753 -0
  214. rucio/daemons/undertaker/__init__.py +14 -0
  215. rucio/daemons/undertaker/undertaker.py +137 -0
  216. rucio/db/__init__.py +14 -0
  217. rucio/db/sqla/__init__.py +38 -0
  218. rucio/db/sqla/constants.py +192 -0
  219. rucio/db/sqla/migrate_repo/__init__.py +14 -0
  220. rucio/db/sqla/migrate_repo/env.py +111 -0
  221. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +71 -0
  222. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +50 -0
  223. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +61 -0
  224. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +46 -0
  225. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +93 -0
  226. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +78 -0
  227. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +46 -0
  228. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +53 -0
  229. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +69 -0
  230. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +42 -0
  231. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +46 -0
  232. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +61 -0
  233. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +42 -0
  234. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +141 -0
  235. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +75 -0
  236. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +75 -0
  237. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +46 -0
  238. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +51 -0
  239. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +135 -0
  240. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +65 -0
  241. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +42 -0
  242. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +66 -0
  243. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +54 -0
  244. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +43 -0
  245. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +46 -0
  246. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +47 -0
  247. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +54 -0
  248. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +39 -0
  249. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +48 -0
  250. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +47 -0
  251. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +48 -0
  252. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +59 -0
  253. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +47 -0
  254. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +72 -0
  255. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +46 -0
  256. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +45 -0
  257. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +48 -0
  258. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +48 -0
  259. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +42 -0
  260. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +69 -0
  261. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +46 -0
  262. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +78 -0
  263. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +62 -0
  264. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +74 -0
  265. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +44 -0
  266. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +67 -0
  267. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +134 -0
  268. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +58 -0
  269. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +79 -0
  270. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +61 -0
  271. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +45 -0
  272. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +46 -0
  273. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +65 -0
  274. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +42 -0
  275. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +46 -0
  276. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +46 -0
  277. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +80 -0
  278. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +43 -0
  279. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +61 -0
  280. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +47 -0
  281. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +46 -0
  282. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +52 -0
  283. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +42 -0
  284. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +65 -0
  285. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +46 -0
  286. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +47 -0
  287. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +45 -0
  288. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +46 -0
  289. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +48 -0
  290. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +50 -0
  291. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +59 -0
  292. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +48 -0
  293. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +108 -0
  294. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +57 -0
  295. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +51 -0
  296. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +50 -0
  297. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +46 -0
  298. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +42 -0
  299. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +93 -0
  300. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +73 -0
  301. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +52 -0
  302. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +45 -0
  303. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +46 -0
  304. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +54 -0
  305. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +48 -0
  306. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +70 -0
  307. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +48 -0
  308. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +95 -0
  309. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +55 -0
  310. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +74 -0
  311. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +78 -0
  312. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +49 -0
  313. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +124 -0
  314. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +60 -0
  315. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +53 -0
  316. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +56 -0
  317. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +67 -0
  318. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +50 -0
  319. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +46 -0
  320. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +92 -0
  321. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +42 -0
  322. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +46 -0
  323. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +147 -0
  324. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +78 -0
  325. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +53 -0
  326. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +74 -0
  327. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +56 -0
  328. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +46 -0
  329. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +68 -0
  330. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +48 -0
  331. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +149 -0
  332. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +106 -0
  333. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +47 -0
  334. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +45 -0
  335. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +105 -0
  336. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +52 -0
  337. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +106 -0
  338. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +30 -0
  339. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +75 -0
  340. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +49 -0
  341. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +45 -0
  342. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +38 -0
  343. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +44 -0
  344. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +46 -0
  345. rucio/db/sqla/models.py +1834 -0
  346. rucio/db/sqla/sautils.py +48 -0
  347. rucio/db/sqla/session.py +470 -0
  348. rucio/db/sqla/types.py +207 -0
  349. rucio/db/sqla/util.py +521 -0
  350. rucio/rse/__init__.py +97 -0
  351. rucio/rse/protocols/__init__.py +14 -0
  352. rucio/rse/protocols/cache.py +123 -0
  353. rucio/rse/protocols/dummy.py +112 -0
  354. rucio/rse/protocols/gfal.py +701 -0
  355. rucio/rse/protocols/globus.py +243 -0
  356. rucio/rse/protocols/gsiftp.py +93 -0
  357. rucio/rse/protocols/http_cache.py +83 -0
  358. rucio/rse/protocols/mock.py +124 -0
  359. rucio/rse/protocols/ngarc.py +210 -0
  360. rucio/rse/protocols/posix.py +251 -0
  361. rucio/rse/protocols/protocol.py +530 -0
  362. rucio/rse/protocols/rclone.py +365 -0
  363. rucio/rse/protocols/rfio.py +137 -0
  364. rucio/rse/protocols/srm.py +339 -0
  365. rucio/rse/protocols/ssh.py +414 -0
  366. rucio/rse/protocols/storm.py +207 -0
  367. rucio/rse/protocols/webdav.py +547 -0
  368. rucio/rse/protocols/xrootd.py +295 -0
  369. rucio/rse/rsemanager.py +752 -0
  370. rucio/tests/__init__.py +14 -0
  371. rucio/tests/common.py +244 -0
  372. rucio/tests/common_server.py +132 -0
  373. rucio/transfertool/__init__.py +14 -0
  374. rucio/transfertool/fts3.py +1484 -0
  375. rucio/transfertool/globus.py +200 -0
  376. rucio/transfertool/globus_library.py +182 -0
  377. rucio/transfertool/mock.py +81 -0
  378. rucio/transfertool/transfertool.py +212 -0
  379. rucio/vcsversion.py +11 -0
  380. rucio/version.py +46 -0
  381. rucio/web/__init__.py +14 -0
  382. rucio/web/rest/__init__.py +14 -0
  383. rucio/web/rest/flaskapi/__init__.py +14 -0
  384. rucio/web/rest/flaskapi/authenticated_bp.py +28 -0
  385. rucio/web/rest/flaskapi/v1/__init__.py +14 -0
  386. rucio/web/rest/flaskapi/v1/accountlimits.py +234 -0
  387. rucio/web/rest/flaskapi/v1/accounts.py +1088 -0
  388. rucio/web/rest/flaskapi/v1/archives.py +100 -0
  389. rucio/web/rest/flaskapi/v1/auth.py +1642 -0
  390. rucio/web/rest/flaskapi/v1/common.py +385 -0
  391. rucio/web/rest/flaskapi/v1/config.py +305 -0
  392. rucio/web/rest/flaskapi/v1/credentials.py +213 -0
  393. rucio/web/rest/flaskapi/v1/dids.py +2204 -0
  394. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  395. rucio/web/rest/flaskapi/v1/export.py +77 -0
  396. rucio/web/rest/flaskapi/v1/heartbeats.py +129 -0
  397. rucio/web/rest/flaskapi/v1/identities.py +263 -0
  398. rucio/web/rest/flaskapi/v1/import.py +133 -0
  399. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +315 -0
  400. rucio/web/rest/flaskapi/v1/locks.py +360 -0
  401. rucio/web/rest/flaskapi/v1/main.py +83 -0
  402. rucio/web/rest/flaskapi/v1/meta.py +226 -0
  403. rucio/web/rest/flaskapi/v1/metrics.py +37 -0
  404. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  405. rucio/web/rest/flaskapi/v1/ping.py +89 -0
  406. rucio/web/rest/flaskapi/v1/redirect.py +366 -0
  407. rucio/web/rest/flaskapi/v1/replicas.py +1866 -0
  408. rucio/web/rest/flaskapi/v1/requests.py +841 -0
  409. rucio/web/rest/flaskapi/v1/rses.py +2204 -0
  410. rucio/web/rest/flaskapi/v1/rules.py +824 -0
  411. rucio/web/rest/flaskapi/v1/scopes.py +161 -0
  412. rucio/web/rest/flaskapi/v1/subscriptions.py +646 -0
  413. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  414. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  415. rucio/web/rest/flaskapi/v1/tmp_dids.py +115 -0
  416. rucio/web/rest/flaskapi/v1/traces.py +100 -0
  417. rucio/web/rest/flaskapi/v1/vos.py +280 -0
  418. rucio/web/rest/main.py +19 -0
  419. rucio/web/rest/metrics.py +28 -0
  420. rucio-32.8.6.data/data/rucio/etc/alembic.ini.template +71 -0
  421. rucio-32.8.6.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  422. rucio-32.8.6.data/data/rucio/etc/globus-config.yml.template +5 -0
  423. rucio-32.8.6.data/data/rucio/etc/ldap.cfg.template +30 -0
  424. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  425. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  426. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  427. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  428. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  429. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  430. rucio-32.8.6.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  431. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.atlas.client.template +42 -0
  432. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.template +257 -0
  433. rucio-32.8.6.data/data/rucio/etc/rucio_multi_vo.cfg.template +234 -0
  434. rucio-32.8.6.data/data/rucio/requirements.txt +55 -0
  435. rucio-32.8.6.data/data/rucio/tools/bootstrap.py +34 -0
  436. rucio-32.8.6.data/data/rucio/tools/merge_rucio_configs.py +147 -0
  437. rucio-32.8.6.data/data/rucio/tools/reset_database.py +40 -0
  438. rucio-32.8.6.data/scripts/rucio +2540 -0
  439. rucio-32.8.6.data/scripts/rucio-abacus-account +75 -0
  440. rucio-32.8.6.data/scripts/rucio-abacus-collection-replica +47 -0
  441. rucio-32.8.6.data/scripts/rucio-abacus-rse +79 -0
  442. rucio-32.8.6.data/scripts/rucio-admin +2434 -0
  443. rucio-32.8.6.data/scripts/rucio-atropos +61 -0
  444. rucio-32.8.6.data/scripts/rucio-auditor +199 -0
  445. rucio-32.8.6.data/scripts/rucio-automatix +51 -0
  446. rucio-32.8.6.data/scripts/rucio-bb8 +58 -0
  447. rucio-32.8.6.data/scripts/rucio-c3po +86 -0
  448. rucio-32.8.6.data/scripts/rucio-cache-client +135 -0
  449. rucio-32.8.6.data/scripts/rucio-cache-consumer +43 -0
  450. rucio-32.8.6.data/scripts/rucio-conveyor-finisher +59 -0
  451. rucio-32.8.6.data/scripts/rucio-conveyor-poller +67 -0
  452. rucio-32.8.6.data/scripts/rucio-conveyor-preparer +38 -0
  453. rucio-32.8.6.data/scripts/rucio-conveyor-receiver +44 -0
  454. rucio-32.8.6.data/scripts/rucio-conveyor-stager +77 -0
  455. rucio-32.8.6.data/scripts/rucio-conveyor-submitter +140 -0
  456. rucio-32.8.6.data/scripts/rucio-conveyor-throttler +105 -0
  457. rucio-32.8.6.data/scripts/rucio-dark-reaper +54 -0
  458. rucio-32.8.6.data/scripts/rucio-dumper +159 -0
  459. rucio-32.8.6.data/scripts/rucio-follower +45 -0
  460. rucio-32.8.6.data/scripts/rucio-hermes +55 -0
  461. rucio-32.8.6.data/scripts/rucio-judge-cleaner +90 -0
  462. rucio-32.8.6.data/scripts/rucio-judge-evaluator +138 -0
  463. rucio-32.8.6.data/scripts/rucio-judge-injector +45 -0
  464. rucio-32.8.6.data/scripts/rucio-judge-repairer +45 -0
  465. rucio-32.8.6.data/scripts/rucio-kronos +45 -0
  466. rucio-32.8.6.data/scripts/rucio-light-reaper +53 -0
  467. rucio-32.8.6.data/scripts/rucio-minos +54 -0
  468. rucio-32.8.6.data/scripts/rucio-minos-temporary-expiration +51 -0
  469. rucio-32.8.6.data/scripts/rucio-necromancer +121 -0
  470. rucio-32.8.6.data/scripts/rucio-oauth-manager +64 -0
  471. rucio-32.8.6.data/scripts/rucio-reaper +84 -0
  472. rucio-32.8.6.data/scripts/rucio-replica-recoverer +249 -0
  473. rucio-32.8.6.data/scripts/rucio-storage-consistency-actions +75 -0
  474. rucio-32.8.6.data/scripts/rucio-transmogrifier +78 -0
  475. rucio-32.8.6.data/scripts/rucio-undertaker +77 -0
  476. rucio-32.8.6.dist-info/METADATA +83 -0
  477. rucio-32.8.6.dist-info/RECORD +481 -0
  478. rucio-32.8.6.dist-info/WHEEL +5 -0
  479. rucio-32.8.6.dist-info/licenses/AUTHORS.rst +94 -0
  480. rucio-32.8.6.dist-info/licenses/LICENSE +201 -0
  481. rucio-32.8.6.dist-info/top_level.txt +1 -0
rucio/core/__init__.py ADDED
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
rucio/core/account.py ADDED
@@ -0,0 +1,426 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from datetime import datetime
17
+ from enum import Enum
18
+ from re import match
19
+ from traceback import format_exc
20
+ from typing import TYPE_CHECKING
21
+
22
+ from sqlalchemy import select, and_
23
+ from sqlalchemy.exc import IntegrityError
24
+ from sqlalchemy.orm import exc
25
+
26
+ import rucio.core.account_counter
27
+ import rucio.core.rse
28
+ from rucio.common import exception
29
+ from rucio.common.config import config_get_bool
30
+ from rucio.core.vo import vo_exists
31
+ from rucio.db.sqla import models
32
+ from rucio.db.sqla.constants import AccountStatus, AccountType
33
+ from rucio.db.sqla.session import read_session, transactional_session, stream_session
34
+
35
+ if TYPE_CHECKING:
36
+ from sqlalchemy.orm import Session
37
+
38
+
39
+ @transactional_session
40
+ def add_account(account, type_, email, *, session: "Session"):
41
+ """ Add an account with the given account name and type.
42
+
43
+ :param account: the name of the new account.
44
+ :param type_: the type of the new account.
45
+ :param email: The Email address associated with the account.
46
+ :param session: the database session in use.
47
+ """
48
+ vo = account.vo
49
+ if not vo_exists(vo=vo, session=session):
50
+ raise exception.VONotFound('VO {} not found'.format(vo))
51
+
52
+ # Reserve the name 'super_root' for multi_vo admins
53
+ if account.external == 'super_root':
54
+ if not (vo == 'def' and config_get_bool('common', 'multi_vo', raise_exception=False, default=False)):
55
+ raise exception.UnsupportedAccountName('The name "%s" cannot be used.' % account.external)
56
+
57
+ new_account = models.Account(account=account, account_type=type_, email=email,
58
+ status=AccountStatus.ACTIVE)
59
+ try:
60
+ new_account.save(session=session)
61
+ except IntegrityError:
62
+ raise exception.Duplicate('Account ID \'%s\' already exists!' % account)
63
+
64
+
65
+ @read_session
66
+ def account_exists(account, *, session: "Session"):
67
+ """ Checks to see if account exists and is active.
68
+
69
+ :param account: Name of the account.
70
+ :param session: the database session in use.
71
+
72
+ :returns: True if found, otherwise false.
73
+ """
74
+ query = select(
75
+ models.Account
76
+ ).where(
77
+ models.Account.account == account,
78
+ models.Account.status == AccountStatus.ACTIVE
79
+ )
80
+ return session.execute(query).scalar() is not None
81
+
82
+
83
+ @read_session
84
+ def get_account(account, *, session: "Session"):
85
+ """ Returns an account for the given account name.
86
+
87
+ :param account: the name of the account.
88
+ :param session: the database session in use.
89
+
90
+ :returns: a dict with all information for the account.
91
+ """
92
+ query = select(
93
+ models.Account
94
+ ).where(
95
+ models.Account.account == account
96
+ )
97
+
98
+ result = session.execute(query).scalar()
99
+ if result is None:
100
+ raise exception.AccountNotFound('Account with ID \'%s\' cannot be found' % account)
101
+ return result
102
+
103
+
104
+ @transactional_session
105
+ def del_account(account, *, session: "Session"):
106
+ """ Disable an account with the given account name.
107
+
108
+ :param account: the account name.
109
+ :param session: the database session in use.
110
+ """
111
+ query = select(
112
+ models.Account
113
+ ).where(
114
+ models.Account.account == account,
115
+ models.Account.status == AccountStatus.ACTIVE
116
+ )
117
+ try:
118
+ account = session.execute(query).scalar_one()
119
+ except exc.NoResultFound:
120
+ raise exception.AccountNotFound('Account with ID \'%s\' cannot be found' % account)
121
+
122
+ account.update({'status': AccountStatus.DELETED, 'deleted_at': datetime.utcnow()})
123
+
124
+
125
+ @transactional_session
126
+ def update_account(account, key, value, *, session: "Session"):
127
+ """ Update a property of an account.
128
+
129
+ :param account: Name of the account.
130
+ :param key: Account property like status.
131
+ :param value: Property value.
132
+ :param session: the database session in use.
133
+ """
134
+ query = select(
135
+ models.Account
136
+ ).where(
137
+ models.Account.account == account
138
+ )
139
+ try:
140
+ account = session.execute(query).scalar_one()
141
+ except exc.NoResultFound:
142
+ raise exception.AccountNotFound('Account with ID \'%s\' cannot be found' % account)
143
+ if key == 'status':
144
+ if isinstance(value, str):
145
+ value = AccountStatus[value]
146
+ if value == AccountStatus.SUSPENDED:
147
+ account.update({'status': value, 'suspended_at': datetime.utcnow()})
148
+ elif value == AccountStatus.ACTIVE:
149
+ account.update({'status': value, 'suspended_at': None})
150
+ else:
151
+ account.update({key: value})
152
+
153
+
154
+ @stream_session
155
+ def list_accounts(filter_=None, *, session: "Session"):
156
+ """ Returns a list of all account names.
157
+
158
+ :param filter_: Dictionary of attributes by which the input data should be filtered
159
+ :param session: the database session in use.
160
+
161
+ returns: a list of all account names.
162
+ """
163
+ if filter_ is None:
164
+ filter_ = {}
165
+ query = select(
166
+ models.Account.account,
167
+ models.Account.account_type,
168
+ models.Account.email
169
+ ).where(
170
+ models.Account.status == AccountStatus.ACTIVE
171
+ )
172
+ for filter_type in filter_:
173
+ if filter_type == 'account_type':
174
+ if isinstance(filter_['account_type'], str):
175
+ query = query.where(
176
+ models.Account.account_type == AccountType[filter_['account_type']]
177
+ )
178
+ elif isinstance(filter_['account_type'], Enum):
179
+ query = query.where(
180
+ models.Account.account_type == filter_['account_type']
181
+ )
182
+
183
+ elif filter_type == 'identity':
184
+ query = query.join(
185
+ models.IdentityAccountAssociation,
186
+ models.Account.account == models.IdentityAccountAssociation.account
187
+ ).where(
188
+ models.IdentityAccountAssociation.identity == filter_['identity']
189
+ )
190
+
191
+ elif filter_type == 'account':
192
+ if '*' in filter_['account'].internal:
193
+ account_str = filter_['account'].internal.replace('*', '%')
194
+ query = query.where(
195
+ models.Account.account.like(account_str)
196
+ )
197
+ else:
198
+ query = query.where(
199
+ models.Account.account == filter_['account']
200
+ )
201
+ else:
202
+ query = query.join(
203
+ models.AccountAttrAssociation,
204
+ models.Account.account == models.AccountAttrAssociation.account
205
+ ).where(
206
+ models.AccountAttrAssociation.key == filter_type,
207
+ models.AccountAttrAssociation.value == filter_[filter_type]
208
+ )
209
+ query = query.order_by(models.Account.account)
210
+
211
+ for account, account_type, email in session.execute(query).yield_per(25):
212
+ yield {'account': account, 'type': account_type, 'email': email}
213
+
214
+
215
+ @read_session
216
+ def list_identities(account, *, session: "Session"):
217
+ """
218
+ List all identities on an account.
219
+
220
+ :param account: The account name.
221
+ :param session: the database session in use.
222
+ """
223
+ query = select(
224
+ models.Account
225
+ ).where(
226
+ models.Account.account == account,
227
+ models.Account.status == AccountStatus.ACTIVE
228
+ )
229
+ try:
230
+ session.execute(query).scalar_one()
231
+ except exc.NoResultFound:
232
+ raise exception.AccountNotFound('Account with ID \'%s\' cannot be found' % account)
233
+
234
+ query = select(
235
+ models.IdentityAccountAssociation.identity_type.label('type'),
236
+ models.IdentityAccountAssociation.identity,
237
+ models.Identity.email
238
+ ).join(
239
+ models.Identity,
240
+ and_(
241
+ models.Identity.identity == models.IdentityAccountAssociation.identity,
242
+ models.Identity.identity_type == models.IdentityAccountAssociation.identity_type
243
+ )
244
+ ).where(
245
+ models.IdentityAccountAssociation.account == account
246
+ )
247
+ return [row._asdict() for row in session.execute(query)]
248
+
249
+
250
+ @read_session
251
+ def list_account_attributes(account, *, session: "Session"):
252
+ """
253
+ Get all attributes defined for an account.
254
+
255
+ :param account: the account name to list the scopes of.
256
+ :param session: The database session in use.
257
+
258
+ :returns: a list of all key, value pairs for this account.
259
+ """
260
+ query = select(
261
+ models.Account
262
+ ).where(
263
+ models.Account.account == account,
264
+ models.Account.status == AccountStatus.ACTIVE
265
+ )
266
+ try:
267
+ session.execute(query).scalar_one()
268
+ except exc.NoResultFound:
269
+ raise exception.AccountNotFound("Account ID '{0}' does not exist".format(account))
270
+
271
+ query = select(
272
+ models.AccountAttrAssociation.key,
273
+ models.AccountAttrAssociation.value
274
+ ).where(
275
+ models.AccountAttrAssociation.account == account
276
+ )
277
+ return [row._asdict() for row in session.execute(query)]
278
+
279
+
280
+ @read_session
281
+ def has_account_attribute(account, key, *, session: "Session"):
282
+ """
283
+ Indicates whether the named key is present for the account.
284
+
285
+ :param account: the account name to list the scopes of.
286
+ :param key: the key for the attribute.
287
+ :param session: The database session in use.
288
+
289
+ :returns: True or False
290
+ """
291
+ query = select(
292
+ models.AccountAttrAssociation.value
293
+ ).where(
294
+ models.AccountAttrAssociation.account == account,
295
+ models.AccountAttrAssociation.key == key
296
+ )
297
+ return session.execute(query).scalar() is not None
298
+
299
+
300
+ @transactional_session
301
+ def add_account_attribute(account, key, value, *, session: "Session"):
302
+ """
303
+ Add an attribute for the given account name.
304
+
305
+ :param key: the key for the new attribute.
306
+ :param value: the value for the new attribute.
307
+ :param account: the account to add the attribute to.
308
+ :param session: The database session in use.
309
+ """
310
+ query = select(
311
+ models.Account
312
+ ).where(
313
+ models.Account.account == account,
314
+ models.Account.status == AccountStatus.ACTIVE
315
+ )
316
+ try:
317
+ session.execute(query).scalar_one()
318
+ except exc.NoResultFound:
319
+ raise exception.AccountNotFound("Account ID '{0}' does not exist".format(account))
320
+
321
+ new_attr = models.AccountAttrAssociation(account=account, key=key, value=value)
322
+ try:
323
+ new_attr.save(session=session)
324
+ except IntegrityError as error:
325
+ if match('.*IntegrityError.*ORA-00001: unique constraint.*ACCOUNT_ATTR_MAP_PK.*violated.*', error.args[0]) \
326
+ or match('.*IntegrityError.*1062.*Duplicate entry.*for key.*', error.args[0]) \
327
+ or match('.*IntegrityError.*UNIQUE constraint failed: account_attr_map.account, account_attr_map.key.*', error.args[0]) \
328
+ or match('.*IntegrityError.*columns? account.*key.*not unique.*', error.args[0]) \
329
+ or match('.*IntegrityError.*duplicate key value violates unique constraint.*', error.args[0]) \
330
+ or match('.*UniqueViolation.*duplicate key value violates unique constraint.*', error.args[0]):
331
+ raise exception.Duplicate('Key {0} already exist for account {1}!'.format(key, account))
332
+ except Exception:
333
+ raise exception.RucioException(str(format_exc()))
334
+
335
+
336
+ @transactional_session
337
+ def del_account_attribute(account, key, *, session: "Session"):
338
+ """
339
+ Add an attribute for the given account name.
340
+
341
+ :param account: the account to add the attribute to.
342
+ :param key: the key for the new attribute.
343
+ :param session: The database session in use.
344
+ """
345
+ query = select(
346
+ models.AccountAttrAssociation
347
+ ).where(
348
+ models.AccountAttrAssociation.account == account,
349
+ models.AccountAttrAssociation.key == key
350
+ )
351
+ aid = session.execute(query).scalar()
352
+ if aid is None:
353
+ raise exception.AccountNotFound('Attribute ({0}) does not exist for the account {1}!'.format(key, account))
354
+ aid.delete(session=session)
355
+
356
+
357
+ @read_session
358
+ def get_usage(rse_id, account, *, session: "Session"):
359
+ """
360
+ Returns current values of the specified counter, or raises CounterNotFound if the counter does not exist.
361
+
362
+ :param rse_id: The id of the RSE.
363
+ :param account: The account name.
364
+ :param session: The database session in use.
365
+ :returns: A dictionary {'bytes', 'files', 'updated_at'}
366
+ """
367
+ query = select(
368
+ models.AccountUsage.bytes,
369
+ models.AccountUsage.files,
370
+ models.AccountUsage.updated_at
371
+ ).where(
372
+ models.AccountUsage.rse_id == rse_id,
373
+ models.AccountUsage.account == account
374
+ )
375
+ try:
376
+ return session.execute(query).one()._asdict()
377
+ except exc.NoResultFound:
378
+ return {'bytes': 0, 'files': 0, 'updated_at': None}
379
+
380
+
381
+ @read_session
382
+ def get_all_rse_usages_per_account(account, *, session: "Session"):
383
+ """
384
+ Returns current values of the specified counter, or raises CounterNotFound if the counter does not exist.
385
+
386
+ :param rse_id: The id of the RSE.
387
+ :param account: The account name.
388
+ :param session: The database session in use.
389
+ :returns: List of dicts with :py:class:`models.AccountUsage` items
390
+ """
391
+ query = select(
392
+ models.AccountUsage
393
+ ).where(
394
+ models.AccountUsage.account == account
395
+ )
396
+ try:
397
+ return [result.to_dict() for result in session.execute(query).scalars()]
398
+ except exc.NoResultFound:
399
+ return []
400
+
401
+
402
+ @read_session
403
+ def get_usage_history(rse_id, account, *, session: "Session"):
404
+ """
405
+ Returns historical values of the specified counter, or raises CounterNotFound if the counter does not exist.
406
+
407
+ :param rse_id: The id of the RSE.
408
+ :param account: The account name.
409
+ :param session: The database session in use.
410
+ :returns: A dictionary {'bytes', 'files', 'updated_at'}
411
+ """
412
+ query = select(
413
+ models.AccountUsageHistory.bytes,
414
+ models.AccountUsageHistory.files,
415
+ models.AccountUsageHistory.updated_at
416
+ ).where(
417
+ models.AccountUsageHistory.rse_id == rse_id,
418
+ models.AccountUsageHistory.account == account
419
+ ).order_by(
420
+ models.AccountUsageHistory.updated_at
421
+ )
422
+ try:
423
+ return [row._asdict() for row in session.execute(query)]
424
+ except exc.NoResultFound:
425
+ raise exception.CounterNotFound('No usage can be found for account %s on RSE %s' % (account, rucio.core.rse.get_rse_name(rse_id=rse_id, session=session)))
426
+ return []
@@ -0,0 +1,171 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import datetime
16
+ from typing import TYPE_CHECKING
17
+
18
+ from sqlalchemy import literal, insert, select
19
+ from sqlalchemy.orm.exc import NoResultFound
20
+
21
+ from rucio.db.sqla import models, filter_thread_work
22
+ from rucio.db.sqla.session import read_session, transactional_session
23
+
24
+ if TYPE_CHECKING:
25
+ from sqlalchemy.orm import Session
26
+
27
+ MAX_COUNTERS = 10
28
+
29
+
30
+ @transactional_session
31
+ def add_counter(rse_id, account, *, session: "Session"):
32
+ """
33
+ Creates the specified counter for a rse_id and account.
34
+
35
+ :param rse_id: The id of the RSE.
36
+ :param account: The account name.
37
+ :param session: The database session in use
38
+ """
39
+
40
+ models.AccountUsage(rse_id=rse_id, account=account, files=0, bytes=0).save(session=session)
41
+
42
+
43
+ @transactional_session
44
+ def increase(rse_id, account, files, bytes_, *, session: "Session"):
45
+ """
46
+ Increments the specified counter by the specified amount.
47
+
48
+ :param rse_id: The id of the RSE.
49
+ :param account: The account name.
50
+ :param files: The number of added/removed files.
51
+ :param bytes_: The corresponding amount in bytes.
52
+ :param session: The database session in use.
53
+ """
54
+ models.UpdatedAccountCounter(account=account, rse_id=rse_id, files=files, bytes=bytes_).save(session=session)
55
+
56
+
57
+ @transactional_session
58
+ def decrease(rse_id, account, files, bytes_, *, session: "Session"):
59
+ """
60
+ Decreases the specified counter by the specified amount.
61
+
62
+ :param rse_id: The id of the RSE.
63
+ :param account: The account name.
64
+ :param files: The amount of files.
65
+ :param bytes_: The amount of bytes.
66
+ :param session: The database session in use.
67
+ """
68
+ return increase(rse_id=rse_id, account=account, files=-files, bytes_=-bytes_, session=session)
69
+
70
+
71
+ @transactional_session
72
+ def del_counter(rse_id, account, *, session: "Session"):
73
+ """
74
+ Resets the specified counter and initializes it by the specified amounts.
75
+
76
+ :param rse_id: The id of the RSE.
77
+ :param account: The account name.
78
+ :param session: The database session in use.
79
+ """
80
+
81
+ session.query(models.AccountUsage).filter_by(rse_id=rse_id, account=account).delete(synchronize_session=False)
82
+
83
+
84
+ @read_session
85
+ def get_updated_account_counters(total_workers, worker_number, *, session: "Session"):
86
+ """
87
+ Get updated rse_counters.
88
+
89
+ :param total_workers: Number of total workers.
90
+ :param worker_number: id of the executing worker.
91
+ :param session: Database session in use.
92
+ :returns: List of rse_ids whose rse_counters need to be updated.
93
+ """
94
+ query = session.query(models.UpdatedAccountCounter.account, models.UpdatedAccountCounter.rse_id).\
95
+ distinct(models.UpdatedAccountCounter.account, models.UpdatedAccountCounter.rse_id)
96
+
97
+ if session.bind.dialect.name == 'oracle':
98
+ hash_variable = 'CONCAT(account, rse_id)'''
99
+ else:
100
+ hash_variable = 'concat(account, rse_id)'
101
+
102
+ query = filter_thread_work(session=session, query=query, total_threads=total_workers, thread_id=worker_number, hash_variable=hash_variable)
103
+
104
+ return query.all()
105
+
106
+
107
+ @transactional_session
108
+ def update_account_counter(account, rse_id, *, session: "Session"):
109
+ """
110
+ Read the updated_account_counters and update the account_counter.
111
+
112
+ :param account: The account to update.
113
+ :param rse_id: The rse_id to update.
114
+ :param session: Database session in use.
115
+ """
116
+
117
+ updated_account_counters = session.query(models.UpdatedAccountCounter).filter_by(account=account, rse_id=rse_id).all()
118
+
119
+ try:
120
+ account_counter = session.query(models.AccountUsage).filter_by(account=account, rse_id=rse_id).one()
121
+ account_counter.bytes += sum([updated_account_counter.bytes for updated_account_counter in updated_account_counters])
122
+ account_counter.files += sum([updated_account_counter.files for updated_account_counter in updated_account_counters])
123
+ except NoResultFound:
124
+ models.AccountUsage(rse_id=rse_id,
125
+ account=account,
126
+ files=sum([updated_account_counter.files for updated_account_counter in updated_account_counters]),
127
+ bytes=sum([updated_account_counter.bytes for updated_account_counter in updated_account_counters])).save(session=session)
128
+
129
+ for update in updated_account_counters:
130
+ update.delete(flush=False, session=session)
131
+
132
+
133
+ @transactional_session
134
+ def update_account_counter_history(account, rse_id, *, session: "Session"):
135
+ """
136
+ Read the AccountUsage and update the AccountUsageHistory.
137
+
138
+ :param account: The account to update.
139
+ :param rse_id: The rse_id to update.
140
+ :param session: Database session in use.
141
+ """
142
+ counter = session.query(models.AccountUsage).filter_by(rse_id=rse_id, account=account).one_or_none()
143
+ if counter:
144
+ models.AccountUsageHistory(rse_id=rse_id, account=account, files=counter.files, bytes=counter.bytes).save(session=session)
145
+ else:
146
+ models.AccountUsageHistory(rse_id=rse_id, account=account, files=0, bytes=0).save(session=session)
147
+
148
+
149
+ @transactional_session
150
+ def fill_account_counter_history_table(*, session: "Session"):
151
+ """
152
+ Make a snapshot of current counters
153
+
154
+ :param session: Database session in use.
155
+ """
156
+
157
+ select_counters_stmt = select(
158
+ models.AccountUsage.rse_id,
159
+ models.AccountUsage.account,
160
+ models.AccountUsage.files,
161
+ models.AccountUsage.bytes,
162
+ literal(datetime.datetime.utcnow()),
163
+ )
164
+
165
+ stmt = insert(
166
+ models.AccountUsageHistory
167
+ ).from_select(
168
+ ['rse_id', 'account', 'files', 'bytes', 'updated_at'],
169
+ select_counters_stmt
170
+ )
171
+ session.execute(stmt)