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
rucio/core/config.py ADDED
@@ -0,0 +1,437 @@
1
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import TYPE_CHECKING, Any, Optional, TypeVar
16
+
17
+ from dogpile.cache.api import NoValue
18
+ from sqlalchemy import and_, delete, func, select, update
19
+
20
+ from rucio.common.cache import CacheKey, MemcacheRegion
21
+ from rucio.common.exception import ConfigNotFound
22
+ from rucio.db.sqla import models
23
+ from rucio.db.sqla.session import read_session, transactional_session
24
+
25
+ T = TypeVar('T')
26
+
27
+ if TYPE_CHECKING:
28
+ from collections.abc import Callable
29
+
30
+ from sqlalchemy.orm import Session
31
+
32
+
33
+ REGION = MemcacheRegion(expiration_time=900)
34
+
35
+ SECTIONS_CACHE_KEY = 'sections'
36
+
37
+
38
+ @read_session
39
+ def sections(
40
+ *,
41
+ use_cache: bool = True,
42
+ expiration_time: int = 900,
43
+ session: "Session"
44
+ ) -> list[str]:
45
+ """
46
+ Return a list of the sections available.
47
+
48
+ :param use_cache: Boolean if the cache should be used.
49
+ :param expiration_time: Time after that the cached value gets ignored.
50
+ :param session: The database session in use.
51
+ :returns: ['section_name', ...]
52
+ """
53
+
54
+ all_sections = NoValue()
55
+ if use_cache:
56
+ all_sections = read_from_cache(SECTIONS_CACHE_KEY, expiration_time)
57
+ if isinstance(all_sections, NoValue):
58
+ stmt = select(
59
+ models.Config.section
60
+ ).distinct(
61
+ )
62
+ all_sections = list(session.execute(stmt).scalars().all())
63
+ write_to_cache(SECTIONS_CACHE_KEY, all_sections)
64
+
65
+ return all_sections
66
+
67
+
68
+ @transactional_session
69
+ def add_section(section: str, *, session: "Session") -> None:
70
+ """
71
+ Add a section to the configuration.
72
+ :param session: The database session in use.
73
+ :param section: The name of the section.
74
+ """
75
+
76
+ raise NotImplementedError('Irrelevant - sections cannot exist without options')
77
+
78
+
79
+ @read_session
80
+ def has_section(
81
+ section: str,
82
+ *,
83
+ use_cache: bool = True,
84
+ expiration_time: int = 900,
85
+ session: "Session"
86
+ ) -> bool:
87
+ """
88
+ Indicates whether the named section is present in the configuration.
89
+
90
+ :param section: The name of the section.
91
+ :param use_cache: Boolean if the cache should be used.
92
+ :param expiration_time: Time after that the cached value gets ignored.
93
+ :param session: The database session in use.
94
+ :returns: True/False
95
+ """
96
+ has_section_key = 'has_section_%s' % section
97
+ has_section = NoValue()
98
+ if use_cache:
99
+ has_section = read_from_cache(has_section_key, expiration_time)
100
+ if isinstance(has_section, NoValue):
101
+ stmt = select(
102
+ models.Config
103
+ ).where(
104
+ models.Config.section == section
105
+ )
106
+ has_section = session.execute(stmt).first() is not None
107
+ write_to_cache(has_section_key, has_section)
108
+ return has_section
109
+
110
+
111
+ @read_session
112
+ def options(
113
+ section: str,
114
+ *,
115
+ use_cache: bool = True,
116
+ expiration_time: int = 900,
117
+ session: "Session"
118
+ ) -> list[str]:
119
+ """
120
+ Returns a list of options available in the specified section.
121
+
122
+ :param section: The name of the section.
123
+ :param use_cache: Boolean if the cache should be used.
124
+ :param expiration_time: Time after that the cached value gets ignored.
125
+ :param session: The database session in use.
126
+ :returns: ['option', ...]
127
+ """
128
+ options_key = CacheKey.options(section)
129
+ options = NoValue()
130
+ if use_cache:
131
+ options = read_from_cache(options_key, expiration_time)
132
+ if isinstance(options, NoValue):
133
+ stmt = select(
134
+ models.Config.opt
135
+ ).where(
136
+ models.Config.section == section
137
+ ).distinct()
138
+ options = list(session.execute(stmt).scalars().all())
139
+ write_to_cache(options_key, options)
140
+ return options
141
+
142
+
143
+ @read_session
144
+ def has_option(
145
+ section: str,
146
+ option: str,
147
+ *,
148
+ use_cache: bool = True,
149
+ expiration_time: int = 900,
150
+ session: "Session"
151
+ ) -> bool:
152
+ """
153
+ Check if the given section exists and contains the given option.
154
+
155
+ :param section: The name of the section.
156
+ :param option: The name of the option.
157
+ :param use_cache: Boolean if the cache should be used.
158
+ :param expiration_time: Time after that the cached value gets ignored.
159
+ :param session: The database session in use.
160
+ :returns: True/False
161
+ """
162
+ has_option_key = CacheKey.has_option(section, option)
163
+ has_option = NoValue()
164
+ if use_cache:
165
+ has_option = read_from_cache(has_option_key, expiration_time)
166
+ if isinstance(has_option, NoValue):
167
+ stmt = select(
168
+ models.Config
169
+ ).where(
170
+ and_(models.Config.section == section,
171
+ models.Config.opt == option)
172
+ )
173
+ has_option = session.execute(stmt).first() is not None
174
+ write_to_cache(has_option_key, has_option)
175
+ return has_option
176
+
177
+
178
+ @read_session
179
+ def get(
180
+ section: str,
181
+ option: str,
182
+ *,
183
+ default: Optional[T] = None,
184
+ use_cache: bool = True,
185
+ expiration_time: int = 900,
186
+ convert_type_fnc: 'Callable[[str], T]',
187
+ session: "Session"
188
+ ) -> T:
189
+ """
190
+ Get an option value for the named section. Value can be auto-coerced to string, int, float, bool, None.
191
+
192
+ Caveat emptor: Strings, regardless the case, matching 'on'/off', 'true'/'false', 'yes'/'no' are converted to bool.
193
+ 0/1 are converted to int, and not to bool.
194
+
195
+ :param section: The name of the section.
196
+ :param option: The name of the option.
197
+ :param default: The default value if no value is found.
198
+ :param use_cache: Boolean if the cache should be used.
199
+ :param expiration_time: Time after that the cached value gets ignored.
200
+ :param convert_type_fnc: A function used to parse the string config value into the desired destination type
201
+ :param session: The database session in use.
202
+ :returns: The auto-coerced value.
203
+ """
204
+ value_key = CacheKey.value(section, option)
205
+ value = NoValue()
206
+ if use_cache:
207
+ value = read_from_cache(value_key, expiration_time)
208
+ if isinstance(value, NoValue):
209
+ stmt = select(
210
+ models.Config.value
211
+ ).where(
212
+ and_(models.Config.section == section,
213
+ models.Config.opt == option)
214
+ )
215
+ tmp = session.execute(stmt).first()
216
+ if tmp is not None:
217
+ value = convert_type_fnc(tmp[0])
218
+ write_to_cache(value_key, tmp[0])
219
+ elif default is None:
220
+ raise ConfigNotFound
221
+ else:
222
+ value = default
223
+ write_to_cache(value_key, value) # Also write default to cache
224
+ else:
225
+ value = convert_type_fnc(value)
226
+ return value
227
+
228
+
229
+ @read_session
230
+ def items(
231
+ section: str,
232
+ use_cache: bool = True,
233
+ expiration_time: int = 900,
234
+ *,
235
+ convert_type_fnc: 'Callable[[str], T]',
236
+ session: "Session"
237
+ ) -> list[tuple[str, T]]:
238
+ """
239
+ Return a list of (option, value) pairs for each option in the given section. Values are auto-coerced as in get().
240
+
241
+ :param section: The name of the section.
242
+ :param use_cache: Boolean if the cache should be used.
243
+ :param expiration_time: Time after that the cached value gets ignored.
244
+ :param convert_type_fnc: A function used to parse the string config value into the desired destination type
245
+ :param session: The database session in use.
246
+ :returns: [('option', auto-coerced value), ...]
247
+ """
248
+ items_key = CacheKey.items(section)
249
+ items = NoValue()
250
+ if use_cache:
251
+ items = read_from_cache(items_key, expiration_time)
252
+ if isinstance(items, NoValue):
253
+ stmt = select(
254
+ models.Config.opt,
255
+ models.Config.value
256
+ ).where(
257
+ models.Config.section == section
258
+ )
259
+ items = session.execute(stmt).all()
260
+ write_to_cache(items_key, items)
261
+ return [(opt, convert_type_fnc(val)) for opt, val in items]
262
+
263
+
264
+ @transactional_session
265
+ def set(
266
+ section: str,
267
+ option: str,
268
+ value: Any,
269
+ *,
270
+ session: "Session"
271
+ ) -> None:
272
+ """
273
+ Set the given option to the specified value. If the option doesn't exist, it is created.
274
+
275
+ :param section: The name of the section.
276
+ :param option: The name of the option.
277
+ :param value: The content of the value.
278
+ :param session: The database session in use.
279
+ """
280
+
281
+ if not has_option(section=section, option=option, use_cache=False, session=session):
282
+ section_existed = has_section(section=section)
283
+
284
+ new_option = models.Config(section=section, opt=option, value=value)
285
+ new_option.save(session=session)
286
+
287
+ delete_from_cache(key=CacheKey.value(section, option))
288
+ delete_from_cache(key=CacheKey.has_option(section, option))
289
+ delete_from_cache(key=CacheKey.items(section))
290
+ if not section_existed:
291
+ delete_from_cache(key=SECTIONS_CACHE_KEY)
292
+ delete_from_cache(key=CacheKey.has_section(section))
293
+ else:
294
+ stmt = select(
295
+ models.Config.value
296
+ ).where(
297
+ and_(models.Config.section == section,
298
+ models.Config.opt == option)
299
+ )
300
+ old_value = session.execute(stmt).scalar_one_or_none()
301
+ if old_value != str(value):
302
+ old_option = models.ConfigHistory(section=section,
303
+ opt=option,
304
+ value=old_value)
305
+ old_option.save(session=session)
306
+ stmt = update(
307
+ models.Config
308
+ ).where(
309
+ and_(models.Config.section == section,
310
+ models.Config.opt == option)
311
+ ).values({
312
+ models.Config.value: str(value)
313
+ })
314
+ session.execute(stmt)
315
+ delete_from_cache(key=CacheKey.value(section, option))
316
+ delete_from_cache(key=CacheKey.items(section))
317
+
318
+
319
+ @transactional_session
320
+ def remove_section(section: str, *, session: "Session") -> bool:
321
+ """
322
+ Remove the specified section from the specified section.
323
+
324
+ :param section: The name of the section.
325
+ :param session: The database session in use.
326
+ :returns: True/False.
327
+ """
328
+
329
+ if not has_section(section=section, session=session):
330
+ return False
331
+ else:
332
+ stmt = select(
333
+ models.Config.value
334
+ ).where(
335
+ models.Config.section == section
336
+ )
337
+ for old in session.execute(stmt).all():
338
+ old_option = models.ConfigHistory(section=old[0],
339
+ opt=old[1],
340
+ value=old[2])
341
+ old_option.save(session=session)
342
+ delete_from_cache(key=CacheKey.has_option(old[0], old[1]))
343
+ delete_from_cache(key=CacheKey.value(old[0], old[1]))
344
+
345
+ stmt = delete(
346
+ models.Config
347
+ ).where(
348
+ models.Config.section == section
349
+ )
350
+ session.execute(stmt)
351
+ delete_from_cache(key=SECTIONS_CACHE_KEY)
352
+ delete_from_cache(key=CacheKey.items(section))
353
+ return True
354
+
355
+
356
+ @transactional_session
357
+ def remove_option(section: str, option: str, *, session: "Session") -> bool:
358
+ """
359
+ Remove the specified option from the configuration.
360
+
361
+ :param section: The name of the section.
362
+ :param option: The name of the option.
363
+ :param session: The database session in use.
364
+ :returns: True/False
365
+ """
366
+
367
+ if not has_option(section=section, option=option, session=session, use_cache=False):
368
+ return False
369
+ else:
370
+ stmt = select(
371
+ models.Config.value
372
+ ).where(
373
+ and_(models.Config.section == section,
374
+ models.Config.opt == option)
375
+ )
376
+ result = session.execute(stmt).scalar_one_or_none()
377
+ old_option = models.ConfigHistory(section=section,
378
+ opt=option,
379
+ value=result)
380
+ old_option.save(session=session)
381
+
382
+ stmt = delete(
383
+ models.Config
384
+ ).where(
385
+ and_(models.Config.section == section,
386
+ models.Config.opt == option)
387
+ )
388
+ session.execute(stmt)
389
+
390
+ stmt = select(
391
+ func.count()
392
+ ).select_from(
393
+ models.Config
394
+ ).where(
395
+ models.Config.section == section
396
+ )
397
+ if not session.execute(stmt).scalar_one_or_none():
398
+ # we deleted the last config entry in the section. Invalidate the section cache
399
+ delete_from_cache(key=SECTIONS_CACHE_KEY)
400
+ delete_from_cache(key=CacheKey.has_section(section))
401
+ delete_from_cache(key=CacheKey.items(section))
402
+ delete_from_cache(key=CacheKey.has_option(section, option))
403
+ delete_from_cache(key=CacheKey.value(section, option))
404
+ return True
405
+
406
+
407
+ def read_from_cache(key: str, expiration_time: int = 900) -> Any:
408
+ """
409
+ Try to read a value from a cache.
410
+
411
+ :param key: Key that stores the value.
412
+ :param expiration_time: Time in seconds that a value should not be older than.
413
+ """
414
+ key = key.replace(' ', '')
415
+ value = REGION.get(key, expiration_time=expiration_time)
416
+ return value
417
+
418
+
419
+ def write_to_cache(key: str, value: Any) -> None:
420
+ """
421
+ Set a value on a key in a cache.
422
+
423
+ :param key: Key that stores the value.
424
+ :param value: Value to be stored.
425
+ """
426
+ key = key.replace(' ', '')
427
+ REGION.set(key, value)
428
+
429
+
430
+ def delete_from_cache(key: str) -> None:
431
+ """
432
+ Delete from cache any data stored for the given key
433
+
434
+ :param key: Key that stores the value.
435
+ """
436
+ key = key.replace(' ', '')
437
+ REGION.delete(key)
@@ -0,0 +1,224 @@
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 Optional
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 MemcacheRegion
29
+ from rucio.common.config import config_get, get_rse_credentials
30
+ from rucio.common.constants import RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS, RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL, SUPPORTED_SIGN_URL_SERVICES, SUPPORTED_SIGN_URL_SERVICES_LITERAL, 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 = MemcacheRegion(expiration_time=900)
38
+ METRICS = MetricManager(module=__name__)
39
+
40
+
41
+ def get_signed_url(
42
+ rse_id: str,
43
+ service: SUPPORTED_SIGN_URL_SERVICES_LITERAL,
44
+ operation: RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL,
45
+ url: str,
46
+ lifetime: Optional[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 SUPPORTED_SIGN_URL_SERVICES:
64
+ raise UnsupportedOperation('Service must be "gcs", "s3" or "swift"')
65
+
66
+ if operation not in RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS:
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
+ # special case to test signature, force epoch time
88
+ if lifetime is None:
89
+ lifetime = 0
90
+ else:
91
+ # GCS is timezone-sensitive, don't use UTC
92
+ # has to be converted to Unixtime
93
+ lifetime_datetime = datetime.datetime.now() + datetime.timedelta(seconds=lifetime)
94
+ lifetime = int(time.mktime(lifetime_datetime.timetuple()))
95
+
96
+ # sign the path only
97
+ path = components.path
98
+
99
+ # Map operations
100
+ operations = {'read': 'GET', 'write': 'PUT', 'delete': 'DELETE'}
101
+
102
+ # assemble message to sign
103
+ to_sign = "%s\n\n\n%s\n%s" % (operations[operation], lifetime, path)
104
+
105
+ # create URL-capable signature
106
+ # first character is always a '=', remove it
107
+ signature = urlencode({'': base64.b64encode(CREDS_GCS.sign_bytes(to_sign))})[1:]
108
+
109
+ # assemble final signed URL
110
+ signed_url = (
111
+ f'https://{host}{path}'
112
+ f'?GoogleAccessId={CREDS_GCS.service_account_email}'
113
+ f'&Expires={lifetime}&Signature={signature}'
114
+ )
115
+
116
+ elif service == 's3':
117
+
118
+ # get RSE S3 URL style (path or host)
119
+ # path-style: https://s3.region-code.amazonaws.com/bucket-name/key-name
120
+ # host-style: https://bucket-name.s3.region-code.amazonaws.com/key-name
121
+ s3_url_style = get_rse_attribute(rse_id, RseAttr.S3_URL_STYLE)
122
+
123
+ # no S3 URL style specified, assume path-style
124
+ if s3_url_style is None:
125
+ s3_url_style = "path"
126
+
127
+ # split URL to get hostname, bucket and key
128
+ components = urlparse(url)
129
+ host = components.netloc
130
+ pathcomponents = components.path.split('/')
131
+ if s3_url_style == "path":
132
+ if len(pathcomponents) < 3:
133
+ raise UnsupportedOperation('Not a valid Path-Style S3 URL')
134
+ bucket = pathcomponents[1]
135
+ key = '/'.join(pathcomponents[2:])
136
+ elif s3_url_style == "host":
137
+ hostcomponents = host.split('.')
138
+ bucket = hostcomponents[0]
139
+ if len(pathcomponents) < 2:
140
+ raise UnsupportedOperation('Not a valid Host-Style S3 URL')
141
+ key = '/'.join(pathcomponents[1:])
142
+ else:
143
+ raise UnsupportedOperation('Not a valid RSE S3 URL style (allowed values: path|host)')
144
+
145
+ # remove port number from host if present
146
+ colon = host.find(':')
147
+ port = '443'
148
+ if colon >= 0:
149
+ port = host[colon + 1:]
150
+ host = host[:colon]
151
+
152
+ # look up in RSE account configuration by RSE ID
153
+ cred_name = rse_id
154
+ cred = REGION.get('s3-%s' % cred_name)
155
+ if cred is NO_VALUE:
156
+ rse_cred = get_rse_credentials()
157
+ cred = rse_cred.get(cred_name)
158
+ REGION.set('s3-%s' % cred_name, cred)
159
+ access_key = cred['access_key']
160
+ secret_key = cred['secret_key']
161
+ signature_version = cred['signature_version']
162
+ region_name = cred['region']
163
+
164
+ if operation == 'read':
165
+ s3op = 'get_object'
166
+ elif operation == 'write':
167
+ s3op = 'put_object'
168
+ else:
169
+ s3op = 'delete_object'
170
+
171
+ with METRICS.timer('signs3'):
172
+
173
+ if s3_url_style == "host":
174
+ s3_url_style = "virtual"
175
+
176
+ s3 = boto3.client(service_name='s3',
177
+ endpoint_url=f'https://{host}:{port}',
178
+ aws_access_key_id=access_key,
179
+ aws_secret_access_key=secret_key,
180
+ config=Config(signature_version=signature_version,
181
+ region_name=region_name,
182
+ s3={"addressing_style": s3_url_style}))
183
+
184
+ signed_url: str = s3.generate_presigned_url(
185
+ s3op, Params={'Bucket': bucket, 'Key': key}, ExpiresIn=lifetime)
186
+
187
+ else: # service == 'swift'
188
+ # split URL to get hostname and path
189
+ components = urlparse(url)
190
+ host = components.netloc
191
+
192
+ # remove port number from host if present
193
+ colon = host.find(':')
194
+ if colon >= 0:
195
+ host = host[:colon]
196
+
197
+ # use RSE ID to look up key
198
+ cred_name = rse_id
199
+
200
+ # look up tempurl signing key
201
+ cred = REGION.get('swift-%s' % cred_name)
202
+ if cred is NO_VALUE:
203
+ rse_cred = get_rse_credentials()
204
+ cred = rse_cred.get(cred_name)
205
+ REGION.set('swift-%s' % cred_name, cred)
206
+ tempurl_key = cred['tempurl_key']
207
+
208
+ if operation == 'read':
209
+ swiftop = 'GET'
210
+ elif operation == 'write':
211
+ swiftop = 'PUT'
212
+ else:
213
+ swiftop = 'DELETE'
214
+
215
+ expires = int(time.time() + lifetime) # type: ignore (lifetime could be None)
216
+
217
+ # create signed URL
218
+ with METRICS.timer('signswift'):
219
+ hmac_body = '%s\n%s\n%s' % (swiftop, expires, components.path)
220
+ # Python 3 hmac only accepts bytes or bytearray
221
+ sig = hmac.new(bytearray(tempurl_key, 'utf-8'), bytearray(hmac_body, 'utf-8'), sha1).hexdigest()
222
+ signed_url = f'https://{host}{components.path}?temp_url_sig={sig}&temp_url_expires={expires}'
223
+
224
+ return signed_url