rucio 35.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rucio might be problematic. Click here for more details.

Files changed (493) hide show
  1. rucio/__init__.py +17 -0
  2. rucio/alembicrevision.py +15 -0
  3. rucio/client/__init__.py +15 -0
  4. rucio/client/accountclient.py +433 -0
  5. rucio/client/accountlimitclient.py +183 -0
  6. rucio/client/baseclient.py +974 -0
  7. rucio/client/client.py +76 -0
  8. rucio/client/configclient.py +126 -0
  9. rucio/client/credentialclient.py +59 -0
  10. rucio/client/didclient.py +866 -0
  11. rucio/client/diracclient.py +56 -0
  12. rucio/client/downloadclient.py +1785 -0
  13. rucio/client/exportclient.py +44 -0
  14. rucio/client/fileclient.py +50 -0
  15. rucio/client/importclient.py +42 -0
  16. rucio/client/lifetimeclient.py +90 -0
  17. rucio/client/lockclient.py +109 -0
  18. rucio/client/metaconventionsclient.py +140 -0
  19. rucio/client/pingclient.py +44 -0
  20. rucio/client/replicaclient.py +454 -0
  21. rucio/client/requestclient.py +125 -0
  22. rucio/client/rseclient.py +746 -0
  23. rucio/client/ruleclient.py +294 -0
  24. rucio/client/scopeclient.py +90 -0
  25. rucio/client/subscriptionclient.py +173 -0
  26. rucio/client/touchclient.py +82 -0
  27. rucio/client/uploadclient.py +955 -0
  28. rucio/common/__init__.py +13 -0
  29. rucio/common/cache.py +74 -0
  30. rucio/common/config.py +801 -0
  31. rucio/common/constants.py +159 -0
  32. rucio/common/constraints.py +17 -0
  33. rucio/common/didtype.py +189 -0
  34. rucio/common/dumper/__init__.py +335 -0
  35. rucio/common/dumper/consistency.py +452 -0
  36. rucio/common/dumper/data_models.py +318 -0
  37. rucio/common/dumper/path_parsing.py +64 -0
  38. rucio/common/exception.py +1151 -0
  39. rucio/common/extra.py +36 -0
  40. rucio/common/logging.py +420 -0
  41. rucio/common/pcache.py +1408 -0
  42. rucio/common/plugins.py +153 -0
  43. rucio/common/policy.py +84 -0
  44. rucio/common/schema/__init__.py +150 -0
  45. rucio/common/schema/atlas.py +413 -0
  46. rucio/common/schema/belleii.py +408 -0
  47. rucio/common/schema/domatpc.py +401 -0
  48. rucio/common/schema/escape.py +426 -0
  49. rucio/common/schema/generic.py +433 -0
  50. rucio/common/schema/generic_multi_vo.py +412 -0
  51. rucio/common/schema/icecube.py +406 -0
  52. rucio/common/stomp_utils.py +159 -0
  53. rucio/common/stopwatch.py +55 -0
  54. rucio/common/test_rucio_server.py +148 -0
  55. rucio/common/types.py +403 -0
  56. rucio/common/utils.py +2238 -0
  57. rucio/core/__init__.py +13 -0
  58. rucio/core/account.py +496 -0
  59. rucio/core/account_counter.py +236 -0
  60. rucio/core/account_limit.py +423 -0
  61. rucio/core/authentication.py +620 -0
  62. rucio/core/config.py +456 -0
  63. rucio/core/credential.py +225 -0
  64. rucio/core/did.py +3000 -0
  65. rucio/core/did_meta_plugins/__init__.py +252 -0
  66. rucio/core/did_meta_plugins/did_column_meta.py +331 -0
  67. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
  68. rucio/core/did_meta_plugins/filter_engine.py +613 -0
  69. rucio/core/did_meta_plugins/json_meta.py +240 -0
  70. rucio/core/did_meta_plugins/mongo_meta.py +216 -0
  71. rucio/core/did_meta_plugins/postgres_meta.py +316 -0
  72. rucio/core/dirac.py +237 -0
  73. rucio/core/distance.py +187 -0
  74. rucio/core/exporter.py +59 -0
  75. rucio/core/heartbeat.py +363 -0
  76. rucio/core/identity.py +300 -0
  77. rucio/core/importer.py +259 -0
  78. rucio/core/lifetime_exception.py +377 -0
  79. rucio/core/lock.py +576 -0
  80. rucio/core/message.py +282 -0
  81. rucio/core/meta_conventions.py +203 -0
  82. rucio/core/monitor.py +447 -0
  83. rucio/core/naming_convention.py +195 -0
  84. rucio/core/nongrid_trace.py +136 -0
  85. rucio/core/oidc.py +1461 -0
  86. rucio/core/permission/__init__.py +119 -0
  87. rucio/core/permission/atlas.py +1348 -0
  88. rucio/core/permission/belleii.py +1077 -0
  89. rucio/core/permission/escape.py +1078 -0
  90. rucio/core/permission/generic.py +1130 -0
  91. rucio/core/permission/generic_multi_vo.py +1150 -0
  92. rucio/core/quarantined_replica.py +223 -0
  93. rucio/core/replica.py +4158 -0
  94. rucio/core/replica_sorter.py +366 -0
  95. rucio/core/request.py +3089 -0
  96. rucio/core/rse.py +1875 -0
  97. rucio/core/rse_counter.py +186 -0
  98. rucio/core/rse_expression_parser.py +459 -0
  99. rucio/core/rse_selector.py +302 -0
  100. rucio/core/rule.py +4483 -0
  101. rucio/core/rule_grouping.py +1618 -0
  102. rucio/core/scope.py +180 -0
  103. rucio/core/subscription.py +364 -0
  104. rucio/core/topology.py +490 -0
  105. rucio/core/trace.py +375 -0
  106. rucio/core/transfer.py +1517 -0
  107. rucio/core/vo.py +169 -0
  108. rucio/core/volatile_replica.py +150 -0
  109. rucio/daemons/__init__.py +13 -0
  110. rucio/daemons/abacus/__init__.py +13 -0
  111. rucio/daemons/abacus/account.py +116 -0
  112. rucio/daemons/abacus/collection_replica.py +124 -0
  113. rucio/daemons/abacus/rse.py +117 -0
  114. rucio/daemons/atropos/__init__.py +13 -0
  115. rucio/daemons/atropos/atropos.py +242 -0
  116. rucio/daemons/auditor/__init__.py +289 -0
  117. rucio/daemons/auditor/hdfs.py +97 -0
  118. rucio/daemons/auditor/srmdumps.py +355 -0
  119. rucio/daemons/automatix/__init__.py +13 -0
  120. rucio/daemons/automatix/automatix.py +293 -0
  121. rucio/daemons/badreplicas/__init__.py +13 -0
  122. rucio/daemons/badreplicas/minos.py +322 -0
  123. rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
  124. rucio/daemons/badreplicas/necromancer.py +196 -0
  125. rucio/daemons/bb8/__init__.py +13 -0
  126. rucio/daemons/bb8/bb8.py +353 -0
  127. rucio/daemons/bb8/common.py +759 -0
  128. rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
  129. rucio/daemons/bb8/t2_background_rebalance.py +153 -0
  130. rucio/daemons/c3po/__init__.py +13 -0
  131. rucio/daemons/c3po/algorithms/__init__.py +13 -0
  132. rucio/daemons/c3po/algorithms/simple.py +134 -0
  133. rucio/daemons/c3po/algorithms/t2_free_space.py +128 -0
  134. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +130 -0
  135. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +294 -0
  136. rucio/daemons/c3po/c3po.py +371 -0
  137. rucio/daemons/c3po/collectors/__init__.py +13 -0
  138. rucio/daemons/c3po/collectors/agis.py +108 -0
  139. rucio/daemons/c3po/collectors/free_space.py +81 -0
  140. rucio/daemons/c3po/collectors/jedi_did.py +57 -0
  141. rucio/daemons/c3po/collectors/mock_did.py +51 -0
  142. rucio/daemons/c3po/collectors/network_metrics.py +71 -0
  143. rucio/daemons/c3po/collectors/workload.py +112 -0
  144. rucio/daemons/c3po/utils/__init__.py +13 -0
  145. rucio/daemons/c3po/utils/dataset_cache.py +50 -0
  146. rucio/daemons/c3po/utils/expiring_dataset_cache.py +56 -0
  147. rucio/daemons/c3po/utils/expiring_list.py +62 -0
  148. rucio/daemons/c3po/utils/popularity.py +85 -0
  149. rucio/daemons/c3po/utils/timeseries.py +89 -0
  150. rucio/daemons/cache/__init__.py +13 -0
  151. rucio/daemons/cache/consumer.py +197 -0
  152. rucio/daemons/common.py +415 -0
  153. rucio/daemons/conveyor/__init__.py +13 -0
  154. rucio/daemons/conveyor/common.py +562 -0
  155. rucio/daemons/conveyor/finisher.py +529 -0
  156. rucio/daemons/conveyor/poller.py +404 -0
  157. rucio/daemons/conveyor/preparer.py +205 -0
  158. rucio/daemons/conveyor/receiver.py +249 -0
  159. rucio/daemons/conveyor/stager.py +132 -0
  160. rucio/daemons/conveyor/submitter.py +403 -0
  161. rucio/daemons/conveyor/throttler.py +532 -0
  162. rucio/daemons/follower/__init__.py +13 -0
  163. rucio/daemons/follower/follower.py +101 -0
  164. rucio/daemons/hermes/__init__.py +13 -0
  165. rucio/daemons/hermes/hermes.py +774 -0
  166. rucio/daemons/judge/__init__.py +13 -0
  167. rucio/daemons/judge/cleaner.py +159 -0
  168. rucio/daemons/judge/evaluator.py +185 -0
  169. rucio/daemons/judge/injector.py +162 -0
  170. rucio/daemons/judge/repairer.py +154 -0
  171. rucio/daemons/oauthmanager/__init__.py +13 -0
  172. rucio/daemons/oauthmanager/oauthmanager.py +198 -0
  173. rucio/daemons/reaper/__init__.py +13 -0
  174. rucio/daemons/reaper/dark_reaper.py +278 -0
  175. rucio/daemons/reaper/reaper.py +743 -0
  176. rucio/daemons/replicarecoverer/__init__.py +13 -0
  177. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
  178. rucio/daemons/rsedecommissioner/__init__.py +13 -0
  179. rucio/daemons/rsedecommissioner/config.py +81 -0
  180. rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
  181. rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
  182. rucio/daemons/rsedecommissioner/profiles/generic.py +451 -0
  183. rucio/daemons/rsedecommissioner/profiles/types.py +92 -0
  184. rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
  185. rucio/daemons/storage/__init__.py +13 -0
  186. rucio/daemons/storage/consistency/__init__.py +13 -0
  187. rucio/daemons/storage/consistency/actions.py +846 -0
  188. rucio/daemons/tracer/__init__.py +13 -0
  189. rucio/daemons/tracer/kronos.py +536 -0
  190. rucio/daemons/transmogrifier/__init__.py +13 -0
  191. rucio/daemons/transmogrifier/transmogrifier.py +762 -0
  192. rucio/daemons/undertaker/__init__.py +13 -0
  193. rucio/daemons/undertaker/undertaker.py +137 -0
  194. rucio/db/__init__.py +13 -0
  195. rucio/db/sqla/__init__.py +52 -0
  196. rucio/db/sqla/constants.py +201 -0
  197. rucio/db/sqla/migrate_repo/__init__.py +13 -0
  198. rucio/db/sqla/migrate_repo/env.py +110 -0
  199. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
  200. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
  201. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
  202. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
  203. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
  204. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
  205. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
  206. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
  207. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
  208. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
  209. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
  210. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
  211. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
  212. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
  213. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
  214. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
  215. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
  216. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
  217. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
  218. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
  219. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
  220. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
  221. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
  222. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
  223. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
  224. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
  225. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
  226. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
  227. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
  228. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
  229. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
  230. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
  231. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
  232. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
  233. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
  234. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
  235. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
  236. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
  237. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
  238. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
  239. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
  240. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
  241. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
  242. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
  243. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
  244. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
  245. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
  246. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
  247. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
  248. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
  249. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
  250. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
  251. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
  252. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
  253. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
  254. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
  255. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
  256. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
  257. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
  258. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
  259. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
  260. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
  261. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
  262. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
  263. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
  264. rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
  265. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
  266. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
  267. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
  268. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
  269. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
  270. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
  271. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
  272. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
  273. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
  274. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
  275. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
  276. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
  277. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
  278. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
  279. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
  280. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
  281. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
  282. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
  283. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
  284. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
  285. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
  286. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
  287. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
  288. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
  289. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
  290. rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
  291. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
  292. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
  293. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
  294. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
  295. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
  296. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
  297. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
  298. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
  299. rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
  300. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
  301. rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
  302. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
  303. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
  304. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
  305. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
  306. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
  307. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
  308. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
  309. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
  310. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
  311. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
  312. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
  313. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
  314. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
  315. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
  316. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
  317. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
  318. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
  319. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
  320. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
  321. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
  322. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
  323. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
  324. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
  325. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
  326. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
  327. rucio/db/sqla/models.py +1740 -0
  328. rucio/db/sqla/sautils.py +55 -0
  329. rucio/db/sqla/session.py +498 -0
  330. rucio/db/sqla/types.py +206 -0
  331. rucio/db/sqla/util.py +543 -0
  332. rucio/gateway/__init__.py +13 -0
  333. rucio/gateway/account.py +339 -0
  334. rucio/gateway/account_limit.py +286 -0
  335. rucio/gateway/authentication.py +375 -0
  336. rucio/gateway/config.py +217 -0
  337. rucio/gateway/credential.py +71 -0
  338. rucio/gateway/did.py +970 -0
  339. rucio/gateway/dirac.py +81 -0
  340. rucio/gateway/exporter.py +59 -0
  341. rucio/gateway/heartbeat.py +74 -0
  342. rucio/gateway/identity.py +204 -0
  343. rucio/gateway/importer.py +45 -0
  344. rucio/gateway/lifetime_exception.py +120 -0
  345. rucio/gateway/lock.py +153 -0
  346. rucio/gateway/meta_conventions.py +87 -0
  347. rucio/gateway/permission.py +71 -0
  348. rucio/gateway/quarantined_replica.py +78 -0
  349. rucio/gateway/replica.py +529 -0
  350. rucio/gateway/request.py +321 -0
  351. rucio/gateway/rse.py +600 -0
  352. rucio/gateway/rule.py +417 -0
  353. rucio/gateway/scope.py +99 -0
  354. rucio/gateway/subscription.py +277 -0
  355. rucio/gateway/vo.py +122 -0
  356. rucio/rse/__init__.py +96 -0
  357. rucio/rse/protocols/__init__.py +13 -0
  358. rucio/rse/protocols/bittorrent.py +184 -0
  359. rucio/rse/protocols/cache.py +122 -0
  360. rucio/rse/protocols/dummy.py +111 -0
  361. rucio/rse/protocols/gfal.py +703 -0
  362. rucio/rse/protocols/globus.py +243 -0
  363. rucio/rse/protocols/gsiftp.py +92 -0
  364. rucio/rse/protocols/http_cache.py +82 -0
  365. rucio/rse/protocols/mock.py +123 -0
  366. rucio/rse/protocols/ngarc.py +209 -0
  367. rucio/rse/protocols/posix.py +250 -0
  368. rucio/rse/protocols/protocol.py +594 -0
  369. rucio/rse/protocols/rclone.py +364 -0
  370. rucio/rse/protocols/rfio.py +136 -0
  371. rucio/rse/protocols/srm.py +338 -0
  372. rucio/rse/protocols/ssh.py +413 -0
  373. rucio/rse/protocols/storm.py +206 -0
  374. rucio/rse/protocols/webdav.py +550 -0
  375. rucio/rse/protocols/xrootd.py +301 -0
  376. rucio/rse/rsemanager.py +764 -0
  377. rucio/tests/__init__.py +13 -0
  378. rucio/tests/common.py +270 -0
  379. rucio/tests/common_server.py +132 -0
  380. rucio/transfertool/__init__.py +13 -0
  381. rucio/transfertool/bittorrent.py +199 -0
  382. rucio/transfertool/bittorrent_driver.py +52 -0
  383. rucio/transfertool/bittorrent_driver_qbittorrent.py +133 -0
  384. rucio/transfertool/fts3.py +1596 -0
  385. rucio/transfertool/fts3_plugins.py +152 -0
  386. rucio/transfertool/globus.py +201 -0
  387. rucio/transfertool/globus_library.py +181 -0
  388. rucio/transfertool/mock.py +90 -0
  389. rucio/transfertool/transfertool.py +221 -0
  390. rucio/vcsversion.py +11 -0
  391. rucio/version.py +38 -0
  392. rucio/web/__init__.py +13 -0
  393. rucio/web/rest/__init__.py +13 -0
  394. rucio/web/rest/flaskapi/__init__.py +13 -0
  395. rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
  396. rucio/web/rest/flaskapi/v1/__init__.py +13 -0
  397. rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
  398. rucio/web/rest/flaskapi/v1/accounts.py +1089 -0
  399. rucio/web/rest/flaskapi/v1/archives.py +102 -0
  400. rucio/web/rest/flaskapi/v1/auth.py +1644 -0
  401. rucio/web/rest/flaskapi/v1/common.py +426 -0
  402. rucio/web/rest/flaskapi/v1/config.py +304 -0
  403. rucio/web/rest/flaskapi/v1/credentials.py +212 -0
  404. rucio/web/rest/flaskapi/v1/dids.py +2334 -0
  405. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  406. rucio/web/rest/flaskapi/v1/export.py +75 -0
  407. rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
  408. rucio/web/rest/flaskapi/v1/identities.py +261 -0
  409. rucio/web/rest/flaskapi/v1/import.py +132 -0
  410. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
  411. rucio/web/rest/flaskapi/v1/locks.py +358 -0
  412. rucio/web/rest/flaskapi/v1/main.py +91 -0
  413. rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
  414. rucio/web/rest/flaskapi/v1/metrics.py +36 -0
  415. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  416. rucio/web/rest/flaskapi/v1/ping.py +88 -0
  417. rucio/web/rest/flaskapi/v1/redirect.py +365 -0
  418. rucio/web/rest/flaskapi/v1/replicas.py +1890 -0
  419. rucio/web/rest/flaskapi/v1/requests.py +998 -0
  420. rucio/web/rest/flaskapi/v1/rses.py +2239 -0
  421. rucio/web/rest/flaskapi/v1/rules.py +854 -0
  422. rucio/web/rest/flaskapi/v1/scopes.py +159 -0
  423. rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
  424. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  425. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  426. rucio/web/rest/flaskapi/v1/traces.py +100 -0
  427. rucio/web/rest/flaskapi/v1/types.py +20 -0
  428. rucio/web/rest/flaskapi/v1/vos.py +278 -0
  429. rucio/web/rest/main.py +18 -0
  430. rucio/web/rest/metrics.py +27 -0
  431. rucio/web/rest/ping.py +27 -0
  432. rucio-35.7.0.data/data/rucio/etc/alembic.ini.template +71 -0
  433. rucio-35.7.0.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  434. rucio-35.7.0.data/data/rucio/etc/globus-config.yml.template +5 -0
  435. rucio-35.7.0.data/data/rucio/etc/ldap.cfg.template +30 -0
  436. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  437. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  438. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  439. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  440. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  441. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  442. rucio-35.7.0.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  443. rucio-35.7.0.data/data/rucio/etc/rucio.cfg.atlas.client.template +42 -0
  444. rucio-35.7.0.data/data/rucio/etc/rucio.cfg.template +257 -0
  445. rucio-35.7.0.data/data/rucio/etc/rucio_multi_vo.cfg.template +234 -0
  446. rucio-35.7.0.data/data/rucio/requirements.server.txt +268 -0
  447. rucio-35.7.0.data/data/rucio/tools/bootstrap.py +34 -0
  448. rucio-35.7.0.data/data/rucio/tools/merge_rucio_configs.py +144 -0
  449. rucio-35.7.0.data/data/rucio/tools/reset_database.py +40 -0
  450. rucio-35.7.0.data/scripts/rucio +2542 -0
  451. rucio-35.7.0.data/scripts/rucio-abacus-account +74 -0
  452. rucio-35.7.0.data/scripts/rucio-abacus-collection-replica +46 -0
  453. rucio-35.7.0.data/scripts/rucio-abacus-rse +78 -0
  454. rucio-35.7.0.data/scripts/rucio-admin +2447 -0
  455. rucio-35.7.0.data/scripts/rucio-atropos +60 -0
  456. rucio-35.7.0.data/scripts/rucio-auditor +205 -0
  457. rucio-35.7.0.data/scripts/rucio-automatix +50 -0
  458. rucio-35.7.0.data/scripts/rucio-bb8 +57 -0
  459. rucio-35.7.0.data/scripts/rucio-c3po +85 -0
  460. rucio-35.7.0.data/scripts/rucio-cache-client +134 -0
  461. rucio-35.7.0.data/scripts/rucio-cache-consumer +42 -0
  462. rucio-35.7.0.data/scripts/rucio-conveyor-finisher +58 -0
  463. rucio-35.7.0.data/scripts/rucio-conveyor-poller +66 -0
  464. rucio-35.7.0.data/scripts/rucio-conveyor-preparer +37 -0
  465. rucio-35.7.0.data/scripts/rucio-conveyor-receiver +43 -0
  466. rucio-35.7.0.data/scripts/rucio-conveyor-stager +76 -0
  467. rucio-35.7.0.data/scripts/rucio-conveyor-submitter +139 -0
  468. rucio-35.7.0.data/scripts/rucio-conveyor-throttler +104 -0
  469. rucio-35.7.0.data/scripts/rucio-dark-reaper +53 -0
  470. rucio-35.7.0.data/scripts/rucio-dumper +160 -0
  471. rucio-35.7.0.data/scripts/rucio-follower +44 -0
  472. rucio-35.7.0.data/scripts/rucio-hermes +54 -0
  473. rucio-35.7.0.data/scripts/rucio-judge-cleaner +89 -0
  474. rucio-35.7.0.data/scripts/rucio-judge-evaluator +137 -0
  475. rucio-35.7.0.data/scripts/rucio-judge-injector +44 -0
  476. rucio-35.7.0.data/scripts/rucio-judge-repairer +44 -0
  477. rucio-35.7.0.data/scripts/rucio-kronos +43 -0
  478. rucio-35.7.0.data/scripts/rucio-minos +53 -0
  479. rucio-35.7.0.data/scripts/rucio-minos-temporary-expiration +50 -0
  480. rucio-35.7.0.data/scripts/rucio-necromancer +120 -0
  481. rucio-35.7.0.data/scripts/rucio-oauth-manager +63 -0
  482. rucio-35.7.0.data/scripts/rucio-reaper +83 -0
  483. rucio-35.7.0.data/scripts/rucio-replica-recoverer +248 -0
  484. rucio-35.7.0.data/scripts/rucio-rse-decommissioner +66 -0
  485. rucio-35.7.0.data/scripts/rucio-storage-consistency-actions +74 -0
  486. rucio-35.7.0.data/scripts/rucio-transmogrifier +77 -0
  487. rucio-35.7.0.data/scripts/rucio-undertaker +76 -0
  488. rucio-35.7.0.dist-info/METADATA +72 -0
  489. rucio-35.7.0.dist-info/RECORD +493 -0
  490. rucio-35.7.0.dist-info/WHEEL +5 -0
  491. rucio-35.7.0.dist-info/licenses/AUTHORS.rst +97 -0
  492. rucio-35.7.0.dist-info/licenses/LICENSE +201 -0
  493. rucio-35.7.0.dist-info/top_level.txt +1 -0
rucio/core/config.py ADDED
@@ -0,0 +1,456 @@
1
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from collections.abc import Callable
16
+ from typing import TYPE_CHECKING, Any, Optional, TypeVar
17
+
18
+ from dogpile.cache.api import NoValue
19
+ from sqlalchemy import and_, delete, func, select, update
20
+
21
+ from rucio.common.cache import make_region_memcached
22
+ from rucio.common.exception import ConfigNotFound
23
+ from rucio.db.sqla import models
24
+ from rucio.db.sqla.session import read_session, transactional_session
25
+
26
+ T = TypeVar('T')
27
+
28
+ if TYPE_CHECKING:
29
+ from sqlalchemy.orm import Session
30
+
31
+
32
+ REGION = make_region_memcached(expiration_time=900)
33
+
34
+ SECTIONS_CACHE_KEY = 'sections'
35
+
36
+
37
+ def _has_section_cache_key(section: str) -> str:
38
+ return 'has_section_%s' % section
39
+
40
+
41
+ def _options_cache_key(section: str) -> str:
42
+ return 'options_%s' % section
43
+
44
+
45
+ def _has_option_cache_key(section: str, option: str) -> str:
46
+ return 'has_option_%s_%s' % (section, option)
47
+
48
+
49
+ def _items_cache_key(section: str) -> str:
50
+ return 'items_%s' % section
51
+
52
+
53
+ def _value_cache_key(section: str, option: str) -> str:
54
+ return 'get_%s_%s' % (section, option)
55
+
56
+
57
+ @read_session
58
+ def sections(
59
+ *,
60
+ use_cache: bool = True,
61
+ expiration_time: int = 900,
62
+ session: "Session"
63
+ ) -> list[str]:
64
+ """
65
+ Return a list of the sections available.
66
+
67
+ :param use_cache: Boolean if the cache should be used.
68
+ :param expiration_time: Time after that the cached value gets ignored.
69
+ :param session: The database session in use.
70
+ :returns: ['section_name', ...]
71
+ """
72
+
73
+ all_sections = NoValue()
74
+ if use_cache:
75
+ all_sections = read_from_cache(SECTIONS_CACHE_KEY, expiration_time)
76
+ if isinstance(all_sections, NoValue):
77
+ stmt = select(
78
+ models.Config.section
79
+ ).distinct(
80
+ )
81
+ all_sections = list(session.execute(stmt).scalars().all())
82
+ write_to_cache(SECTIONS_CACHE_KEY, all_sections)
83
+
84
+ return all_sections
85
+
86
+
87
+ @transactional_session
88
+ def add_section(section: str, *, session: "Session") -> None:
89
+ """
90
+ Add a section to the configuration.
91
+ :param session: The database session in use.
92
+ :param section: The name of the section.
93
+ """
94
+
95
+ raise NotImplementedError('Irrelevant - sections cannot exist without options')
96
+
97
+
98
+ @read_session
99
+ def has_section(
100
+ section: str,
101
+ *,
102
+ use_cache: bool = True,
103
+ expiration_time: int = 900,
104
+ session: "Session"
105
+ ) -> bool:
106
+ """
107
+ Indicates whether the named section is present in the configuration.
108
+
109
+ :param section: The name of the section.
110
+ :param use_cache: Boolean if the cache should be used.
111
+ :param expiration_time: Time after that the cached value gets ignored.
112
+ :param session: The database session in use.
113
+ :returns: True/False
114
+ """
115
+ has_section_key = 'has_section_%s' % section
116
+ has_section = NoValue()
117
+ if use_cache:
118
+ has_section = read_from_cache(has_section_key, expiration_time)
119
+ if isinstance(has_section, NoValue):
120
+ stmt = select(
121
+ models.Config
122
+ ).where(
123
+ models.Config.section == section
124
+ )
125
+ has_section = session.execute(stmt).first() is not None
126
+ write_to_cache(has_section_key, has_section)
127
+ return has_section
128
+
129
+
130
+ @read_session
131
+ def options(
132
+ section: str,
133
+ *,
134
+ use_cache: bool = True,
135
+ expiration_time: int = 900,
136
+ session: "Session"
137
+ ) -> list[str]:
138
+ """
139
+ Returns a list of options available in the specified section.
140
+
141
+ :param section: The name of the section.
142
+ :param use_cache: Boolean if the cache should be used.
143
+ :param expiration_time: Time after that the cached value gets ignored.
144
+ :param session: The database session in use.
145
+ :returns: ['option', ...]
146
+ """
147
+ options_key = _options_cache_key(section)
148
+ options = NoValue()
149
+ if use_cache:
150
+ options = read_from_cache(options_key, expiration_time)
151
+ if isinstance(options, NoValue):
152
+ stmt = select(
153
+ models.Config.opt
154
+ ).where(
155
+ models.Config.section == section
156
+ ).distinct()
157
+ options = list(session.execute(stmt).scalars().all())
158
+ write_to_cache(options_key, options)
159
+ return options
160
+
161
+
162
+ @read_session
163
+ def has_option(
164
+ section: str,
165
+ option: str,
166
+ *,
167
+ use_cache: bool = True,
168
+ expiration_time: int = 900,
169
+ session: "Session"
170
+ ) -> bool:
171
+ """
172
+ Check if the given section exists and contains the given option.
173
+
174
+ :param section: The name of the section.
175
+ :param option: The name of the option.
176
+ :param use_cache: Boolean if the cache should be used.
177
+ :param expiration_time: Time after that the cached value gets ignored.
178
+ :param session: The database session in use.
179
+ :returns: True/False
180
+ """
181
+ has_option_key = _has_option_cache_key(section, option)
182
+ has_option = NoValue()
183
+ if use_cache:
184
+ has_option = read_from_cache(has_option_key, expiration_time)
185
+ if isinstance(has_option, NoValue):
186
+ stmt = select(
187
+ models.Config
188
+ ).where(
189
+ and_(models.Config.section == section,
190
+ models.Config.opt == option)
191
+ )
192
+ has_option = session.execute(stmt).first() is not None
193
+ write_to_cache(has_option_key, has_option)
194
+ return has_option
195
+
196
+
197
+ @read_session
198
+ def get(
199
+ section: str,
200
+ option: str,
201
+ *,
202
+ default: Optional[T] = None,
203
+ use_cache: bool = True,
204
+ expiration_time: int = 900,
205
+ convert_type_fnc: Callable[[str], T],
206
+ session: "Session"
207
+ ) -> T:
208
+ """
209
+ Get an option value for the named section. Value can be auto-coerced to string, int, float, bool, None.
210
+
211
+ Caveat emptor: Strings, regardless the case, matching 'on'/off', 'true'/'false', 'yes'/'no' are converted to bool.
212
+ 0/1 are converted to int, and not to bool.
213
+
214
+ :param section: The name of the section.
215
+ :param option: The name of the option.
216
+ :param default: The default value if no value is found.
217
+ :param use_cache: Boolean if the cache should be used.
218
+ :param expiration_time: Time after that the cached value gets ignored.
219
+ :param convert_type_fnc: A function used to parse the string config value into the desired destination type
220
+ :param session: The database session in use.
221
+ :returns: The auto-coerced value.
222
+ """
223
+ value_key = _value_cache_key(section, option)
224
+ value = NoValue()
225
+ if use_cache:
226
+ value = read_from_cache(value_key, expiration_time)
227
+ if isinstance(value, NoValue):
228
+ stmt = select(
229
+ models.Config.value
230
+ ).where(
231
+ and_(models.Config.section == section,
232
+ models.Config.opt == option)
233
+ )
234
+ tmp = session.execute(stmt).first()
235
+ if tmp is not None:
236
+ value = convert_type_fnc(tmp[0])
237
+ write_to_cache(value_key, tmp[0])
238
+ elif default is None:
239
+ raise ConfigNotFound
240
+ else:
241
+ value = default
242
+ write_to_cache(value_key, value) # Also write default to cache
243
+ else:
244
+ value = convert_type_fnc(value)
245
+ return value
246
+
247
+
248
+ @read_session
249
+ def items(
250
+ section: str,
251
+ use_cache: bool = True,
252
+ expiration_time: int = 900,
253
+ *,
254
+ convert_type_fnc: Callable[[str], T],
255
+ session: "Session"
256
+ ) -> list[tuple[str, T]]:
257
+ """
258
+ Return a list of (option, value) pairs for each option in the given section. Values are auto-coerced as in get().
259
+
260
+ :param section: The name of the section.
261
+ :param use_cache: Boolean if the cache should be used.
262
+ :param expiration_time: Time after that the cached value gets ignored.
263
+ :param convert_type_fnc: A function used to parse the string config value into the desired destination type
264
+ :param session: The database session in use.
265
+ :returns: [('option', auto-coerced value), ...]
266
+ """
267
+ items_key = _items_cache_key(section)
268
+ items = NoValue()
269
+ if use_cache:
270
+ items = read_from_cache(items_key, expiration_time)
271
+ if isinstance(items, NoValue):
272
+ stmt = select(
273
+ models.Config.opt,
274
+ models.Config.value
275
+ ).where(
276
+ models.Config.section == section
277
+ )
278
+ items = session.execute(stmt).all()
279
+ write_to_cache(items_key, items)
280
+ return [(opt, convert_type_fnc(val)) for opt, val in items]
281
+
282
+
283
+ @transactional_session
284
+ def set(
285
+ section: str,
286
+ option: str,
287
+ value: Any,
288
+ *,
289
+ session: "Session"
290
+ ) -> None:
291
+ """
292
+ Set the given option to the specified value. If the option doesn't exist, it is created.
293
+
294
+ :param section: The name of the section.
295
+ :param option: The name of the option.
296
+ :param value: The content of the value.
297
+ :param session: The database session in use.
298
+ """
299
+
300
+ if not has_option(section=section, option=option, use_cache=False, session=session):
301
+ section_existed = has_section(section=section)
302
+
303
+ new_option = models.Config(section=section, opt=option, value=value)
304
+ new_option.save(session=session)
305
+
306
+ delete_from_cache(key=_value_cache_key(section, option))
307
+ delete_from_cache(key=_has_option_cache_key(section, option))
308
+ delete_from_cache(key=_items_cache_key(section))
309
+ if not section_existed:
310
+ delete_from_cache(key=SECTIONS_CACHE_KEY)
311
+ delete_from_cache(key=_has_section_cache_key(section))
312
+ else:
313
+ stmt = select(
314
+ models.Config.value
315
+ ).where(
316
+ and_(models.Config.section == section,
317
+ models.Config.opt == option)
318
+ )
319
+ old_value = session.execute(stmt).scalar_one_or_none()
320
+ if old_value != str(value):
321
+ old_option = models.ConfigHistory(section=section,
322
+ opt=option,
323
+ value=old_value)
324
+ old_option.save(session=session)
325
+ stmt = update(
326
+ models.Config
327
+ ).where(
328
+ and_(models.Config.section == section,
329
+ models.Config.opt == option)
330
+ ).values({
331
+ models.Config.value: str(value)
332
+ })
333
+ session.execute(stmt)
334
+ delete_from_cache(key=_value_cache_key(section, option))
335
+ delete_from_cache(key=_items_cache_key(section))
336
+
337
+
338
+ @transactional_session
339
+ def remove_section(section: str, *, session: "Session") -> bool:
340
+ """
341
+ Remove the specified section from the specified section.
342
+
343
+ :param section: The name of the section.
344
+ :param session: The database session in use.
345
+ :returns: True/False.
346
+ """
347
+
348
+ if not has_section(section=section, session=session):
349
+ return False
350
+ else:
351
+ stmt = select(
352
+ models.Config.value
353
+ ).where(
354
+ models.Config.section == section
355
+ )
356
+ for old in session.execute(stmt).all():
357
+ old_option = models.ConfigHistory(section=old[0],
358
+ opt=old[1],
359
+ value=old[2])
360
+ old_option.save(session=session)
361
+ delete_from_cache(key=_has_option_cache_key(old[0], old[1]))
362
+ delete_from_cache(key=_value_cache_key(old[0], old[1]))
363
+
364
+ stmt = delete(
365
+ models.Config
366
+ ).where(
367
+ models.Config.section == section
368
+ )
369
+ session.execute(stmt)
370
+ delete_from_cache(key=SECTIONS_CACHE_KEY)
371
+ delete_from_cache(key=_items_cache_key(section))
372
+ return True
373
+
374
+
375
+ @transactional_session
376
+ def remove_option(section: str, option: str, *, session: "Session") -> bool:
377
+ """
378
+ Remove the specified option from the configuration.
379
+
380
+ :param section: The name of the section.
381
+ :param option: The name of the option.
382
+ :param session: The database session in use.
383
+ :returns: True/False
384
+ """
385
+
386
+ if not has_option(section=section, option=option, session=session, use_cache=False):
387
+ return False
388
+ else:
389
+ stmt = select(
390
+ models.Config.value
391
+ ).where(
392
+ and_(models.Config.section == section,
393
+ models.Config.opt == option)
394
+ )
395
+ result = session.execute(stmt).scalar_one_or_none()
396
+ old_option = models.ConfigHistory(section=section,
397
+ opt=option,
398
+ value=result)
399
+ old_option.save(session=session)
400
+
401
+ stmt = delete(
402
+ models.Config
403
+ ).where(
404
+ and_(models.Config.section == section,
405
+ models.Config.opt == option)
406
+ )
407
+ session.execute(stmt)
408
+
409
+ stmt = select(
410
+ func.count()
411
+ ).select_from(
412
+ models.Config
413
+ ).where(
414
+ models.Config.section == section
415
+ )
416
+ if not session.execute(stmt).scalar_one_or_none():
417
+ # we deleted the last config entry in the section. Invalidate the section cache
418
+ delete_from_cache(key=SECTIONS_CACHE_KEY)
419
+ delete_from_cache(key=_has_section_cache_key(section))
420
+ delete_from_cache(key=_items_cache_key(section))
421
+ delete_from_cache(key=_has_option_cache_key(section, option))
422
+ delete_from_cache(key=_value_cache_key(section, option))
423
+ return True
424
+
425
+
426
+ def read_from_cache(key: str, expiration_time: int = 900) -> Any:
427
+ """
428
+ Try to read a value from a cache.
429
+
430
+ :param key: Key that stores the value.
431
+ :param expiration_time: Time in seconds that a value should not be older than.
432
+ """
433
+ key = key.replace(' ', '')
434
+ value = REGION.get(key, expiration_time=expiration_time)
435
+ return value
436
+
437
+
438
+ def write_to_cache(key: str, value: Any) -> None:
439
+ """
440
+ Set a value on a key in a cache.
441
+
442
+ :param key: Key that stores the value.
443
+ :param value: Value to be stored.
444
+ """
445
+ key = key.replace(' ', '')
446
+ REGION.set(key, value)
447
+
448
+
449
+ def delete_from_cache(key: str) -> None:
450
+ """
451
+ Delete from cache any data stored for the given key
452
+
453
+ :param key: Key that stores the value.
454
+ """
455
+ key = key.replace(' ', '')
456
+ REGION.delete(key)
@@ -0,0 +1,225 @@
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 base64
16
+ import datetime
17
+ import hmac
18
+ import time
19
+ from hashlib import sha1
20
+ from typing import Literal
21
+ from urllib.parse import urlencode, urlparse
22
+
23
+ import boto3
24
+ from botocore.client import Config
25
+ from dogpile.cache.api import NO_VALUE
26
+ from google.oauth2.service_account import Credentials
27
+
28
+ from rucio.common.cache import make_region_memcached
29
+ from rucio.common.config import config_get, get_rse_credentials
30
+ from rucio.common.constants import RseAttr
31
+ from rucio.common.exception import UnsupportedOperation
32
+ from rucio.core.monitor import MetricManager
33
+ from rucio.core.rse import get_rse_attribute
34
+
35
+ CREDS_GCS = None
36
+
37
+ REGION = make_region_memcached(expiration_time=900)
38
+ METRICS = MetricManager(module=__name__)
39
+
40
+
41
+ def get_signed_url(
42
+ rse_id: str,
43
+ service: Literal['gsc', 's3', 'swift'],
44
+ operation: Literal['read', 'write', 'delete'],
45
+ url: str,
46
+ lifetime: int = 600
47
+ ) -> str:
48
+ """
49
+ Get a signed URL for a particular service and operation.
50
+
51
+ The signed URL will be valid for 1 hour but can be overridden.
52
+
53
+ :param rse_id: The ID of the RSE that the URL points to.
54
+ :param service: The service to authorise, either 'gcs', 's3' or 'swift'.
55
+ :param operation: The operation to sign, either 'read', 'write', or 'delete'.
56
+ :param url: The URL to sign.
57
+ :param lifetime: Lifetime of the signed URL in seconds.
58
+ :returns: Signed URL as a variable-length string.
59
+ """
60
+
61
+ global CREDS_GCS
62
+
63
+ if service not in ['gcs', 's3', 'swift']:
64
+ raise UnsupportedOperation('Service must be "gcs", "s3" or "swift"')
65
+
66
+ if operation not in ['read', 'write', 'delete']:
67
+ raise UnsupportedOperation('Operation must be "read", "write", or "delete"')
68
+
69
+ if url is None or url == '':
70
+ raise UnsupportedOperation('URL must not be empty')
71
+
72
+ if lifetime:
73
+ if not isinstance(lifetime, int):
74
+ try:
75
+ lifetime = int(lifetime)
76
+ except:
77
+ raise UnsupportedOperation('Lifetime must be convertible to numeric.')
78
+
79
+ if service == 'gcs':
80
+ if not CREDS_GCS:
81
+ CREDS_GCS = Credentials.from_service_account_file(config_get('credentials', 'gcs',
82
+ raise_exception=False,
83
+ default='/opt/rucio/etc/google-cloud-storage-test.json'))
84
+ components = urlparse(url)
85
+ host = components.netloc
86
+
87
+ # select the correct operation
88
+ operations = {'read': 'GET', 'write': 'PUT', 'delete': 'DELETE'}
89
+ operation = operations[operation]
90
+
91
+ # special case to test signature, force epoch time
92
+ if lifetime is None:
93
+ lifetime = 0
94
+ else:
95
+ # GCS is timezone-sensitive, don't use UTC
96
+ # has to be converted to Unixtime
97
+ lifetime_datetime = datetime.datetime.now() + datetime.timedelta(seconds=lifetime)
98
+ lifetime = int(time.mktime(lifetime_datetime.timetuple()))
99
+
100
+ # sign the path only
101
+ path = components.path
102
+
103
+ # assemble message to sign
104
+ to_sign = "%s\n\n\n%s\n%s" % (operation, lifetime, path)
105
+
106
+ # create URL-capable signature
107
+ # first character is always a '=', remove it
108
+ signature = urlencode({'': base64.b64encode(CREDS_GCS.sign_bytes(to_sign))})[1:]
109
+
110
+ # assemble final signed URL
111
+ signed_url = (
112
+ f'https://{host}{path}'
113
+ f'?GoogleAccessId={CREDS_GCS.service_account_email}'
114
+ f'&Expires={lifetime}&Signature={signature}'
115
+ )
116
+
117
+ elif service == 's3':
118
+
119
+ # get RSE S3 URL style (path or host)
120
+ # path-style: https://s3.region-code.amazonaws.com/bucket-name/key-name
121
+ # host-style: https://bucket-name.s3.region-code.amazonaws.com/key-name
122
+ s3_url_style = get_rse_attribute(rse_id, RseAttr.S3_URL_STYLE)
123
+
124
+ # no S3 URL style specified, assume path-style
125
+ if s3_url_style is None:
126
+ s3_url_style = "path"
127
+
128
+ # split URL to get hostname, bucket and key
129
+ components = urlparse(url)
130
+ host = components.netloc
131
+ pathcomponents = components.path.split('/')
132
+ if s3_url_style == "path":
133
+ if len(pathcomponents) < 3:
134
+ raise UnsupportedOperation('Not a valid Path-Style S3 URL')
135
+ bucket = pathcomponents[1]
136
+ key = '/'.join(pathcomponents[2:])
137
+ elif s3_url_style == "host":
138
+ hostcomponents = host.split('.')
139
+ bucket = hostcomponents[0]
140
+ if len(pathcomponents) < 2:
141
+ raise UnsupportedOperation('Not a valid Host-Style S3 URL')
142
+ key = '/'.join(pathcomponents[1:])
143
+ else:
144
+ raise UnsupportedOperation('Not a valid RSE S3 URL style (allowed values: path|host)')
145
+
146
+ # remove port number from host if present
147
+ colon = host.find(':')
148
+ port = '443'
149
+ if colon >= 0:
150
+ port = host[colon + 1:]
151
+ host = host[:colon]
152
+
153
+ # look up in RSE account configuration by RSE ID
154
+ cred_name = rse_id
155
+ cred = REGION.get('s3-%s' % cred_name)
156
+ if cred is NO_VALUE:
157
+ rse_cred = get_rse_credentials()
158
+ cred = rse_cred.get(cred_name)
159
+ REGION.set('s3-%s' % cred_name, cred)
160
+ access_key = cred['access_key']
161
+ secret_key = cred['secret_key']
162
+ signature_version = cred['signature_version']
163
+ region_name = cred['region']
164
+
165
+ if operation == 'read':
166
+ s3op = 'get_object'
167
+ elif operation == 'write':
168
+ s3op = 'put_object'
169
+ else:
170
+ s3op = 'delete_object'
171
+
172
+ with METRICS.timer('signs3'):
173
+
174
+ if s3_url_style == "host":
175
+ s3_url_style = "virtual"
176
+
177
+ s3 = boto3.client(service_name='s3',
178
+ endpoint_url=f'https://{host}:{port}',
179
+ aws_access_key_id=access_key,
180
+ aws_secret_access_key=secret_key,
181
+ config=Config(signature_version=signature_version,
182
+ region_name=region_name,
183
+ s3={"addressing_style": s3_url_style}))
184
+
185
+ signed_url: str = s3.generate_presigned_url(
186
+ s3op, Params={'Bucket': bucket, 'Key': key}, ExpiresIn=lifetime)
187
+
188
+ else: # service == 'swift'
189
+ # split URL to get hostname and path
190
+ components = urlparse(url)
191
+ host = components.netloc
192
+
193
+ # remove port number from host if present
194
+ colon = host.find(':')
195
+ if colon >= 0:
196
+ host = host[:colon]
197
+
198
+ # use RSE ID to look up key
199
+ cred_name = rse_id
200
+
201
+ # look up tempurl signing key
202
+ cred = REGION.get('swift-%s' % cred_name)
203
+ if cred is NO_VALUE:
204
+ rse_cred = get_rse_credentials()
205
+ cred = rse_cred.get(cred_name)
206
+ REGION.set('swift-%s' % cred_name, cred)
207
+ tempurl_key = cred['tempurl_key']
208
+
209
+ if operation == 'read':
210
+ swiftop = 'GET'
211
+ elif operation == 'write':
212
+ swiftop = 'PUT'
213
+ else:
214
+ swiftop = 'DELETE'
215
+
216
+ expires = int(time.time() + lifetime)
217
+
218
+ # create signed URL
219
+ with METRICS.timer('signswift'):
220
+ hmac_body = '%s\n%s\n%s' % (swiftop, expires, components.path)
221
+ # Python 3 hmac only accepts bytes or bytearray
222
+ sig = hmac.new(bytearray(tempurl_key, 'utf-8'), bytearray(hmac_body, 'utf-8'), sha1).hexdigest()
223
+ signed_url = f'https://{host}{components.path}?temp_url_sig={sig}&temp_url_expires={expires}'
224
+
225
+ return signed_url