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,260 @@
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 hashlib
15
+ import importlib
16
+ import logging
17
+ from configparser import NoOptionError, NoSectionError
18
+ from typing import TYPE_CHECKING, Any, Optional
19
+
20
+ from rucio.common import config
21
+ from rucio.common.constants import RseAttr
22
+ from rucio.common.exception import ConfigNotFound
23
+ from rucio.common.plugins import PolicyPackageAlgorithms
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Callable, Mapping
27
+
28
+ from rucio.common.types import RSESettingsDict
29
+
30
+
31
+ class RSEDeterministicScopeTranslation(PolicyPackageAlgorithms):
32
+ """
33
+ Translates a pfn dictionary into a scope and name
34
+ """
35
+
36
+ _algorithm_type = "pfn2lfn"
37
+
38
+ def __init__(self, vo: str = 'def'):
39
+ super().__init__()
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ try:
44
+ algorithm_name = config.config_get('policy', self._algorithm_type)
45
+ except (ConfigNotFound, NoOptionError, NoSectionError, RuntimeError):
46
+ logger.debug("PFN2LFN: no algorithm specified in the config.")
47
+ if super()._supports(self._algorithm_type, vo):
48
+ algorithm_name = vo
49
+ else:
50
+ algorithm_name = "def"
51
+ logger.debug("PFN2LFN: Falling back to %s algorithm.", 'default' if algorithm_name == 'def' else algorithm_name)
52
+
53
+ self.parser = self.get_parser(algorithm_name)
54
+
55
+ @classmethod
56
+ def _module_init_(cls) -> None:
57
+ """
58
+ Registers the included scope extraction algorithms
59
+ """
60
+ cls.register(cls._default, "def")
61
+
62
+ @classmethod
63
+ def get_parser(cls, algorithm_name: str) -> 'Callable[..., Any]':
64
+ return super()._get_one_algorithm(cls._algorithm_type, algorithm_name)
65
+
66
+ @classmethod
67
+ def register(
68
+ cls,
69
+ pfn2lfn_callable: 'Callable',
70
+ name: Optional[str] = None
71
+ ) -> None:
72
+ """
73
+ Provided a callable function, register it as one of the valid PFN2LFN algorithms.
74
+
75
+
76
+ :param pfn2lfn_callable: Callable function to use.
77
+ :param name: Algorithm name used for registration.
78
+ """
79
+ if name is None:
80
+ name = pfn2lfn_callable.__name__
81
+ algorithm_dict = {name: pfn2lfn_callable}
82
+ super()._register(cls._algorithm_type, algorithm_dict)
83
+
84
+ @staticmethod
85
+ def _default(parsed_pfn: 'Mapping[str, str]') -> tuple[str, str]:
86
+ """ Translate pfn to name/scope pair
87
+
88
+ :param parsed_pfn: dictionary representing pfn containing:
89
+ - path: str,
90
+ - name: str
91
+ :return: tuple containing name, scope
92
+ """
93
+ path = parsed_pfn['path']
94
+ scope = path.lstrip('/').split('/')[0]
95
+ name = parsed_pfn['name']
96
+ return name, scope
97
+
98
+
99
+ RSEDeterministicScopeTranslation._module_init_() # pylint: disable=protected-access
100
+
101
+
102
+ class RSEDeterministicTranslation(PolicyPackageAlgorithms):
103
+ """
104
+ Execute the logic for translating a LFN to a path.
105
+ """
106
+
107
+ _DEFAULT_LFN2PFN = "hash"
108
+ _algorithm_type = "lfn2pfn"
109
+
110
+ def __init__(
111
+ self,
112
+ rse: Optional[str] = None,
113
+ rse_attributes: Optional["RSESettingsDict"] = None,
114
+ protocol_attributes: Optional[dict[str, Any]] = None
115
+ ):
116
+ """
117
+ Initialize a translator object from the RSE, its attributes, and the protocol-specific
118
+ attributes.
119
+
120
+ :param rse: Name of RSE for this translation.
121
+ :param rse_attributes: A dictionary of RSE-specific attributes for use in the translation.
122
+ :param protocol_attributes: A dictionary of RSE/protocol-specific attributes.
123
+ """
124
+ super().__init__()
125
+ self.rse = rse
126
+ self.rse_attributes = rse_attributes if rse_attributes else {}
127
+ self.protocol_attributes = protocol_attributes if protocol_attributes else {}
128
+
129
+ @classmethod
130
+ def supports(
131
+ cls,
132
+ name: str
133
+ ) -> bool:
134
+ """
135
+ Check to see if a specific algorithm is supported.
136
+
137
+ :param name: Name of the deterministic algorithm.
138
+ :returns: True if `name` is an algorithm supported by the translator class, False otherwise
139
+ """
140
+ return super()._supports(cls._algorithm_type, name)
141
+
142
+ @classmethod
143
+ def register(
144
+ cls,
145
+ lfn2pfn_callable: 'Callable',
146
+ name: Optional[str] = None
147
+ ) -> None:
148
+ """
149
+ Provided a callable function, register it as one of the valid LFN2PFN algorithms.
150
+
151
+ The callable will receive five arguments:
152
+ - scope: Scope of the LFN.
153
+ - name: LFN's path name
154
+ - rse: RSE name the translation is being done for.
155
+ - rse_attributes: Attributes of the RSE.
156
+ - protocol_attributes: Attributes of the RSE's protocol
157
+ The return value should be the last part of the PFN - it will be appended to the
158
+ rest of the URL.
159
+
160
+ :param lfn2pfn_callable: Callable function to use for generating paths.
161
+ :param name: Algorithm name used for registration. If None, then `lfn2pfn_callable.__name__` is used.
162
+ """
163
+ if name is None:
164
+ name = lfn2pfn_callable.__name__
165
+ algorithm_dict = {name: lfn2pfn_callable}
166
+ super()._register(cls._algorithm_type, algorithm_dict)
167
+
168
+ @staticmethod
169
+ def __hash(
170
+ scope: str,
171
+ name: str,
172
+ rse: str,
173
+ rse_attrs: dict[str, Any],
174
+ protocol_attrs: dict[str, Any]
175
+ ) -> str:
176
+ """
177
+ Given a LFN, turn it into a sub-directory structure using a hash function.
178
+
179
+ This takes the MD5 of the LFN and uses the first four characters as a subdirectory
180
+ name.
181
+
182
+ :param scope: Scope of the LFN.
183
+ :param name: File name of the LFN.
184
+ :param rse: RSE for PFN (ignored)
185
+ :param rse_attrs: RSE attributes for PFN (ignored)
186
+ :param protocol_attrs: RSE protocol attributes for PFN (ignored)
187
+ :returns: Path for use in the PFN generation.
188
+ """
189
+ del rse
190
+ del rse_attrs
191
+ del protocol_attrs
192
+ hstr = hashlib.md5(('%s:%s' % (scope, name)).encode('utf-8')).hexdigest()
193
+ if scope.startswith('user') or scope.startswith('group'):
194
+ scope = scope.replace('.', '/')
195
+ return '%s/%s/%s/%s' % (scope, hstr[0:2], hstr[2:4], name)
196
+
197
+ @staticmethod
198
+ def __identity(
199
+ scope: str,
200
+ name: str,
201
+ rse: str,
202
+ rse_attrs: dict[str, Any],
203
+ protocol_attrs: dict[str, Any]
204
+ ) -> str:
205
+ """
206
+ Given a LFN, convert it directly to a path using the mapping:
207
+
208
+ scope:path -> scope/path
209
+
210
+ :param scope: Scope of the LFN.
211
+ :param name: File name of the LFN.
212
+ :param rse: RSE for PFN (ignored)
213
+ :param rse_attrs: RSE attributes for PFN (ignored)
214
+ :param protocol_attrs: RSE protocol attributes for PFN (ignored)
215
+ :returns: Path for use in the PFN generation.
216
+ """
217
+ del rse
218
+ del rse_attrs
219
+ del protocol_attrs
220
+ if scope.startswith('user') or scope.startswith('group'):
221
+ scope = scope.replace('.', '/')
222
+ return '%s/%s' % (scope, name)
223
+
224
+ @classmethod
225
+ def _module_init_(cls) -> None:
226
+ """
227
+ Initialize the class object on first module load.
228
+ """
229
+ cls.register(cls.__hash, "hash")
230
+ cls.register(cls.__identity, "identity")
231
+ policy_module = None
232
+ try:
233
+ policy_module = config.config_get('policy', 'lfn2pfn_module')
234
+ except (ConfigNotFound, NoOptionError, NoSectionError):
235
+ pass
236
+ if policy_module:
237
+ importlib.import_module(policy_module)
238
+
239
+ cls._DEFAULT_LFN2PFN = config.get_lfn2pfn_algorithm_default()
240
+
241
+ def path(
242
+ self,
243
+ scope: str,
244
+ name: str
245
+ ) -> str:
246
+ """ Transforms the logical file name into a PFN's path.
247
+
248
+ :param lfn: filename
249
+ :param scope: scope
250
+
251
+ :returns: RSE specific URI of the physical file
252
+ """
253
+ algorithm = self.rse_attributes.get(RseAttr.LFN2PFN_ALGORITHM, 'default')
254
+ if algorithm == 'default':
255
+ algorithm = RSEDeterministicTranslation._DEFAULT_LFN2PFN
256
+ algorithm_callable = super()._get_one_algorithm(RSEDeterministicTranslation._algorithm_type, algorithm)
257
+ return algorithm_callable(scope, name, self.rse, self.rse_attributes, self.protocol_attributes)
258
+
259
+
260
+ RSEDeterministicTranslation._module_init_() # pylint: disable=protected-access
@@ -0,0 +1,13 @@
1
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
rucio/tests/common.py ADDED
@@ -0,0 +1,280 @@
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
+ import contextlib
16
+ import itertools
17
+ import json
18
+ import os
19
+ import tempfile
20
+ from collections import namedtuple
21
+ from functools import wraps
22
+ from os import rename
23
+ from random import choice, choices
24
+ from string import ascii_letters, ascii_uppercase, digits
25
+ from typing import IO, TYPE_CHECKING, Any, Literal, Optional
26
+
27
+ import pytest
28
+ import requests
29
+
30
+ from rucio.common.config import config_get, config_get_bool, get_config_dirs
31
+ from rucio.common.utils import execute
32
+ from rucio.common.utils import generate_uuid as uuid
33
+
34
+ if TYPE_CHECKING:
35
+ from collections.abc import Callable, Iterable, Iterator
36
+ from types import ModuleType
37
+
38
+ from werkzeug.test import TestResponse
39
+
40
+ skip_rse_tests_with_accounts = pytest.mark.skipif(not any(os.path.exists(os.path.join(d, 'rse-accounts.cfg')) for d in get_config_dirs()),
41
+ reason='fails if no rse-accounts.cfg found')
42
+ skiplimitedsql = pytest.mark.skipif('RDBMS' in os.environ and os.environ['RDBMS'] == 'sqlite',
43
+ reason="does not work in SQLite because of missing features")
44
+ skip_multivo = pytest.mark.skipif('SUITE' in os.environ and os.environ['SUITE'] == 'multi_vo',
45
+ reason="does not work for multiVO")
46
+ skip_non_belleii = pytest.mark.skipif(not ('POLICY' in os.environ and os.environ['POLICY'] == 'belleii'),
47
+ reason="specific belleii tests")
48
+ skip_outside_gh_actions = pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") != "true",
49
+ reason="Skipping tests outside GitHub Actions")
50
+
51
+
52
+ def is_influxdb_available() -> bool:
53
+ """Return True if influxdb is available, else return False."""
54
+ try:
55
+ response = requests.get('http://localhost:8086/ping')
56
+ return response.status_code == 204
57
+ except requests.exceptions.ConnectionError:
58
+ print('InfluxDB is not running at localhost:8086')
59
+ return False
60
+
61
+
62
+ def is_elasticsearch_available() -> bool:
63
+ """Return True if elasticsearch is available, else return False."""
64
+ try:
65
+ response = requests.get('http://localhost:9200/')
66
+ return response.status_code == 200
67
+ except requests.exceptions.ConnectionError:
68
+ print('Elasticsearch is not running at localhost:9200')
69
+ return False
70
+
71
+
72
+ skip_missing_elasticsearch_influxdb_in_env = pytest.mark.skipif(not (is_influxdb_available() and is_elasticsearch_available()), reason='influxdb is not available')
73
+
74
+
75
+ def get_long_vo() -> str:
76
+ """ Get the VO name from the config file for testing.
77
+ Don't map the name to a short version.
78
+ :returns: VO name string.
79
+ """
80
+ vo_name = 'def'
81
+ if config_get_bool('common', 'multi_vo', raise_exception=False, default=False):
82
+ vo = config_get('client', 'vo', raise_exception=False, default=None)
83
+ if vo is not None:
84
+ vo_name = vo
85
+ return vo_name
86
+
87
+
88
+ def account_name_generator() -> str:
89
+ """ Generate random account name.
90
+
91
+ :returns: A random account name
92
+ """
93
+ return 'jdoe-' + str(uuid()).lower()[:16]
94
+
95
+
96
+ def scope_name_generator() -> str:
97
+ """ Generate random scope name.
98
+
99
+ :returns: A random scope name
100
+ """
101
+ return 'mock_' + str(uuid()).lower()[:16]
102
+
103
+
104
+ def did_name_generator(did_type: str = 'file', name_prefix: str = '', name_suffix: str = '', path: Optional[str] = None) -> str:
105
+ """ Generate random did name.
106
+ :param did_type: A string to create a meaningful did_name depending on the did_type (file, dataset, container)
107
+ :param name_prefix: String to prefix to the did name
108
+ :param name_suffix: String to append to the did name
109
+ :param path: If specified, use the path to generate the did_name
110
+
111
+ :returns: A random did name
112
+ """
113
+ if os.getenv('POLICY') == 'belleii':
114
+ if path is not None:
115
+ return path
116
+
117
+ container_path = os.path.join("/belle", name_prefix if name_prefix else "mock", 'cont_%s' % str(uuid()))
118
+ if did_type == 'container':
119
+ return container_path
120
+
121
+ dataset_path = os.path.join(container_path, 'dataset_%s' % str(uuid()))
122
+ if did_type == 'dataset':
123
+ return dataset_path
124
+
125
+ file_path = os.path.join(dataset_path, 'file_%s%s' % (str(uuid()), name_suffix))
126
+ return file_path
127
+
128
+ if path is not None:
129
+ return os.path.basename(path)
130
+
131
+ return '%s%s_%s%s' % (name_prefix, did_type, str(uuid()), name_suffix)
132
+
133
+
134
+ def rse_name_generator(size: int = 10) -> str:
135
+ """ Generate random RSE name.
136
+
137
+ :returns: A random RSE name
138
+ """
139
+ return 'MOCK-' + ''.join(choice(ascii_uppercase) for x in range(size)) # noqa: S311
140
+
141
+
142
+ def rfc2253_dn_generator() -> str:
143
+ """ Generate a random DN in RFC 2253 format.
144
+
145
+ :returns: A random DN
146
+ """
147
+ random_cn = ''.join(choices(ascii_letters + digits, k=8)) # noqa: S311
148
+ random_o = ''.join(choices(ascii_letters + digits, k=8)) # noqa: S311
149
+ random_c = ''.join(choices(ascii_letters, k=2)) # noqa: S311
150
+ random_dn = "CN={}, O={}, C={}".format(random_cn, random_o, random_c)
151
+ return random_dn
152
+
153
+
154
+ def file_generator(size: int = 2, namelen: int = 10) -> str:
155
+ """ Create a bogus file and returns it's name.
156
+ :param size: size in bytes
157
+ :returns: The name of the generated file.
158
+ """
159
+ fn = '/tmp/file_' + ''.join(choice(ascii_uppercase) for x in range(namelen)) # noqa: S311
160
+ execute('dd if=/dev/urandom of={0} count={1} bs=1'.format(fn, size))
161
+ return fn
162
+
163
+
164
+ def make_temp_file(dir_: str, data: str) -> str:
165
+ """
166
+ Creates a temporal file and write `data` on it.
167
+ :param data: String to be written on the created file.
168
+ :returns: Name of the temporal file.
169
+ """
170
+ fd, path = tempfile.mkstemp(dir=dir_)
171
+ with os.fdopen(fd, 'w', encoding='utf-8') as f:
172
+ f.write(data)
173
+ return path
174
+
175
+
176
+ @contextlib.contextmanager
177
+ def mock_open(module: "ModuleType", file_like_object: IO):
178
+ call_info = {}
179
+
180
+ def mocked_open(
181
+ filename: str,
182
+ mode: str = 'r'
183
+ ) -> contextlib.closing[IO]:
184
+ call_info['filename'] = filename
185
+ call_info['mode'] = mode
186
+ file_like_object.close = lambda: None
187
+ return contextlib.closing(file_like_object)
188
+
189
+ setattr(module, 'open', mocked_open)
190
+ try:
191
+ yield call_info
192
+ finally:
193
+ file_like_object.seek(0)
194
+ delattr(module, 'open')
195
+
196
+
197
+ def print_response(rest_response: "TestResponse") -> None:
198
+ print('Status:', rest_response.status)
199
+ print()
200
+ nohdrs = True
201
+ for hdr, val in rest_response.headers.items():
202
+ if nohdrs:
203
+ print('Headers:')
204
+ print('-------')
205
+ nohdrs = False
206
+ print('%s: %s' % (hdr, val))
207
+
208
+ if not nohdrs:
209
+ print()
210
+
211
+ text = rest_response.get_data(as_text=True)
212
+ print(text if text else '<no content>')
213
+
214
+
215
+ def headers(*iterables: "Iterable") -> list[itertools.chain]:
216
+ return list(itertools.chain(*iterables))
217
+
218
+
219
+ def loginhdr(account: str, username: str, password: str) -> "Iterator[tuple[Literal['X-Rucio-Account', 'X-Rucio-Username', 'X-Rucio-Password'], str]]":
220
+ yield 'X-Rucio-Account', str(account)
221
+ yield 'X-Rucio-Username', str(username)
222
+ yield 'X-Rucio-Password', str(password)
223
+
224
+
225
+ def auth(token) -> "Iterator[tuple[Literal['X-Rucio-Auth-Token'], str]]":
226
+ yield 'X-Rucio-Auth-Token', str(token)
227
+
228
+
229
+ def vohdr(vo: str) -> "Iterator[tuple[Literal['X-Rucio-VO'], str]]":
230
+ if vo:
231
+ yield 'X-Rucio-VO', str(vo)
232
+
233
+
234
+ def hdrdict(dictionary: dict[str, Any]) -> "Iterator[tuple[str, str]]":
235
+ for key in dictionary:
236
+ yield str(key), str(dictionary[key])
237
+
238
+
239
+ def accept(mimetype: "Mime") -> "Iterator[tuple[Literal['Accept'], Mime]]":
240
+ yield 'Accept', mimetype
241
+
242
+
243
+ class Mime:
244
+ """ Enum-type class for mimetypes. """
245
+ METALINK = 'application/metalink4+xml'
246
+ JSON = 'application/json'
247
+ JSON_STREAM = 'application/x-json-stream'
248
+ BINARY = 'application/octet-stream'
249
+
250
+
251
+ def load_test_conf_file(file_name: str) -> dict[str, Any]:
252
+ config_dir = next(filter(lambda d: os.path.exists(os.path.join(d, file_name)), get_config_dirs()))
253
+ with open(os.path.join(config_dir, file_name)) as f:
254
+ return json.load(f)
255
+
256
+
257
+ def remove_config(func: "Callable") -> "Callable":
258
+ @wraps(func)
259
+ def wrapper(*args, **kwargs) -> None:
260
+ for configfile in get_config_dirs():
261
+ # Rename the config to <config>.tmp
262
+ try:
263
+ rename(f"{configfile}rucio.cfg", f"{configfile}rucio.cfg.tmp")
264
+ except FileNotFoundError:
265
+ pass # When a test uses a os.env assigned conf, there's nothing stating the default location has something
266
+ try:
267
+ # Execute the test
268
+ func(*args, **kwargs)
269
+ finally:
270
+ # And put the config back
271
+ for configfile in get_config_dirs():
272
+ try:
273
+ rename(f"{configfile}rucio.cfg.tmp", f"{configfile}rucio.cfg")
274
+ except FileNotFoundError:
275
+ pass
276
+
277
+ return wrapper
278
+
279
+
280
+ RSE_namedtuple = namedtuple('RSE_namedtuple', ['name', 'id'])
@@ -0,0 +1,149 @@
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 copy
15
+ from typing import TYPE_CHECKING, Optional
16
+
17
+ from sqlalchemy import and_, delete, exists, select
18
+ from sqlalchemy.orm import Session, aliased
19
+
20
+ from rucio.core import config as core_config
21
+ from rucio.core.vo import map_vo
22
+ from rucio.db.sqla import models
23
+ from rucio.db.sqla.session import get_session, transactional_session
24
+
25
+ from .common import get_long_vo
26
+
27
+ if TYPE_CHECKING:
28
+ from collections.abc import Iterator
29
+
30
+ from sqlalchemy.sql.elements import ColumnElement
31
+ from sqlalchemy.sql.schema import ForeignKeyConstraint
32
+ from sqlalchemy.sql.selectable import FromClause
33
+
34
+ # Functions containing server-only includes that can't be included in client tests
35
+ # For each table, get the foreign key constraints from all other tables towards this table.
36
+ INBOUND_FOREIGN_KEYS: "dict[FromClause, set[ForeignKeyConstraint]]" = {}
37
+ for __table in models.BASE.metadata.tables.values():
38
+ for __fk in __table.foreign_key_constraints:
39
+ INBOUND_FOREIGN_KEYS.setdefault(__fk.referred_table, set()).add(__fk)
40
+
41
+
42
+ def _dependency_paths(
43
+ stack: list["ForeignKeyConstraint"],
44
+ nb_times_in_stack: dict["FromClause", int],
45
+ cur_table: "FromClause"
46
+ ) -> "Iterator":
47
+ """
48
+ Generates lists of foreign keys: paths starting at cur_table and
49
+ navigating the table graph via foreign key constraints.
50
+
51
+ For example: As of time of writing, for cur_table = models.ReplicationRule.__table__,
52
+ it will generate
53
+ [DATASET_LOCKS_RULE_ID_FK] # rule.id <-> dataset_locks.rule_id
54
+ [LOCKS_RULE_ID_FK] # rule.id <-> locks.rule_id
55
+ [RULES_CHILD_RULE_ID_FK, DATASET_LOCKS_RULE_ID_FK] # rule.id <-> rule(alias).child_rule_id, rule(alias).id <-> dataset_locks.rule_id
56
+ [RULES_CHILD_RULE_ID_FK, LOCKS_RULE_ID_FK] # rule.id <-> rule(alias).child_rule_id, rule(alias).id <-> locks.rule_id
57
+ [RULES_CHILD_RULE_ID_FK] # rule.id <-> rule(alias).child_rule_id
58
+ """
59
+ nb_times_in_stack[cur_table] = nb_times_in_stack.get(cur_table, 0) + 1
60
+
61
+ for fk in INBOUND_FOREIGN_KEYS.get(cur_table, []):
62
+ if nb_times_in_stack.get(fk.table, 0) > 1:
63
+ # Only allow a table to appear twice in the stack.
64
+ # This handles recursive constraints (like the one between rules and itself)
65
+ continue
66
+ stack.append(fk)
67
+ yield from _dependency_paths(stack, nb_times_in_stack, fk.table)
68
+
69
+ if stack:
70
+ yield copy.copy(stack)
71
+ fk = stack.pop()
72
+ nb_times_in_stack[fk.table] -= 1
73
+
74
+
75
+ @transactional_session
76
+ def cleanup_db_deps(
77
+ model: models.BASE,
78
+ select_rows_stmt: "ColumnElement",
79
+ *,
80
+ session: Optional["Session"] = None
81
+ ) -> None:
82
+ """
83
+ Removes rows which have foreign key constraints pointing to rows
84
+ selected by `select_rows_stmt` in `model`. The deletion is transitive.
85
+ This implements a behavior similar to "ON DELETE CASCADE", but without
86
+ removing the initial rows from `model`, only their dependencies.
87
+ """
88
+
89
+ for fk_path in _dependency_paths(stack=[], nb_times_in_stack={}, cur_table=model.__table__):
90
+ seen_tables = set()
91
+ referred_table = model.__table__
92
+ current_table = fk_path[-1].table
93
+ filters = []
94
+ for i, fk in enumerate(fk_path):
95
+ current_table = fk.table
96
+ if current_table in seen_tables:
97
+ current_table = aliased(current_table)
98
+ else:
99
+ seen_tables.add(current_table)
100
+
101
+ filters.append(and_(current_table.columns.get(e.parent.name) == referred_table.columns.get(e.column.name) for e in fk.elements)) # type: ignore
102
+ referred_table = current_table
103
+
104
+ if session.bind.dialect.name == 'mysql': # type: ignore (bind could be None)
105
+ stmt = delete(
106
+ current_table
107
+ ).where(
108
+ and_(*filters)
109
+ ).where(
110
+ select_rows_stmt
111
+ )
112
+ else:
113
+ stmt = delete(
114
+ current_table,
115
+ ).where(
116
+ exists(
117
+ select(
118
+ 1
119
+ ).where(
120
+ and_(*filters)
121
+ ).where(
122
+ select_rows_stmt
123
+ )
124
+ )
125
+ )
126
+
127
+ stmt = stmt.execution_options(
128
+ synchronize_session=False
129
+ )
130
+
131
+ session.execute(stmt) # type: ignore (Session could be None)
132
+
133
+
134
+ def reset_config_table() -> None:
135
+ """ Clear the config table and install any default entries needed for the tests.
136
+ """
137
+ db_session = get_session()
138
+ db_session.query(models.Config).delete()
139
+ db_session.commit()
140
+ core_config.set("vo-map", "testvo1", "tst")
141
+ core_config.set("vo-map", "testvo2", "ts2")
142
+
143
+
144
+ def get_vo() -> str:
145
+ """ Gets the current short/mapped VO name for testing.
146
+ Maps the vo name to the short name, if configured.
147
+ :returns: VO name string.
148
+ """
149
+ return map_vo(get_long_vo())