rucio 32.8.6__py3-none-any.whl

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

Potentially problematic release.


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

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