rucio 35.7.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (493) hide show
  1. rucio/__init__.py +17 -0
  2. rucio/alembicrevision.py +15 -0
  3. rucio/client/__init__.py +15 -0
  4. rucio/client/accountclient.py +433 -0
  5. rucio/client/accountlimitclient.py +183 -0
  6. rucio/client/baseclient.py +974 -0
  7. rucio/client/client.py +76 -0
  8. rucio/client/configclient.py +126 -0
  9. rucio/client/credentialclient.py +59 -0
  10. rucio/client/didclient.py +866 -0
  11. rucio/client/diracclient.py +56 -0
  12. rucio/client/downloadclient.py +1785 -0
  13. rucio/client/exportclient.py +44 -0
  14. rucio/client/fileclient.py +50 -0
  15. rucio/client/importclient.py +42 -0
  16. rucio/client/lifetimeclient.py +90 -0
  17. rucio/client/lockclient.py +109 -0
  18. rucio/client/metaconventionsclient.py +140 -0
  19. rucio/client/pingclient.py +44 -0
  20. rucio/client/replicaclient.py +454 -0
  21. rucio/client/requestclient.py +125 -0
  22. rucio/client/rseclient.py +746 -0
  23. rucio/client/ruleclient.py +294 -0
  24. rucio/client/scopeclient.py +90 -0
  25. rucio/client/subscriptionclient.py +173 -0
  26. rucio/client/touchclient.py +82 -0
  27. rucio/client/uploadclient.py +955 -0
  28. rucio/common/__init__.py +13 -0
  29. rucio/common/cache.py +74 -0
  30. rucio/common/config.py +801 -0
  31. rucio/common/constants.py +159 -0
  32. rucio/common/constraints.py +17 -0
  33. rucio/common/didtype.py +189 -0
  34. rucio/common/dumper/__init__.py +335 -0
  35. rucio/common/dumper/consistency.py +452 -0
  36. rucio/common/dumper/data_models.py +318 -0
  37. rucio/common/dumper/path_parsing.py +64 -0
  38. rucio/common/exception.py +1151 -0
  39. rucio/common/extra.py +36 -0
  40. rucio/common/logging.py +420 -0
  41. rucio/common/pcache.py +1408 -0
  42. rucio/common/plugins.py +153 -0
  43. rucio/common/policy.py +84 -0
  44. rucio/common/schema/__init__.py +150 -0
  45. rucio/common/schema/atlas.py +413 -0
  46. rucio/common/schema/belleii.py +408 -0
  47. rucio/common/schema/domatpc.py +401 -0
  48. rucio/common/schema/escape.py +426 -0
  49. rucio/common/schema/generic.py +433 -0
  50. rucio/common/schema/generic_multi_vo.py +412 -0
  51. rucio/common/schema/icecube.py +406 -0
  52. rucio/common/stomp_utils.py +159 -0
  53. rucio/common/stopwatch.py +55 -0
  54. rucio/common/test_rucio_server.py +148 -0
  55. rucio/common/types.py +403 -0
  56. rucio/common/utils.py +2238 -0
  57. rucio/core/__init__.py +13 -0
  58. rucio/core/account.py +496 -0
  59. rucio/core/account_counter.py +236 -0
  60. rucio/core/account_limit.py +423 -0
  61. rucio/core/authentication.py +620 -0
  62. rucio/core/config.py +456 -0
  63. rucio/core/credential.py +225 -0
  64. rucio/core/did.py +3000 -0
  65. rucio/core/did_meta_plugins/__init__.py +252 -0
  66. rucio/core/did_meta_plugins/did_column_meta.py +331 -0
  67. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
  68. rucio/core/did_meta_plugins/filter_engine.py +613 -0
  69. rucio/core/did_meta_plugins/json_meta.py +240 -0
  70. rucio/core/did_meta_plugins/mongo_meta.py +216 -0
  71. rucio/core/did_meta_plugins/postgres_meta.py +316 -0
  72. rucio/core/dirac.py +237 -0
  73. rucio/core/distance.py +187 -0
  74. rucio/core/exporter.py +59 -0
  75. rucio/core/heartbeat.py +363 -0
  76. rucio/core/identity.py +300 -0
  77. rucio/core/importer.py +259 -0
  78. rucio/core/lifetime_exception.py +377 -0
  79. rucio/core/lock.py +576 -0
  80. rucio/core/message.py +282 -0
  81. rucio/core/meta_conventions.py +203 -0
  82. rucio/core/monitor.py +447 -0
  83. rucio/core/naming_convention.py +195 -0
  84. rucio/core/nongrid_trace.py +136 -0
  85. rucio/core/oidc.py +1461 -0
  86. rucio/core/permission/__init__.py +119 -0
  87. rucio/core/permission/atlas.py +1348 -0
  88. rucio/core/permission/belleii.py +1077 -0
  89. rucio/core/permission/escape.py +1078 -0
  90. rucio/core/permission/generic.py +1130 -0
  91. rucio/core/permission/generic_multi_vo.py +1150 -0
  92. rucio/core/quarantined_replica.py +223 -0
  93. rucio/core/replica.py +4158 -0
  94. rucio/core/replica_sorter.py +366 -0
  95. rucio/core/request.py +3089 -0
  96. rucio/core/rse.py +1875 -0
  97. rucio/core/rse_counter.py +186 -0
  98. rucio/core/rse_expression_parser.py +459 -0
  99. rucio/core/rse_selector.py +302 -0
  100. rucio/core/rule.py +4483 -0
  101. rucio/core/rule_grouping.py +1618 -0
  102. rucio/core/scope.py +180 -0
  103. rucio/core/subscription.py +364 -0
  104. rucio/core/topology.py +490 -0
  105. rucio/core/trace.py +375 -0
  106. rucio/core/transfer.py +1517 -0
  107. rucio/core/vo.py +169 -0
  108. rucio/core/volatile_replica.py +150 -0
  109. rucio/daemons/__init__.py +13 -0
  110. rucio/daemons/abacus/__init__.py +13 -0
  111. rucio/daemons/abacus/account.py +116 -0
  112. rucio/daemons/abacus/collection_replica.py +124 -0
  113. rucio/daemons/abacus/rse.py +117 -0
  114. rucio/daemons/atropos/__init__.py +13 -0
  115. rucio/daemons/atropos/atropos.py +242 -0
  116. rucio/daemons/auditor/__init__.py +289 -0
  117. rucio/daemons/auditor/hdfs.py +97 -0
  118. rucio/daemons/auditor/srmdumps.py +355 -0
  119. rucio/daemons/automatix/__init__.py +13 -0
  120. rucio/daemons/automatix/automatix.py +293 -0
  121. rucio/daemons/badreplicas/__init__.py +13 -0
  122. rucio/daemons/badreplicas/minos.py +322 -0
  123. rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
  124. rucio/daemons/badreplicas/necromancer.py +196 -0
  125. rucio/daemons/bb8/__init__.py +13 -0
  126. rucio/daemons/bb8/bb8.py +353 -0
  127. rucio/daemons/bb8/common.py +759 -0
  128. rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
  129. rucio/daemons/bb8/t2_background_rebalance.py +153 -0
  130. rucio/daemons/c3po/__init__.py +13 -0
  131. rucio/daemons/c3po/algorithms/__init__.py +13 -0
  132. rucio/daemons/c3po/algorithms/simple.py +134 -0
  133. rucio/daemons/c3po/algorithms/t2_free_space.py +128 -0
  134. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +130 -0
  135. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +294 -0
  136. rucio/daemons/c3po/c3po.py +371 -0
  137. rucio/daemons/c3po/collectors/__init__.py +13 -0
  138. rucio/daemons/c3po/collectors/agis.py +108 -0
  139. rucio/daemons/c3po/collectors/free_space.py +81 -0
  140. rucio/daemons/c3po/collectors/jedi_did.py +57 -0
  141. rucio/daemons/c3po/collectors/mock_did.py +51 -0
  142. rucio/daemons/c3po/collectors/network_metrics.py +71 -0
  143. rucio/daemons/c3po/collectors/workload.py +112 -0
  144. rucio/daemons/c3po/utils/__init__.py +13 -0
  145. rucio/daemons/c3po/utils/dataset_cache.py +50 -0
  146. rucio/daemons/c3po/utils/expiring_dataset_cache.py +56 -0
  147. rucio/daemons/c3po/utils/expiring_list.py +62 -0
  148. rucio/daemons/c3po/utils/popularity.py +85 -0
  149. rucio/daemons/c3po/utils/timeseries.py +89 -0
  150. rucio/daemons/cache/__init__.py +13 -0
  151. rucio/daemons/cache/consumer.py +197 -0
  152. rucio/daemons/common.py +415 -0
  153. rucio/daemons/conveyor/__init__.py +13 -0
  154. rucio/daemons/conveyor/common.py +562 -0
  155. rucio/daemons/conveyor/finisher.py +529 -0
  156. rucio/daemons/conveyor/poller.py +404 -0
  157. rucio/daemons/conveyor/preparer.py +205 -0
  158. rucio/daemons/conveyor/receiver.py +249 -0
  159. rucio/daemons/conveyor/stager.py +132 -0
  160. rucio/daemons/conveyor/submitter.py +403 -0
  161. rucio/daemons/conveyor/throttler.py +532 -0
  162. rucio/daemons/follower/__init__.py +13 -0
  163. rucio/daemons/follower/follower.py +101 -0
  164. rucio/daemons/hermes/__init__.py +13 -0
  165. rucio/daemons/hermes/hermes.py +774 -0
  166. rucio/daemons/judge/__init__.py +13 -0
  167. rucio/daemons/judge/cleaner.py +159 -0
  168. rucio/daemons/judge/evaluator.py +185 -0
  169. rucio/daemons/judge/injector.py +162 -0
  170. rucio/daemons/judge/repairer.py +154 -0
  171. rucio/daemons/oauthmanager/__init__.py +13 -0
  172. rucio/daemons/oauthmanager/oauthmanager.py +198 -0
  173. rucio/daemons/reaper/__init__.py +13 -0
  174. rucio/daemons/reaper/dark_reaper.py +278 -0
  175. rucio/daemons/reaper/reaper.py +743 -0
  176. rucio/daemons/replicarecoverer/__init__.py +13 -0
  177. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
  178. rucio/daemons/rsedecommissioner/__init__.py +13 -0
  179. rucio/daemons/rsedecommissioner/config.py +81 -0
  180. rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
  181. rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
  182. rucio/daemons/rsedecommissioner/profiles/generic.py +451 -0
  183. rucio/daemons/rsedecommissioner/profiles/types.py +92 -0
  184. rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
  185. rucio/daemons/storage/__init__.py +13 -0
  186. rucio/daemons/storage/consistency/__init__.py +13 -0
  187. rucio/daemons/storage/consistency/actions.py +846 -0
  188. rucio/daemons/tracer/__init__.py +13 -0
  189. rucio/daemons/tracer/kronos.py +536 -0
  190. rucio/daemons/transmogrifier/__init__.py +13 -0
  191. rucio/daemons/transmogrifier/transmogrifier.py +762 -0
  192. rucio/daemons/undertaker/__init__.py +13 -0
  193. rucio/daemons/undertaker/undertaker.py +137 -0
  194. rucio/db/__init__.py +13 -0
  195. rucio/db/sqla/__init__.py +52 -0
  196. rucio/db/sqla/constants.py +201 -0
  197. rucio/db/sqla/migrate_repo/__init__.py +13 -0
  198. rucio/db/sqla/migrate_repo/env.py +110 -0
  199. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
  200. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
  201. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
  202. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
  203. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
  204. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
  205. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
  206. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
  207. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
  208. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
  209. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
  210. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
  211. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
  212. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
  213. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
  214. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
  215. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
  216. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
  217. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
  218. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
  219. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
  220. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
  221. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
  222. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
  223. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
  224. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
  225. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
  226. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
  227. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
  228. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
  229. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
  230. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
  231. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
  232. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
  233. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
  234. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
  235. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
  236. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
  237. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
  238. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
  239. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
  240. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
  241. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
  242. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
  243. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
  244. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
  245. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
  246. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
  247. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
  248. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
  249. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
  250. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
  251. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
  252. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
  253. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
  254. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
  255. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
  256. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
  257. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
  258. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
  259. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
  260. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
  261. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
  262. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
  263. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
  264. rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
  265. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
  266. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
  267. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
  268. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
  269. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
  270. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
  271. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
  272. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
  273. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
  274. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
  275. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
  276. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
  277. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
  278. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
  279. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
  280. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
  281. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
  282. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
  283. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
  284. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
  285. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
  286. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
  287. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
  288. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
  289. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
  290. rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
  291. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
  292. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
  293. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
  294. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
  295. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
  296. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
  297. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
  298. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
  299. rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
  300. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
  301. rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
  302. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
  303. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
  304. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
  305. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
  306. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
  307. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
  308. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
  309. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
  310. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
  311. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
  312. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
  313. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
  314. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
  315. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
  316. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
  317. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
  318. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
  319. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
  320. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
  321. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
  322. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
  323. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
  324. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
  325. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
  326. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
  327. rucio/db/sqla/models.py +1740 -0
  328. rucio/db/sqla/sautils.py +55 -0
  329. rucio/db/sqla/session.py +498 -0
  330. rucio/db/sqla/types.py +206 -0
  331. rucio/db/sqla/util.py +543 -0
  332. rucio/gateway/__init__.py +13 -0
  333. rucio/gateway/account.py +339 -0
  334. rucio/gateway/account_limit.py +286 -0
  335. rucio/gateway/authentication.py +375 -0
  336. rucio/gateway/config.py +217 -0
  337. rucio/gateway/credential.py +71 -0
  338. rucio/gateway/did.py +970 -0
  339. rucio/gateway/dirac.py +81 -0
  340. rucio/gateway/exporter.py +59 -0
  341. rucio/gateway/heartbeat.py +74 -0
  342. rucio/gateway/identity.py +204 -0
  343. rucio/gateway/importer.py +45 -0
  344. rucio/gateway/lifetime_exception.py +120 -0
  345. rucio/gateway/lock.py +153 -0
  346. rucio/gateway/meta_conventions.py +87 -0
  347. rucio/gateway/permission.py +71 -0
  348. rucio/gateway/quarantined_replica.py +78 -0
  349. rucio/gateway/replica.py +529 -0
  350. rucio/gateway/request.py +321 -0
  351. rucio/gateway/rse.py +600 -0
  352. rucio/gateway/rule.py +417 -0
  353. rucio/gateway/scope.py +99 -0
  354. rucio/gateway/subscription.py +277 -0
  355. rucio/gateway/vo.py +122 -0
  356. rucio/rse/__init__.py +96 -0
  357. rucio/rse/protocols/__init__.py +13 -0
  358. rucio/rse/protocols/bittorrent.py +184 -0
  359. rucio/rse/protocols/cache.py +122 -0
  360. rucio/rse/protocols/dummy.py +111 -0
  361. rucio/rse/protocols/gfal.py +703 -0
  362. rucio/rse/protocols/globus.py +243 -0
  363. rucio/rse/protocols/gsiftp.py +92 -0
  364. rucio/rse/protocols/http_cache.py +82 -0
  365. rucio/rse/protocols/mock.py +123 -0
  366. rucio/rse/protocols/ngarc.py +209 -0
  367. rucio/rse/protocols/posix.py +250 -0
  368. rucio/rse/protocols/protocol.py +594 -0
  369. rucio/rse/protocols/rclone.py +364 -0
  370. rucio/rse/protocols/rfio.py +136 -0
  371. rucio/rse/protocols/srm.py +338 -0
  372. rucio/rse/protocols/ssh.py +413 -0
  373. rucio/rse/protocols/storm.py +206 -0
  374. rucio/rse/protocols/webdav.py +550 -0
  375. rucio/rse/protocols/xrootd.py +301 -0
  376. rucio/rse/rsemanager.py +764 -0
  377. rucio/tests/__init__.py +13 -0
  378. rucio/tests/common.py +270 -0
  379. rucio/tests/common_server.py +132 -0
  380. rucio/transfertool/__init__.py +13 -0
  381. rucio/transfertool/bittorrent.py +199 -0
  382. rucio/transfertool/bittorrent_driver.py +52 -0
  383. rucio/transfertool/bittorrent_driver_qbittorrent.py +133 -0
  384. rucio/transfertool/fts3.py +1596 -0
  385. rucio/transfertool/fts3_plugins.py +152 -0
  386. rucio/transfertool/globus.py +201 -0
  387. rucio/transfertool/globus_library.py +181 -0
  388. rucio/transfertool/mock.py +90 -0
  389. rucio/transfertool/transfertool.py +221 -0
  390. rucio/vcsversion.py +11 -0
  391. rucio/version.py +38 -0
  392. rucio/web/__init__.py +13 -0
  393. rucio/web/rest/__init__.py +13 -0
  394. rucio/web/rest/flaskapi/__init__.py +13 -0
  395. rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
  396. rucio/web/rest/flaskapi/v1/__init__.py +13 -0
  397. rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
  398. rucio/web/rest/flaskapi/v1/accounts.py +1089 -0
  399. rucio/web/rest/flaskapi/v1/archives.py +102 -0
  400. rucio/web/rest/flaskapi/v1/auth.py +1644 -0
  401. rucio/web/rest/flaskapi/v1/common.py +426 -0
  402. rucio/web/rest/flaskapi/v1/config.py +304 -0
  403. rucio/web/rest/flaskapi/v1/credentials.py +212 -0
  404. rucio/web/rest/flaskapi/v1/dids.py +2334 -0
  405. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  406. rucio/web/rest/flaskapi/v1/export.py +75 -0
  407. rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
  408. rucio/web/rest/flaskapi/v1/identities.py +261 -0
  409. rucio/web/rest/flaskapi/v1/import.py +132 -0
  410. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
  411. rucio/web/rest/flaskapi/v1/locks.py +358 -0
  412. rucio/web/rest/flaskapi/v1/main.py +91 -0
  413. rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
  414. rucio/web/rest/flaskapi/v1/metrics.py +36 -0
  415. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  416. rucio/web/rest/flaskapi/v1/ping.py +88 -0
  417. rucio/web/rest/flaskapi/v1/redirect.py +365 -0
  418. rucio/web/rest/flaskapi/v1/replicas.py +1890 -0
  419. rucio/web/rest/flaskapi/v1/requests.py +998 -0
  420. rucio/web/rest/flaskapi/v1/rses.py +2239 -0
  421. rucio/web/rest/flaskapi/v1/rules.py +854 -0
  422. rucio/web/rest/flaskapi/v1/scopes.py +159 -0
  423. rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
  424. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  425. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  426. rucio/web/rest/flaskapi/v1/traces.py +100 -0
  427. rucio/web/rest/flaskapi/v1/types.py +20 -0
  428. rucio/web/rest/flaskapi/v1/vos.py +278 -0
  429. rucio/web/rest/main.py +18 -0
  430. rucio/web/rest/metrics.py +27 -0
  431. rucio/web/rest/ping.py +27 -0
  432. rucio-35.7.0.data/data/rucio/etc/alembic.ini.template +71 -0
  433. rucio-35.7.0.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  434. rucio-35.7.0.data/data/rucio/etc/globus-config.yml.template +5 -0
  435. rucio-35.7.0.data/data/rucio/etc/ldap.cfg.template +30 -0
  436. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  437. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  438. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  439. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  440. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  441. rucio-35.7.0.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  442. rucio-35.7.0.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  443. rucio-35.7.0.data/data/rucio/etc/rucio.cfg.atlas.client.template +42 -0
  444. rucio-35.7.0.data/data/rucio/etc/rucio.cfg.template +257 -0
  445. rucio-35.7.0.data/data/rucio/etc/rucio_multi_vo.cfg.template +234 -0
  446. rucio-35.7.0.data/data/rucio/requirements.server.txt +268 -0
  447. rucio-35.7.0.data/data/rucio/tools/bootstrap.py +34 -0
  448. rucio-35.7.0.data/data/rucio/tools/merge_rucio_configs.py +144 -0
  449. rucio-35.7.0.data/data/rucio/tools/reset_database.py +40 -0
  450. rucio-35.7.0.data/scripts/rucio +2542 -0
  451. rucio-35.7.0.data/scripts/rucio-abacus-account +74 -0
  452. rucio-35.7.0.data/scripts/rucio-abacus-collection-replica +46 -0
  453. rucio-35.7.0.data/scripts/rucio-abacus-rse +78 -0
  454. rucio-35.7.0.data/scripts/rucio-admin +2447 -0
  455. rucio-35.7.0.data/scripts/rucio-atropos +60 -0
  456. rucio-35.7.0.data/scripts/rucio-auditor +205 -0
  457. rucio-35.7.0.data/scripts/rucio-automatix +50 -0
  458. rucio-35.7.0.data/scripts/rucio-bb8 +57 -0
  459. rucio-35.7.0.data/scripts/rucio-c3po +85 -0
  460. rucio-35.7.0.data/scripts/rucio-cache-client +134 -0
  461. rucio-35.7.0.data/scripts/rucio-cache-consumer +42 -0
  462. rucio-35.7.0.data/scripts/rucio-conveyor-finisher +58 -0
  463. rucio-35.7.0.data/scripts/rucio-conveyor-poller +66 -0
  464. rucio-35.7.0.data/scripts/rucio-conveyor-preparer +37 -0
  465. rucio-35.7.0.data/scripts/rucio-conveyor-receiver +43 -0
  466. rucio-35.7.0.data/scripts/rucio-conveyor-stager +76 -0
  467. rucio-35.7.0.data/scripts/rucio-conveyor-submitter +139 -0
  468. rucio-35.7.0.data/scripts/rucio-conveyor-throttler +104 -0
  469. rucio-35.7.0.data/scripts/rucio-dark-reaper +53 -0
  470. rucio-35.7.0.data/scripts/rucio-dumper +160 -0
  471. rucio-35.7.0.data/scripts/rucio-follower +44 -0
  472. rucio-35.7.0.data/scripts/rucio-hermes +54 -0
  473. rucio-35.7.0.data/scripts/rucio-judge-cleaner +89 -0
  474. rucio-35.7.0.data/scripts/rucio-judge-evaluator +137 -0
  475. rucio-35.7.0.data/scripts/rucio-judge-injector +44 -0
  476. rucio-35.7.0.data/scripts/rucio-judge-repairer +44 -0
  477. rucio-35.7.0.data/scripts/rucio-kronos +43 -0
  478. rucio-35.7.0.data/scripts/rucio-minos +53 -0
  479. rucio-35.7.0.data/scripts/rucio-minos-temporary-expiration +50 -0
  480. rucio-35.7.0.data/scripts/rucio-necromancer +120 -0
  481. rucio-35.7.0.data/scripts/rucio-oauth-manager +63 -0
  482. rucio-35.7.0.data/scripts/rucio-reaper +83 -0
  483. rucio-35.7.0.data/scripts/rucio-replica-recoverer +248 -0
  484. rucio-35.7.0.data/scripts/rucio-rse-decommissioner +66 -0
  485. rucio-35.7.0.data/scripts/rucio-storage-consistency-actions +74 -0
  486. rucio-35.7.0.data/scripts/rucio-transmogrifier +77 -0
  487. rucio-35.7.0.data/scripts/rucio-undertaker +76 -0
  488. rucio-35.7.0.dist-info/METADATA +72 -0
  489. rucio-35.7.0.dist-info/RECORD +493 -0
  490. rucio-35.7.0.dist-info/WHEEL +5 -0
  491. rucio-35.7.0.dist-info/licenses/AUTHORS.rst +97 -0
  492. rucio-35.7.0.dist-info/licenses/LICENSE +201 -0
  493. rucio-35.7.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,316 @@
1
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import json
16
+ import operator
17
+ from typing import TYPE_CHECKING
18
+
19
+ import psycopg2
20
+ import psycopg2.extras
21
+
22
+ from rucio.common import config, exception
23
+ from rucio.common.types import InternalScope
24
+ from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
25
+ from rucio.core.did_meta_plugins.filter_engine import FilterEngine
26
+
27
+ if TYPE_CHECKING:
28
+ from typing import Optional
29
+
30
+ from sqlalchemy.orm import Session
31
+
32
+
33
+ class ExternalPostgresDidMeta(DidMetaPlugin):
34
+ # TODO: column-based plugin? mixed-mode (json & columns)?
35
+ pass
36
+
37
+
38
+ class ExternalPostgresJSONDidMeta(DidMetaPlugin):
39
+ def __init__(self, host=None, port=None, db=None, user=None, password=None, db_schema=None, table=None,
40
+ table_is_managed=None, table_column_vo=None, table_column_scope=None, table_column_name=None,
41
+ table_column_data=None):
42
+ super(ExternalPostgresJSONDidMeta, self).__init__()
43
+ if host is None:
44
+ host = config.config_get('metadata', 'postgres_service_host')
45
+ if port is None:
46
+ port = config.config_get_int('metadata', 'postgres_service_port')
47
+ if db is None:
48
+ db = config.config_get('metadata', 'postgres_db')
49
+ if user is None:
50
+ user = config.config_get('metadata', 'postgres_user')
51
+ if password is None:
52
+ password = config.config_get('metadata', 'postgres_password')
53
+ if db_schema is None:
54
+ db_schema = config.config_get('metadata', 'postgres_db_schema', default='public')
55
+ if table is None:
56
+ table = config.config_get('metadata', 'postgres_table', default='dids')
57
+ if table_is_managed is None:
58
+ table_is_managed = config.config_get_bool('metadata', 'postgres_table_is_managed', default=False)
59
+ if table_column_vo is None:
60
+ table_column_vo = config.config_get('metadata', 'postgres_table_column_vo', default='vo')
61
+ if table_column_scope is None:
62
+ table_column_scope = config.config_get('metadata', 'postgres_table_column_scope', default='scope')
63
+ if table_column_name is None:
64
+ table_column_name = config.config_get('metadata', 'postgres_table_column_name', default='name')
65
+ if table_column_data is None:
66
+ table_column_data = config.config_get('metadata', 'postgres_table_column_data', default='data')
67
+
68
+ self.fixed_table_columns = {
69
+ 'vo': table_column_vo,
70
+ 'scope': table_column_scope,
71
+ 'name': table_column_name
72
+ }
73
+ self.jsonb_column = table_column_data
74
+
75
+ self.table = table
76
+ self.client = psycopg2.connect(
77
+ host=host,
78
+ port=port,
79
+ database=db,
80
+ user=user,
81
+ password=password)
82
+
83
+ # set search_path to include database schema by default
84
+ cur = self.client.cursor()
85
+ statement = "SET search_path TO {};".format(db_schema)
86
+ cur.execute(statement)
87
+ cur.close()
88
+
89
+ if not table_is_managed: # not managed by Rucio, so just verify table schema
90
+ self._verify_table_schema(table_column_vo, table_column_scope, table_column_name, table_column_data)
91
+ else: # managed by Rucio, create a metadata table if it doesn't exist
92
+ self._try_create_metadata_table()
93
+
94
+ self.plugin_name = "POSTGRES_JSON"
95
+
96
+ def _try_create_metadata_table(self):
97
+ """
98
+ Try to create a metadata table.
99
+ """
100
+ table_clauses = (
101
+ ("id", "bigint", "NOT NULL", "GENERATED ALWAYS AS IDENTITY"),
102
+ ("vo", "varchar", "NOT NULL"),
103
+ ("scope", "varchar", "NOT NULL"),
104
+ ("name", "varchar", "NOT NULL"),
105
+ ("data", "jsonb", "DEFAULT", "'{}'::jsonb"),
106
+ ("UNIQUE", "(scope, name)") # unique scope+name table constraint, required for ON CONFLICT
107
+ )
108
+ statement = "CREATE TABLE IF NOT EXISTS {} ({})".format(
109
+ self.table,
110
+ ', '.join([' '.join(clause) for clause in table_clauses]))
111
+
112
+ cur = self.client.cursor()
113
+ cur.execute(statement)
114
+ cur.close()
115
+ self.client.commit()
116
+
117
+ def _verify_table_schema(self, table_column_vo, table_column_scope, table_column_name, table_column_data):
118
+ """
119
+ Rudimentary verification that the metadata table schema meets the requirements for the plugin.
120
+
121
+ Should be called when using externally managed database tables as a sanity check.
122
+
123
+ :param table_column_vo: The table column used for the vo
124
+ :param table_column_scope: The table column used for the scope
125
+ :param table_column_name: The table column used for the name
126
+ :param table_column_data: The table column used for the data
127
+ :raises: MetadataSchemaMismatchError
128
+ """
129
+ # Check mandatory columns are of right data type and have the right nullable qualifier.
130
+ statement = "SELECT column_name, data_type, is_nullable " \
131
+ "FROM INFORMATION_SCHEMA.COLUMNS where table_name = '{}';".format(self.table)
132
+ cur = self.client.cursor()
133
+ cur.execute(statement)
134
+ existing_table_columns = cur.fetchall()
135
+ cur.close()
136
+
137
+ mandatory_column_specifications = [
138
+ (table_column_vo, "character varying", "NO"),
139
+ (table_column_scope, "character varying", "NO"),
140
+ (table_column_name, "character varying", "NO"),
141
+ (table_column_data, "jsonb", "YES")
142
+ ]
143
+ for specification in mandatory_column_specifications:
144
+ if specification not in existing_table_columns:
145
+ raise exception.MetadataSchemaMismatchError(
146
+ "mandatory table column {} does not match that defined in the required table schema {}".format(
147
+ specification, existing_table_columns))
148
+
149
+ # Check required table constraints exist.
150
+ statement = "SELECT con.contype AS constraint_type, " \
151
+ "(SELECT array_agg(att.attname) FROM pg_attribute att " \
152
+ " INNER JOIN unnest(con.conkey) unnest(conkey) ON unnest.conkey = att.attnum " \
153
+ " WHERE att.attrelid = con.conrelid) AS columns " \
154
+ "FROM pg_constraint con " \
155
+ "INNER JOIN pg_class rel ON rel.oid = con.conrelid " \
156
+ "INNER JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace " \
157
+ "WHERE rel.relname = '{}';".format(self.table)
158
+ cur = self.client.cursor()
159
+ cur.execute(statement)
160
+ existing_table_constraints = cur.fetchall() # list of (constraint_type, [columns])
161
+ cur.close()
162
+
163
+ mandatory_table_constraints = [
164
+ ("u", [table_column_scope, table_column_name]), # unique scope+name table constraint
165
+ ]
166
+ for constraint in mandatory_table_constraints:
167
+ if constraint not in existing_table_constraints:
168
+ raise exception.MetadataSchemaMismatchError(
169
+ "mandatory table constraint {} does not match that defined in the required table schema {}".format(
170
+ constraint, len(existing_table_constraints)))
171
+
172
+ def _drop_metadata_table(self):
173
+ statement = "DROP TABLE IF EXISTS {};".format(self.table)
174
+ cur = self.client.cursor()
175
+ cur.execute(statement)
176
+ cur.close()
177
+ self.client.commit()
178
+
179
+ def get_metadata(self, scope, name, *, session: "Optional[Session]" = None):
180
+ """
181
+ Get data identifier metadata.
182
+
183
+ :param scope: The scope name
184
+ :param name: The data identifier name
185
+ :param session: The database session in use
186
+ :returns: the metadata for the did
187
+ """
188
+ statement = "SELECT data from {} ".format(self.table) + \
189
+ "WHERE scope='{}' AND name='{}';".format(scope.internal, name)
190
+ cur = self.client.cursor()
191
+ cur.execute(statement)
192
+ metadata = cur.fetchone()
193
+ cur.close()
194
+
195
+ if not metadata:
196
+ raise exception.DataIdentifierNotFound("No metadata found for did '{}:{}".format(scope, name))
197
+
198
+ return metadata[0]
199
+
200
+ def set_metadata(self, scope, name, key, value, recursive=False, *, session: "Optional[Session]" = None):
201
+ """
202
+ Set single metadata key.
203
+
204
+ :param scope: the scope of did
205
+ :param name: the name of the did
206
+ :param key: the key to be added
207
+ :param value: the value of the key to be added
208
+ :param recursive: recurse into DIDs (not supported)
209
+ :param session: The database session in use
210
+ """
211
+ self.set_metadata_bulk(scope=scope, name=name, metadata={key: value}, recursive=recursive, session=session)
212
+
213
+ def set_metadata_bulk(self, scope, name, metadata, recursive=False, *, session: "Optional[Session]" = None):
214
+ """
215
+ Bulk set metadata keys.
216
+
217
+ :param scope: the scope of did
218
+ :param name: the name of the did
219
+ :param metadata: dictionary of metadata keypairs to be added
220
+ :param recursive: recurse into DIDs (not supported)
221
+ :param session: The database session in use
222
+ """
223
+ # upsert metadata
224
+ statement = "INSERT INTO {} (scope, name, vo, data) ".format(self.table) + \
225
+ "VALUES ('{}', '{}', '{}', '{}') ".format(scope.external, name, scope.vo, json.dumps(metadata)) + \
226
+ "ON CONFLICT (scope, name) DO UPDATE set data = {}.data || EXCLUDED.data;".format(self.table)
227
+ cur = self.client.cursor()
228
+ cur.execute(statement)
229
+ cur.close()
230
+ self.client.commit()
231
+
232
+ def delete_metadata(self, scope, name, key, *, session: "Optional[Session]" = None):
233
+ """
234
+ Delete a key from metadata.
235
+
236
+ :param scope: the scope of did
237
+ :param name: the name of the did
238
+ :param key: the key to be deleted
239
+ :param session: the database session in use
240
+ """
241
+ statement = "UPDATE {} ".format(self.table) + \
242
+ "SET data = {}.data - '{}';".format(self.table, key)
243
+ cur = self.client.cursor()
244
+ cur.execute(statement)
245
+ cur.close()
246
+ self.client.commit()
247
+
248
+ def list_dids(self, scope, filters, did_type='collection', ignore_case=False, limit=None,
249
+ offset=None, long=False, recursive=False, ignore_dids=None, *, session: "Optional[Session]" = None):
250
+
251
+ if not ignore_dids:
252
+ ignore_dids = set()
253
+
254
+ # backwards compatibility for filters as single {}.
255
+ if isinstance(filters, dict):
256
+ filters = [filters]
257
+
258
+ try:
259
+ # instantiate fe and create postgres query
260
+ fe = FilterEngine(filters, model_class=None, strict_coerce=False)
261
+ postgres_query_str = fe.create_postgres_query(
262
+ additional_filters=[
263
+ ('scope', operator.eq, scope.internal),
264
+ ('vo', operator.eq, scope.vo)
265
+ ],
266
+ fixed_table_columns=self.fixed_table_columns,
267
+ jsonb_column=self.jsonb_column
268
+ )
269
+ except Exception as e:
270
+ raise exception.DataIdentifierNotFound(e)
271
+
272
+ if recursive:
273
+ # TODO: possible, but requires retrieving the results of a concurrent sqla query to call list_content
274
+ # on for datasets and containers
275
+ raise exception.UnsupportedOperation(
276
+ "'{}' metadata module does not currently support recursive searches".format(self.plugin_name.lower())
277
+ )
278
+
279
+ statement = "SELECT * FROM {} WHERE {} ".format(self.table, postgres_query_str)
280
+ if limit:
281
+ statement += "LIMIT {}".format(limit)
282
+ cur = self.client.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
283
+ cur.execute(statement)
284
+ query_result = cur.fetchall()
285
+ cur.close()
286
+
287
+ if long:
288
+ for row in query_result:
289
+ did = "{}:{}".format(row['scope'], row['name'])
290
+ if did not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
291
+ ignore_dids.add(did)
292
+ yield {
293
+ 'scope': InternalScope(row['scope']),
294
+ 'name': row['name'],
295
+ 'did_type': "N/A",
296
+ 'bytes': "N/A",
297
+ 'length': "N/A"
298
+ }
299
+ else:
300
+ for row in query_result:
301
+ did = "{}:{}".format(row['scope'], row['name'])
302
+ if did not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
303
+ ignore_dids.add(did)
304
+ yield row['name']
305
+
306
+ def manages_key(self, key, *, session: "Optional[Session]" = None):
307
+ return True
308
+
309
+ def get_plugin_name(self):
310
+ """
311
+ Returns a unique identifier for this plugin. This can be later used for filtering down results to this
312
+ plugin only.
313
+
314
+ :returns: The name of the plugin
315
+ """
316
+ return self.plugin_name
rucio/core/dirac.py ADDED
@@ -0,0 +1,237 @@
1
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import re
16
+ from json import loads
17
+ from json.decoder import JSONDecodeError
18
+ from typing import TYPE_CHECKING, Any, Optional
19
+
20
+ from sqlalchemy import and_, select
21
+ from sqlalchemy.exc import NoResultFound
22
+
23
+ from rucio.common.config import config_get
24
+ from rucio.common.exception import ConfigNotFound, InvalidType, RucioException, UnsupportedOperation
25
+ from rucio.common.types import InternalAccount, InternalScope
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 read_session, transactional_session
34
+
35
+ if TYPE_CHECKING:
36
+ from collections.abc import Iterable
37
+
38
+ from sqlalchemy.orm import Session
39
+
40
+
41
+ @read_session
42
+ def _exists(
43
+ scope: str,
44
+ name: str,
45
+ *,
46
+ session: "Session"
47
+ ) -> tuple[bool, Optional[DIDType]]:
48
+ """
49
+ Check if the did exists
50
+
51
+ :scope: The scope
52
+ :name: The name
53
+ :session: The session used
54
+ """
55
+ try:
56
+ stmt = select(
57
+ models.DataIdentifier.did_type
58
+ ).with_hint(
59
+ models.DataIdentifier,
60
+ "INDEX(DIDS DIDS_PK)",
61
+ 'oracle'
62
+ ).where(
63
+ and_(models.DataIdentifier.scope == scope,
64
+ models.DataIdentifier.name == name)
65
+ )
66
+ return True, session.execute(stmt).scalar_one()
67
+ except NoResultFound:
68
+ return False, None
69
+
70
+
71
+ @transactional_session
72
+ def add_files(
73
+ lfns: "Iterable[dict[str, Any]]",
74
+ account: str,
75
+ ignore_availability: bool,
76
+ parents_metadata: Optional[dict[str, Any]] = None,
77
+ vo: str = 'def',
78
+ *,
79
+ session: "Session"
80
+ ) -> None:
81
+ """
82
+ Bulk add files :
83
+ - Create the file and replica.
84
+ - If doesn't exist create the dataset containing the file as well as a rule on the dataset on ANY sites.
85
+ - Create all the ascendants of the dataset if they do not exist
86
+
87
+ :param lfns: List of lfn (dictionary {'lfn': <lfn>, 'rse': <rse>, 'bytes': <bytes>, 'adler32': <adler32>, 'guid': <guid>, 'pfn': <pfn>}
88
+ :param issuer: The issuer account.
89
+ :param ignore_availability: A boolean to ignore blocklisted sites.
90
+ :param parents_metadata: Metadata for selected hierarchy DIDs. (dictionary {'lpn': {key : value}})
91
+ :param vo: The VO to act on
92
+ :param session: The session used
93
+ """
94
+ rule_extension_list = []
95
+ attachments = []
96
+ if not parents_metadata:
97
+ parents_metadata = {}
98
+ # The list of scopes is necessary for the extract_scope
99
+ filter_ = {'scope': InternalScope(scope='*', vo=vo)}
100
+ scopes = list_scopes(filter_=filter_, session=session)
101
+ scopes = [scope.external for scope in scopes]
102
+ exist_lfn = []
103
+ try:
104
+ config_lifetime: str = config_get(section='dirac', option='lifetime', default='{}', session=session)
105
+ lifetime_dict: dict = loads(config_lifetime)
106
+ except ConfigNotFound:
107
+ lifetime_dict = {}
108
+ except JSONDecodeError as err:
109
+ raise InvalidType('Problem parsing lifetime option in dirac section : %s' % str(err))
110
+ except Exception as err:
111
+ raise RucioException(str(err))
112
+
113
+ for lfn in lfns:
114
+ # First check if the file exists
115
+ filename = lfn['lfn']
116
+ lfn_scope, _ = extract_scope(filename, scopes)
117
+ lfn_scope = InternalScope(lfn_scope, vo=vo)
118
+
119
+ exists, did_type = _exists(lfn_scope, filename)
120
+ if exists:
121
+ continue
122
+
123
+ # Get all the ascendants of the file
124
+ lfn_split = filename.split('/')
125
+ lpns = ["/".join(lfn_split[:idx]) for idx in range(2, len(lfn_split))]
126
+ lpns.reverse()
127
+ print(lpns)
128
+
129
+ # The parent must be a dataset. Register it as well as the rule
130
+ dsn_name = lpns[0]
131
+ dsn_scope, _ = extract_scope(dsn_name, scopes)
132
+ dsn_scope = InternalScope(dsn_scope, vo=vo)
133
+ dsn_meta = parents_metadata.get(dsn_name, {})
134
+
135
+ # Compute lifetime
136
+ lifetime = None
137
+ if dsn_scope in lifetime_dict:
138
+ lifetime = lifetime_dict[dsn_scope.external]
139
+ else:
140
+ for pattern in lifetime_dict:
141
+ if dsn_scope.external and re.match(pattern, str(dsn_scope.external)):
142
+ lifetime = lifetime_dict[pattern]
143
+ break
144
+
145
+ exists, did_type = _exists(dsn_scope, dsn_name)
146
+ if exists and did_type == DIDType.CONTAINER:
147
+ raise UnsupportedOperation('Cannot create %s as dataset' % dsn_name)
148
+ if (dsn_name not in exist_lfn) and not exists:
149
+ print('Will create %s' % dsn_name)
150
+ # to maintain a compatibility between master and LTS-1.26 branches remove keywords for first 3 arguments
151
+ add_did(dsn_scope,
152
+ dsn_name,
153
+ DIDType.DATASET,
154
+ account=InternalAccount(account, vo=vo),
155
+ statuses=None,
156
+ meta=dsn_meta,
157
+ rules=[{'copies': 1, 'rse_expression': 'ANY=true', 'weight': None, 'account': InternalAccount(account, vo=vo), 'lifetime': lifetime, 'grouping': 'NONE'}],
158
+ lifetime=None,
159
+ dids=None,
160
+ rse_id=None,
161
+ session=session)
162
+ exist_lfn.append(dsn_name)
163
+ parent_name = lpns[1]
164
+ parent_scope, _ = extract_scope(parent_name, scopes)
165
+ parent_scope = InternalScope(parent_scope, vo=vo)
166
+ attachments.append({'scope': parent_scope, 'name': parent_name, 'dids': [{'scope': dsn_scope, 'name': dsn_name}]})
167
+ rule_extension_list.append((dsn_scope, dsn_name))
168
+ if lifetime and (dsn_scope, dsn_name) not in rule_extension_list:
169
+ # Reset the lifetime of the rule to the configured value
170
+ 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']
171
+ if rule:
172
+ update_rule(rule[0]['id'], options={'lifetime': lifetime}, session=session)
173
+ rule_extension_list.append((dsn_scope, dsn_name))
174
+
175
+ # Register the file
176
+ rse_id = lfn.get('rse_id', None)
177
+ if not rse_id:
178
+ raise InvalidType('Missing rse_id')
179
+ bytes_ = lfn.get('bytes', None)
180
+ guid = lfn.get('guid', None)
181
+ adler32 = lfn.get('adler32', None)
182
+ pfn = lfn.get('pfn', None)
183
+ meta = lfn.get('meta', {})
184
+ files = {'scope': lfn_scope, 'name': filename, 'bytes': bytes_, 'adler32': adler32, 'meta': meta}
185
+ if pfn:
186
+ files['pfn'] = str(pfn)
187
+ if guid:
188
+ files['meta']['guid'] = guid
189
+ add_replicas(rse_id=rse_id,
190
+ files=[files],
191
+ dataset_meta=None,
192
+ account=InternalAccount(account, vo=vo),
193
+ ignore_availability=ignore_availability,
194
+ session=session)
195
+ add_rule(dids=[{'scope': lfn_scope, 'name': filename}],
196
+ account=InternalAccount(account, vo=vo),
197
+ copies=1,
198
+ rse_expression=lfn['rse'],
199
+ grouping=None,
200
+ weight=None,
201
+ lifetime=86400,
202
+ locked=None,
203
+ subscription_id=None,
204
+ session=session)
205
+ attachments.append({'scope': dsn_scope, 'name': dsn_name, 'dids': [{'scope': lfn_scope, 'name': filename}]})
206
+
207
+ # Now loop over the ascendants of the dataset and created them
208
+ for lpn in lpns[1:]:
209
+ child_scope, _ = extract_scope(lpn, scopes)
210
+ child_scope = InternalScope(child_scope, vo=vo)
211
+ exists, did_type = _exists(child_scope, lpn)
212
+ child_meta = parents_metadata.get(lpn, {})
213
+ if exists and did_type == DIDType.DATASET:
214
+ raise UnsupportedOperation('Cannot create %s as container' % lpn)
215
+ if (lpn not in exist_lfn) and not exists:
216
+ print('Will create %s' % lpn)
217
+ add_did(child_scope,
218
+ lpn,
219
+ DIDType.CONTAINER,
220
+ account=InternalAccount(account, vo=vo),
221
+ statuses=None,
222
+ meta=child_meta,
223
+ rules=None,
224
+ lifetime=None,
225
+ dids=None,
226
+ rse_id=None,
227
+ session=session)
228
+ exist_lfn.append(lpn)
229
+ parent_name = lpns[lpns.index(lpn) + 1]
230
+ parent_scope, _ = extract_scope(parent_name, scopes)
231
+ parent_scope = InternalScope(parent_scope, vo=vo)
232
+ attachments.append({'scope': parent_scope, 'name': parent_name, 'dids': [{'scope': child_scope, 'name': lpn}]})
233
+ # Finally attach everything
234
+ attach_dids_to_dids(attachments,
235
+ account=InternalAccount(account, vo=vo),
236
+ ignore_duplicate=True,
237
+ session=session)