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
@@ -0,0 +1,317 @@
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 json
17
+ import operator
18
+ from typing import TYPE_CHECKING
19
+
20
+ import psycopg2
21
+ import psycopg2.extras
22
+
23
+ from rucio.common import config
24
+ from rucio.common import exception
25
+ from rucio.common.types import InternalScope
26
+ from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
27
+ from rucio.core.did_meta_plugins.filter_engine import FilterEngine
28
+
29
+ if TYPE_CHECKING:
30
+ from typing import Optional
31
+ from sqlalchemy.orm import Session
32
+
33
+
34
+ class ExternalPostgresDidMeta(DidMetaPlugin):
35
+ # TODO: column-based plugin? mixed-mode (json & columns)?
36
+ pass
37
+
38
+
39
+ class ExternalPostgresJSONDidMeta(DidMetaPlugin):
40
+ def __init__(self, host=None, port=None, db=None, user=None, password=None, db_schema=None, table=None,
41
+ table_is_managed=None, table_column_vo=None, table_column_scope=None, table_column_name=None,
42
+ table_column_data=None):
43
+ super(ExternalPostgresJSONDidMeta, self).__init__()
44
+ if host is None:
45
+ host = config.config_get('metadata', 'postgres_service_host')
46
+ if port is None:
47
+ port = config.config_get_int('metadata', 'postgres_service_port')
48
+ if db is None:
49
+ db = config.config_get('metadata', 'postgres_db')
50
+ if user is None:
51
+ user = config.config_get('metadata', 'postgres_user')
52
+ if password is None:
53
+ password = config.config_get('metadata', 'postgres_password')
54
+ if db_schema is None:
55
+ db_schema = config.config_get('metadata', 'postgres_db_schema', default='public')
56
+ if table is None:
57
+ table = config.config_get('metadata', 'postgres_table', default='dids')
58
+ if table_is_managed is None:
59
+ table_is_managed = config.config_get_bool('metadata', 'postgres_table_is_managed', default=False)
60
+ if table_column_vo is None:
61
+ table_column_vo = config.config_get('metadata', 'postgres_table_column_vo', default='vo')
62
+ if table_column_scope is None:
63
+ table_column_scope = config.config_get('metadata', 'postgres_table_column_scope', default='scope')
64
+ if table_column_name is None:
65
+ table_column_name = config.config_get('metadata', 'postgres_table_column_name', default='name')
66
+ if table_column_data is None:
67
+ table_column_data = config.config_get('metadata', 'postgres_table_column_data', default='data')
68
+
69
+ self.fixed_table_columns = {
70
+ 'vo': table_column_vo,
71
+ 'scope': table_column_scope,
72
+ 'name': table_column_name
73
+ }
74
+ self.jsonb_column = table_column_data
75
+
76
+ self.table = table
77
+ self.client = psycopg2.connect(
78
+ host=host,
79
+ port=port,
80
+ database=db,
81
+ user=user,
82
+ password=password)
83
+
84
+ # set search_path to include database schema by default
85
+ cur = self.client.cursor()
86
+ statement = "SET search_path TO {};".format(db_schema)
87
+ cur.execute(statement)
88
+ cur.close()
89
+
90
+ if not table_is_managed: # not managed by Rucio, so just verify table schema
91
+ self._verify_table_schema(table_column_vo, table_column_scope, table_column_name, table_column_data)
92
+ else: # managed by Rucio, create a metadata table if it doesn't exist
93
+ self._try_create_metadata_table()
94
+
95
+ self.plugin_name = "POSTGRES_JSON"
96
+
97
+ def _try_create_metadata_table(self):
98
+ """
99
+ Try to create a metadata table.
100
+ """
101
+ table_clauses = (
102
+ ("id", "bigint", "NOT NULL", "GENERATED ALWAYS AS IDENTITY"),
103
+ ("vo", "varchar", "NOT NULL"),
104
+ ("scope", "varchar", "NOT NULL"),
105
+ ("name", "varchar", "NOT NULL"),
106
+ ("data", "jsonb", "DEFAULT", "'{}'::jsonb"),
107
+ ("UNIQUE", "(scope, name)") # unique scope+name table constraint, required for ON CONFLICT
108
+ )
109
+ statement = "CREATE TABLE IF NOT EXISTS {} ({})".format(
110
+ self.table,
111
+ ', '.join([' '.join(clause) for clause in table_clauses]))
112
+
113
+ cur = self.client.cursor()
114
+ cur.execute(statement)
115
+ cur.close()
116
+ self.client.commit()
117
+
118
+ def _verify_table_schema(self, table_column_vo, table_column_scope, table_column_name, table_column_data):
119
+ """
120
+ Rudimentary verification that the metadata table schema meets the requirements for the plugin.
121
+
122
+ Should be called when using externally managed database tables as a sanity check.
123
+
124
+ :param table_column_vo: The table column used for the vo
125
+ :param table_column_scope: The table column used for the scope
126
+ :param table_column_name: The table column used for the name
127
+ :param table_column_data: The table column used for the data
128
+ :raises: MetadataSchemaMismatchError
129
+ """
130
+ # Check mandatory columns are of right data type and have the right nullable qualifier.
131
+ statement = "SELECT column_name, data_type, is_nullable " \
132
+ "FROM INFORMATION_SCHEMA.COLUMNS where table_name = '{}';".format(self.table)
133
+ cur = self.client.cursor()
134
+ cur.execute(statement)
135
+ existing_table_columns = cur.fetchall()
136
+ cur.close()
137
+
138
+ mandatory_column_specifications = [
139
+ (table_column_vo, "character varying", "NO"),
140
+ (table_column_scope, "character varying", "NO"),
141
+ (table_column_name, "character varying", "NO"),
142
+ (table_column_data, "jsonb", "YES")
143
+ ]
144
+ for specification in mandatory_column_specifications:
145
+ if specification not in existing_table_columns:
146
+ raise exception.MetadataSchemaMismatchError(
147
+ "mandatory table column {} does not match that defined in the required table schema {}".format(
148
+ specification, existing_table_columns))
149
+
150
+ # Check required table constraints exist.
151
+ statement = "SELECT con.contype AS constraint_type, " \
152
+ "(SELECT array_agg(att.attname) FROM pg_attribute att " \
153
+ " INNER JOIN unnest(con.conkey) unnest(conkey) ON unnest.conkey = att.attnum " \
154
+ " WHERE att.attrelid = con.conrelid) AS columns " \
155
+ "FROM pg_constraint con " \
156
+ "INNER JOIN pg_class rel ON rel.oid = con.conrelid " \
157
+ "INNER JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace " \
158
+ "WHERE rel.relname = '{}';".format(self.table)
159
+ cur = self.client.cursor()
160
+ cur.execute(statement)
161
+ existing_table_constraints = cur.fetchall() # list of (constraint_type, [columns])
162
+ cur.close()
163
+
164
+ mandatory_table_constraints = [
165
+ ("u", [table_column_scope, table_column_name]), # unique scope+name table constraint
166
+ ]
167
+ for constraint in mandatory_table_constraints:
168
+ if constraint not in existing_table_constraints:
169
+ raise exception.MetadataSchemaMismatchError(
170
+ "mandatory table constraint {} does not match that defined in the required table schema {}".format(
171
+ constraint, len(existing_table_constraints)))
172
+
173
+ def _drop_metadata_table(self):
174
+ statement = "DROP TABLE IF EXISTS {};".format(self.table)
175
+ cur = self.client.cursor()
176
+ cur.execute(statement)
177
+ cur.close()
178
+ self.client.commit()
179
+
180
+ def get_metadata(self, scope, name, *, session: "Optional[Session]" = None):
181
+ """
182
+ Get data identifier metadata.
183
+
184
+ :param scope: The scope name
185
+ :param name: The data identifier name
186
+ :param session: The database session in use
187
+ :returns: the metadata for the did
188
+ """
189
+ statement = "SELECT data from {} ".format(self.table) + \
190
+ "WHERE scope='{}' AND name='{}';".format(scope.internal, name)
191
+ cur = self.client.cursor()
192
+ cur.execute(statement)
193
+ metadata = cur.fetchone()
194
+ cur.close()
195
+
196
+ if not metadata:
197
+ raise exception.DataIdentifierNotFound("No metadata found for did '{}:{}".format(scope, name))
198
+
199
+ return metadata[0]
200
+
201
+ def set_metadata(self, scope, name, key, value, recursive=False, *, session: "Optional[Session]" = None):
202
+ """
203
+ Set single metadata key.
204
+
205
+ :param scope: the scope of did
206
+ :param name: the name of the did
207
+ :param key: the key to be added
208
+ :param value: the value of the key to be added
209
+ :param recursive: recurse into DIDs (not supported)
210
+ :param session: The database session in use
211
+ """
212
+ self.set_metadata_bulk(scope=scope, name=name, metadata={key: value}, recursive=recursive, session=session)
213
+
214
+ def set_metadata_bulk(self, scope, name, metadata, recursive=False, *, session: "Optional[Session]" = None):
215
+ """
216
+ Bulk set metadata keys.
217
+
218
+ :param scope: the scope of did
219
+ :param name: the name of the did
220
+ :param metadata: dictionary of metadata keypairs to be added
221
+ :param recursive: recurse into DIDs (not supported)
222
+ :param session: The database session in use
223
+ """
224
+ # upsert metadata
225
+ statement = "INSERT INTO {} (scope, name, vo, data) ".format(self.table) + \
226
+ "VALUES ('{}', '{}', '{}', '{}') ".format(scope.external, name, scope.vo, json.dumps(metadata)) + \
227
+ "ON CONFLICT (scope, name) DO UPDATE set data = {}.data || EXCLUDED.data;".format(self.table)
228
+ cur = self.client.cursor()
229
+ cur.execute(statement)
230
+ cur.close()
231
+ self.client.commit()
232
+
233
+ def delete_metadata(self, scope, name, key, *, session: "Optional[Session]" = None):
234
+ """
235
+ Delete a key from metadata.
236
+
237
+ :param scope: the scope of did
238
+ :param name: the name of the did
239
+ :param key: the key to be deleted
240
+ :param session: the database session in use
241
+ """
242
+ statement = "UPDATE {} ".format(self.table) + \
243
+ "SET data = {}.data - '{}';".format(self.table, key)
244
+ cur = self.client.cursor()
245
+ cur.execute(statement)
246
+ cur.close()
247
+ self.client.commit()
248
+
249
+ def list_dids(self, scope, filters, did_type='collection', ignore_case=False, limit=None,
250
+ offset=None, long=False, recursive=False, ignore_dids=None, *, session: "Optional[Session]" = None):
251
+
252
+ if not ignore_dids:
253
+ ignore_dids = set()
254
+
255
+ # backwards compatability for filters as single {}.
256
+ if isinstance(filters, dict):
257
+ filters = [filters]
258
+
259
+ try:
260
+ # instantiate fe and create postgres query
261
+ fe = FilterEngine(filters, model_class=None, strict_coerce=False)
262
+ postgres_query_str = fe.create_postgres_query(
263
+ additional_filters=[
264
+ ('scope', operator.eq, scope.internal),
265
+ ('vo', operator.eq, scope.vo)
266
+ ],
267
+ fixed_table_columns=self.fixed_table_columns,
268
+ jsonb_column=self.jsonb_column
269
+ )
270
+ except Exception as e:
271
+ raise exception.DataIdentifierNotFound(e)
272
+
273
+ if recursive:
274
+ # TODO: possible, but requires retrieving the results of a concurrent sqla query to call list_content
275
+ # on for datasets and containers
276
+ raise exception.UnsupportedOperation(
277
+ "'{}' metadata module does not currently support recursive searches".format(self.plugin_name.lower())
278
+ )
279
+
280
+ statement = "SELECT * FROM {} WHERE {} ".format(self.table, postgres_query_str)
281
+ if limit:
282
+ statement += "LIMIT {}".format(limit)
283
+ cur = self.client.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
284
+ cur.execute(statement)
285
+ query_result = cur.fetchall()
286
+ cur.close()
287
+
288
+ if long:
289
+ for row in query_result:
290
+ did = "{}:{}".format(row['scope'], row['name'])
291
+ if did not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
292
+ ignore_dids.add(did)
293
+ yield {
294
+ 'scope': InternalScope(row['scope']),
295
+ 'name': row['name'],
296
+ 'did_type': "N/A",
297
+ 'bytes': "N/A",
298
+ 'length': "N/A"
299
+ }
300
+ else:
301
+ for row in query_result:
302
+ did = "{}:{}".format(row['scope'], row['name'])
303
+ if did not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
304
+ ignore_dids.add(did)
305
+ yield row['name']
306
+
307
+ def manages_key(self, key, *, session: "Optional[Session]" = None):
308
+ return True
309
+
310
+ def get_plugin_name(self):
311
+ """
312
+ Returns a unique identifier for this plugin. This can be later used for filtering down results to this
313
+ plugin only.
314
+
315
+ :returns: The name of the plugin
316
+ """
317
+ return self.plugin_name
rucio/core/dirac.py ADDED
@@ -0,0 +1,208 @@
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 re
17
+ from json import loads
18
+ from json.decoder import JSONDecodeError
19
+ from typing import TYPE_CHECKING
20
+
21
+ from sqlalchemy.orm.exc import NoResultFound
22
+
23
+ from rucio.common.config import config_get
24
+ from rucio.common.exception import InvalidType, UnsupportedOperation, ConfigNotFound, RucioException
25
+ from rucio.common.types import InternalScope, InternalAccount
26
+ from rucio.common.utils import extract_scope
27
+ from rucio.core.did import add_did, attach_dids_to_dids
28
+ from rucio.core.replica import add_replicas
29
+ from rucio.core.rule import add_rule, list_rules, update_rule
30
+ from rucio.core.scope import list_scopes
31
+ from rucio.db.sqla import models
32
+ from rucio.db.sqla.constants import DIDType
33
+ from rucio.db.sqla.session import transactional_session, read_session
34
+
35
+ if TYPE_CHECKING:
36
+ from sqlalchemy.orm import Session
37
+
38
+
39
+ @read_session
40
+ def _exists(scope, name, *, session: "Session"):
41
+ """
42
+ Check if the did exists
43
+
44
+ :scope: The scope
45
+ :name: The name
46
+ :session: The session used
47
+ """
48
+ try:
49
+ res = session.query(models.DataIdentifier).filter_by(scope=scope, name=name).\
50
+ with_hint(models.DataIdentifier, "INDEX(DIDS DIDS_PK)", 'oracle').one()
51
+ return True, res.did_type
52
+ except NoResultFound:
53
+ return False, None
54
+
55
+
56
+ @transactional_session
57
+ def add_files(lfns, account, ignore_availability, vo='def', *, session: "Session"):
58
+ """
59
+ Bulk add files :
60
+ - Create the file and replica.
61
+ - If doesn't exist create the dataset containing the file as well as a rule on the dataset on ANY sites.
62
+ - Create all the ascendants of the dataset if they do not exist
63
+
64
+ :param lfns: List of lfn (dictionary {'lfn': <lfn>, 'rse': <rse>, 'bytes': <bytes>, 'adler32': <adler32>, 'guid': <guid>, 'pfn': <pfn>}
65
+ :param issuer: The issuer account.
66
+ :param ignore_availability: A boolean to ignore blocklisted sites.
67
+ :param vo: The VO to act on
68
+ :param session: The session used
69
+ """
70
+ rule_extension_list = []
71
+ attachments = []
72
+ # The list of scopes is necessary for the extract_scope
73
+ filter_ = {'scope': InternalScope(scope='*', vo=vo)}
74
+ scopes = list_scopes(filter_=filter_, session=session)
75
+ scopes = [scope.external for scope in scopes]
76
+ exist_lfn = []
77
+ try:
78
+ lifetime_dict: str = config_get(section='dirac', option='lifetime', default='{}', session=session)
79
+ lifetime_dict = loads(lifetime_dict)
80
+ except ConfigNotFound:
81
+ lifetime_dict = {}
82
+ except JSONDecodeError as err:
83
+ raise InvalidType('Problem parsing lifetime option in dirac section : %s' % str(err))
84
+ except Exception as err:
85
+ raise RucioException(str(err))
86
+
87
+ for lfn in lfns:
88
+ # First check if the file exists
89
+ filename = lfn['lfn']
90
+ lfn_scope, _ = extract_scope(filename, scopes)
91
+ lfn_scope = InternalScope(lfn_scope, vo=vo)
92
+
93
+ exists, did_type = _exists(lfn_scope, filename)
94
+ if exists:
95
+ continue
96
+
97
+ # Get all the ascendants of the file
98
+ lfn_split = filename.split('/')
99
+ lpns = ["/".join(lfn_split[:idx]) for idx in range(2, len(lfn_split))]
100
+ lpns.reverse()
101
+ print(lpns)
102
+
103
+ # The parent must be a dataset. Register it as well as the rule
104
+ dsn_name = lpns[0]
105
+ dsn_scope, _ = extract_scope(dsn_name, scopes)
106
+ dsn_scope = InternalScope(dsn_scope, vo=vo)
107
+
108
+ # Compute lifetime
109
+ lifetime = None
110
+ if dsn_scope in lifetime_dict:
111
+ lifetime = lifetime_dict[dsn_scope.external]
112
+ else:
113
+ for pattern in lifetime_dict:
114
+ if dsn_scope.external and re.match(pattern, str(dsn_scope.external)):
115
+ lifetime = lifetime_dict[pattern]
116
+ break
117
+
118
+ exists, did_type = _exists(dsn_scope, dsn_name)
119
+ if exists and did_type == DIDType.CONTAINER:
120
+ raise UnsupportedOperation('Cannot create %s as dataset' % dsn_name)
121
+ if (dsn_name not in exist_lfn) and not exists:
122
+ print('Will create %s' % dsn_name)
123
+ # to maintain a compatibility between master and LTS-1.26 branches remove keywords for first 3 arguments
124
+ add_did(dsn_scope,
125
+ dsn_name,
126
+ DIDType.DATASET,
127
+ account=InternalAccount(account, vo=vo),
128
+ statuses=None,
129
+ meta=None,
130
+ rules=[{'copies': 1, 'rse_expression': 'ANY=true', 'weight': None, 'account': InternalAccount(account, vo=vo), 'lifetime': lifetime, 'grouping': 'NONE'}],
131
+ lifetime=None,
132
+ dids=None,
133
+ rse_id=None,
134
+ session=session)
135
+ exist_lfn.append(dsn_name)
136
+ parent_name = lpns[1]
137
+ parent_scope, _ = extract_scope(parent_name, scopes)
138
+ parent_scope = InternalScope(parent_scope, vo=vo)
139
+ attachments.append({'scope': parent_scope, 'name': parent_name, 'dids': [{'scope': dsn_scope, 'name': dsn_name}]})
140
+ rule_extension_list.append((dsn_scope, dsn_name))
141
+ if lifetime and (dsn_scope, dsn_name) not in rule_extension_list:
142
+ # Reset the lifetime of the rule to the configured value
143
+ rule = [rul for rul in list_rules({'scope': dsn_scope, 'name': dsn_name, 'account': InternalAccount(account, vo=vo)}, session=session) if rul['rse_expression'] == 'ANY=true']
144
+ if rule:
145
+ update_rule(rule[0]['id'], options={'lifetime': lifetime}, session=session)
146
+ rule_extension_list.append((dsn_scope, dsn_name))
147
+
148
+ # Register the file
149
+ rse_id = lfn.get('rse_id', None)
150
+ if not rse_id:
151
+ raise InvalidType('Missing rse_id')
152
+ bytes_ = lfn.get('bytes', None)
153
+ guid = lfn.get('guid', None)
154
+ adler32 = lfn.get('adler32', None)
155
+ pfn = lfn.get('pfn', None)
156
+ files = {'scope': lfn_scope, 'name': filename, 'bytes': bytes_, 'adler32': adler32}
157
+ if pfn:
158
+ files['pfn'] = str(pfn)
159
+ if guid:
160
+ files['meta'] = {'guid': guid}
161
+ add_replicas(rse_id=rse_id,
162
+ files=[files],
163
+ dataset_meta=None,
164
+ account=InternalAccount(account, vo=vo),
165
+ ignore_availability=ignore_availability,
166
+ session=session)
167
+ add_rule(dids=[{'scope': lfn_scope, 'name': filename}],
168
+ account=InternalAccount(account, vo=vo),
169
+ copies=1,
170
+ rse_expression=lfn['rse'],
171
+ grouping=None,
172
+ weight=None,
173
+ lifetime=86400,
174
+ locked=None,
175
+ subscription_id=None,
176
+ session=session)
177
+ attachments.append({'scope': dsn_scope, 'name': dsn_name, 'dids': [{'scope': lfn_scope, 'name': filename}]})
178
+
179
+ # Now loop over the ascendants of the dataset and created them
180
+ for lpn in lpns[1:]:
181
+ child_scope, _ = extract_scope(lpn, scopes)
182
+ child_scope = InternalScope(child_scope, vo=vo)
183
+ exists, did_type = _exists(child_scope, lpn)
184
+ if exists and did_type == DIDType.DATASET:
185
+ raise UnsupportedOperation('Cannot create %s as container' % lpn)
186
+ if (lpn not in exist_lfn) and not exists:
187
+ print('Will create %s' % lpn)
188
+ add_did(child_scope,
189
+ lpn,
190
+ DIDType.CONTAINER,
191
+ account=InternalAccount(account, vo=vo),
192
+ statuses=None,
193
+ meta=None,
194
+ rules=None,
195
+ lifetime=None,
196
+ dids=None,
197
+ rse_id=None,
198
+ session=session)
199
+ exist_lfn.append(lpn)
200
+ parent_name = lpns[lpns.index(lpn) + 1]
201
+ parent_scope, _ = extract_scope(parent_name, scopes)
202
+ parent_scope = InternalScope(parent_scope, vo=vo)
203
+ attachments.append({'scope': parent_scope, 'name': parent_name, 'dids': [{'scope': child_scope, 'name': lpn}]})
204
+ # Finally attach everything
205
+ attach_dids_to_dids(attachments,
206
+ account=InternalAccount(account, vo=vo),
207
+ ignore_duplicate=True,
208
+ session=session)
rucio/core/distance.py ADDED
@@ -0,0 +1,164 @@
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 typing import TYPE_CHECKING
17
+
18
+ from sqlalchemy.exc import DatabaseError, IntegrityError
19
+ from sqlalchemy.orm import aliased
20
+
21
+ from rucio.common import exception
22
+ from rucio.db.sqla.models import Distance, RSE
23
+ from rucio.db.sqla.session import transactional_session, read_session
24
+
25
+ if TYPE_CHECKING:
26
+ from sqlalchemy.orm import Session
27
+
28
+
29
+ @transactional_session
30
+ def add_distance(src_rse_id, dest_rse_id, distance=None, *, session: "Session"):
31
+ """
32
+ Add a src-dest distance.
33
+
34
+ :param src_rse_id: The source RSE ID.
35
+ :param dest_rse_id: The destination RSE ID.
36
+ :param distance: Distance as an integer.
37
+ :param session: The database session to use.
38
+ """
39
+
40
+ try:
41
+ new_distance = Distance(src_rse_id=src_rse_id, dest_rse_id=dest_rse_id, distance=distance)
42
+ new_distance.save(session=session)
43
+ except IntegrityError:
44
+ raise exception.Duplicate()
45
+ except DatabaseError as error:
46
+ raise exception.RucioException(error.args)
47
+
48
+
49
+ @read_session
50
+ def get_distances(src_rse_id=None, dest_rse_id=None, *, session: "Session") -> list[dict]:
51
+ """
52
+ Get distances between rses.
53
+
54
+ :param src_rse_id: The source RSE ID.
55
+ :param dest_rse_id: The destination RSE ID.
56
+ :param session: The database session to use.
57
+
58
+ :returns distance: List of dictionaries.
59
+ """
60
+
61
+ try:
62
+ query = session.query(Distance)
63
+ if src_rse_id:
64
+ query = query.filter(Distance.src_rse_id == src_rse_id)
65
+ if dest_rse_id:
66
+ query = query.filter(Distance.dest_rse_id == dest_rse_id)
67
+
68
+ distances = []
69
+ tmp = query.all()
70
+ if tmp:
71
+ for t in tmp:
72
+ t2 = t.to_dict()
73
+ t2['ranking'] = t2['distance'] # Compatibility with old clients
74
+ distances.append(t2)
75
+ return distances
76
+ except IntegrityError as error:
77
+ raise exception.RucioException(error.args)
78
+
79
+
80
+ @transactional_session
81
+ def delete_distances(src_rse_id=None, dest_rse_id=None, *, session: "Session"):
82
+ """
83
+ Delete distances with the given RSE ids.
84
+
85
+ :param src_rse_id: The source RSE ID.
86
+ :param dest_rse_id: The destination RSE ID.
87
+ :param session: The database session to use.
88
+ """
89
+
90
+ try:
91
+ query = session.query(Distance)
92
+
93
+ if src_rse_id:
94
+ query = query.filter(Distance.src_rse_id == src_rse_id)
95
+ if dest_rse_id:
96
+ query = query.filter(Distance.dest_rse_id == dest_rse_id)
97
+
98
+ query.delete()
99
+ except IntegrityError as error:
100
+ raise exception.RucioException(error.args)
101
+
102
+
103
+ @transactional_session
104
+ def update_distances(src_rse_id=None, dest_rse_id=None, distance=None, *, session: "Session"):
105
+ """
106
+ Update distances with the given RSE ids.
107
+
108
+ :param src_rse_id: The source RSE ID.
109
+ :param dest_rse_id: The destination RSE ID.
110
+ :param distance: The new distance to set
111
+ :param session: The database session to use.
112
+ """
113
+ try:
114
+ query = session.query(Distance)
115
+ if src_rse_id:
116
+ query = query.filter(Distance.src_rse_id == src_rse_id)
117
+ if dest_rse_id:
118
+ query = query.filter(Distance.dest_rse_id == dest_rse_id)
119
+ query.update({Distance.distance: distance})
120
+ except IntegrityError as error:
121
+ raise exception.RucioException(error.args)
122
+
123
+
124
+ @read_session
125
+ def list_distances(filter_={}, *, session: "Session"):
126
+ """
127
+ Get distances between all the RSEs.
128
+
129
+ :param filter_: dictionary to filter distances.
130
+ :param session: The database session in use.
131
+ """
132
+ return [distance.to_dict() for distance in session.query(Distance).all()]
133
+
134
+
135
+ @read_session
136
+ def export_distances(vo='def', *, session: "Session"):
137
+ """
138
+ Export distances between all the RSEs using RSE ids.
139
+ :param vo: The VO to export.
140
+ :param session: The database session to use.
141
+ :returns distance: dictionary of dictionaries with all the distances.
142
+ """
143
+
144
+ distances = {}
145
+ try:
146
+ rse_src = aliased(RSE)
147
+ rse_dest = aliased(RSE)
148
+ query = session.query(Distance, rse_src.id, rse_dest.id)\
149
+ .join(rse_src, rse_src.id == Distance.src_rse_id)\
150
+ .join(rse_dest, rse_dest.id == Distance.dest_rse_id)\
151
+ .filter(rse_src.vo == vo)\
152
+ .filter(rse_dest.vo == vo)
153
+ for result in query.all():
154
+ distance = result[0]
155
+ src_id = result[1]
156
+ dst_id = result[2]
157
+ if src_id not in distances:
158
+ distances[src_id] = {}
159
+ distance = distance.to_dict()
160
+ distance['ranking'] = distance['distance'] # Compatibility with old clients
161
+ distances[src_id][dst_id] = distance
162
+ return distances
163
+ except IntegrityError as error:
164
+ raise exception.RucioException(error.args)