rucio 37.0.0rc1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (487) hide show
  1. rucio/__init__.py +17 -0
  2. rucio/alembicrevision.py +15 -0
  3. rucio/cli/__init__.py +14 -0
  4. rucio/cli/account.py +216 -0
  5. rucio/cli/bin_legacy/__init__.py +13 -0
  6. rucio/cli/bin_legacy/rucio.py +2825 -0
  7. rucio/cli/bin_legacy/rucio_admin.py +2500 -0
  8. rucio/cli/command.py +272 -0
  9. rucio/cli/config.py +72 -0
  10. rucio/cli/did.py +191 -0
  11. rucio/cli/download.py +128 -0
  12. rucio/cli/lifetime_exception.py +33 -0
  13. rucio/cli/replica.py +162 -0
  14. rucio/cli/rse.py +293 -0
  15. rucio/cli/rule.py +158 -0
  16. rucio/cli/scope.py +40 -0
  17. rucio/cli/subscription.py +73 -0
  18. rucio/cli/upload.py +60 -0
  19. rucio/cli/utils.py +226 -0
  20. rucio/client/__init__.py +15 -0
  21. rucio/client/accountclient.py +432 -0
  22. rucio/client/accountlimitclient.py +183 -0
  23. rucio/client/baseclient.py +983 -0
  24. rucio/client/client.py +120 -0
  25. rucio/client/configclient.py +126 -0
  26. rucio/client/credentialclient.py +59 -0
  27. rucio/client/didclient.py +868 -0
  28. rucio/client/diracclient.py +56 -0
  29. rucio/client/downloadclient.py +1783 -0
  30. rucio/client/exportclient.py +44 -0
  31. rucio/client/fileclient.py +50 -0
  32. rucio/client/importclient.py +42 -0
  33. rucio/client/lifetimeclient.py +90 -0
  34. rucio/client/lockclient.py +109 -0
  35. rucio/client/metaconventionsclient.py +140 -0
  36. rucio/client/pingclient.py +44 -0
  37. rucio/client/replicaclient.py +452 -0
  38. rucio/client/requestclient.py +125 -0
  39. rucio/client/richclient.py +317 -0
  40. rucio/client/rseclient.py +746 -0
  41. rucio/client/ruleclient.py +294 -0
  42. rucio/client/scopeclient.py +90 -0
  43. rucio/client/subscriptionclient.py +173 -0
  44. rucio/client/touchclient.py +82 -0
  45. rucio/client/uploadclient.py +969 -0
  46. rucio/common/__init__.py +13 -0
  47. rucio/common/bittorrent.py +234 -0
  48. rucio/common/cache.py +111 -0
  49. rucio/common/checksum.py +168 -0
  50. rucio/common/client.py +122 -0
  51. rucio/common/config.py +788 -0
  52. rucio/common/constants.py +217 -0
  53. rucio/common/constraints.py +17 -0
  54. rucio/common/didtype.py +237 -0
  55. rucio/common/dumper/__init__.py +342 -0
  56. rucio/common/dumper/consistency.py +497 -0
  57. rucio/common/dumper/data_models.py +362 -0
  58. rucio/common/dumper/path_parsing.py +75 -0
  59. rucio/common/exception.py +1208 -0
  60. rucio/common/extra.py +31 -0
  61. rucio/common/logging.py +420 -0
  62. rucio/common/pcache.py +1409 -0
  63. rucio/common/plugins.py +185 -0
  64. rucio/common/policy.py +93 -0
  65. rucio/common/schema/__init__.py +200 -0
  66. rucio/common/schema/generic.py +416 -0
  67. rucio/common/schema/generic_multi_vo.py +395 -0
  68. rucio/common/stomp_utils.py +423 -0
  69. rucio/common/stopwatch.py +55 -0
  70. rucio/common/test_rucio_server.py +154 -0
  71. rucio/common/types.py +483 -0
  72. rucio/common/utils.py +1688 -0
  73. rucio/core/__init__.py +13 -0
  74. rucio/core/account.py +496 -0
  75. rucio/core/account_counter.py +236 -0
  76. rucio/core/account_limit.py +425 -0
  77. rucio/core/authentication.py +620 -0
  78. rucio/core/config.py +437 -0
  79. rucio/core/credential.py +224 -0
  80. rucio/core/did.py +3004 -0
  81. rucio/core/did_meta_plugins/__init__.py +252 -0
  82. rucio/core/did_meta_plugins/did_column_meta.py +331 -0
  83. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
  84. rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
  85. rucio/core/did_meta_plugins/filter_engine.py +672 -0
  86. rucio/core/did_meta_plugins/json_meta.py +240 -0
  87. rucio/core/did_meta_plugins/mongo_meta.py +229 -0
  88. rucio/core/did_meta_plugins/postgres_meta.py +352 -0
  89. rucio/core/dirac.py +237 -0
  90. rucio/core/distance.py +187 -0
  91. rucio/core/exporter.py +59 -0
  92. rucio/core/heartbeat.py +363 -0
  93. rucio/core/identity.py +301 -0
  94. rucio/core/importer.py +260 -0
  95. rucio/core/lifetime_exception.py +377 -0
  96. rucio/core/lock.py +577 -0
  97. rucio/core/message.py +288 -0
  98. rucio/core/meta_conventions.py +203 -0
  99. rucio/core/monitor.py +448 -0
  100. rucio/core/naming_convention.py +195 -0
  101. rucio/core/nongrid_trace.py +136 -0
  102. rucio/core/oidc.py +1463 -0
  103. rucio/core/permission/__init__.py +161 -0
  104. rucio/core/permission/generic.py +1124 -0
  105. rucio/core/permission/generic_multi_vo.py +1144 -0
  106. rucio/core/quarantined_replica.py +224 -0
  107. rucio/core/replica.py +4483 -0
  108. rucio/core/replica_sorter.py +362 -0
  109. rucio/core/request.py +3091 -0
  110. rucio/core/rse.py +2079 -0
  111. rucio/core/rse_counter.py +185 -0
  112. rucio/core/rse_expression_parser.py +459 -0
  113. rucio/core/rse_selector.py +304 -0
  114. rucio/core/rule.py +4484 -0
  115. rucio/core/rule_grouping.py +1620 -0
  116. rucio/core/scope.py +181 -0
  117. rucio/core/subscription.py +362 -0
  118. rucio/core/topology.py +490 -0
  119. rucio/core/trace.py +375 -0
  120. rucio/core/transfer.py +1531 -0
  121. rucio/core/vo.py +169 -0
  122. rucio/core/volatile_replica.py +151 -0
  123. rucio/daemons/__init__.py +13 -0
  124. rucio/daemons/abacus/__init__.py +13 -0
  125. rucio/daemons/abacus/account.py +116 -0
  126. rucio/daemons/abacus/collection_replica.py +124 -0
  127. rucio/daemons/abacus/rse.py +117 -0
  128. rucio/daemons/atropos/__init__.py +13 -0
  129. rucio/daemons/atropos/atropos.py +242 -0
  130. rucio/daemons/auditor/__init__.py +289 -0
  131. rucio/daemons/auditor/hdfs.py +97 -0
  132. rucio/daemons/auditor/srmdumps.py +355 -0
  133. rucio/daemons/automatix/__init__.py +13 -0
  134. rucio/daemons/automatix/automatix.py +304 -0
  135. rucio/daemons/badreplicas/__init__.py +13 -0
  136. rucio/daemons/badreplicas/minos.py +322 -0
  137. rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
  138. rucio/daemons/badreplicas/necromancer.py +196 -0
  139. rucio/daemons/bb8/__init__.py +13 -0
  140. rucio/daemons/bb8/bb8.py +353 -0
  141. rucio/daemons/bb8/common.py +759 -0
  142. rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
  143. rucio/daemons/bb8/t2_background_rebalance.py +153 -0
  144. rucio/daemons/cache/__init__.py +13 -0
  145. rucio/daemons/cache/consumer.py +133 -0
  146. rucio/daemons/common.py +405 -0
  147. rucio/daemons/conveyor/__init__.py +13 -0
  148. rucio/daemons/conveyor/common.py +562 -0
  149. rucio/daemons/conveyor/finisher.py +529 -0
  150. rucio/daemons/conveyor/poller.py +394 -0
  151. rucio/daemons/conveyor/preparer.py +205 -0
  152. rucio/daemons/conveyor/receiver.py +179 -0
  153. rucio/daemons/conveyor/stager.py +133 -0
  154. rucio/daemons/conveyor/submitter.py +403 -0
  155. rucio/daemons/conveyor/throttler.py +532 -0
  156. rucio/daemons/follower/__init__.py +13 -0
  157. rucio/daemons/follower/follower.py +101 -0
  158. rucio/daemons/hermes/__init__.py +13 -0
  159. rucio/daemons/hermes/hermes.py +534 -0
  160. rucio/daemons/judge/__init__.py +13 -0
  161. rucio/daemons/judge/cleaner.py +159 -0
  162. rucio/daemons/judge/evaluator.py +185 -0
  163. rucio/daemons/judge/injector.py +162 -0
  164. rucio/daemons/judge/repairer.py +154 -0
  165. rucio/daemons/oauthmanager/__init__.py +13 -0
  166. rucio/daemons/oauthmanager/oauthmanager.py +198 -0
  167. rucio/daemons/reaper/__init__.py +13 -0
  168. rucio/daemons/reaper/dark_reaper.py +282 -0
  169. rucio/daemons/reaper/reaper.py +739 -0
  170. rucio/daemons/replicarecoverer/__init__.py +13 -0
  171. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
  172. rucio/daemons/rsedecommissioner/__init__.py +13 -0
  173. rucio/daemons/rsedecommissioner/config.py +81 -0
  174. rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
  175. rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
  176. rucio/daemons/rsedecommissioner/profiles/generic.py +452 -0
  177. rucio/daemons/rsedecommissioner/profiles/types.py +93 -0
  178. rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
  179. rucio/daemons/storage/__init__.py +13 -0
  180. rucio/daemons/storage/consistency/__init__.py +13 -0
  181. rucio/daemons/storage/consistency/actions.py +848 -0
  182. rucio/daemons/tracer/__init__.py +13 -0
  183. rucio/daemons/tracer/kronos.py +511 -0
  184. rucio/daemons/transmogrifier/__init__.py +13 -0
  185. rucio/daemons/transmogrifier/transmogrifier.py +762 -0
  186. rucio/daemons/undertaker/__init__.py +13 -0
  187. rucio/daemons/undertaker/undertaker.py +137 -0
  188. rucio/db/__init__.py +13 -0
  189. rucio/db/sqla/__init__.py +52 -0
  190. rucio/db/sqla/constants.py +206 -0
  191. rucio/db/sqla/migrate_repo/__init__.py +13 -0
  192. rucio/db/sqla/migrate_repo/env.py +110 -0
  193. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
  194. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
  195. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
  196. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
  197. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
  198. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
  199. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
  200. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
  201. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
  202. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
  203. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
  204. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
  205. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
  206. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
  207. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
  208. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
  209. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
  210. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
  211. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
  212. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
  213. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
  214. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
  215. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
  216. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
  217. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
  218. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
  219. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
  220. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
  221. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
  222. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
  223. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
  224. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
  225. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
  226. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
  227. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
  228. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
  229. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
  230. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
  231. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
  232. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
  233. rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
  234. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
  235. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
  236. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
  237. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
  238. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
  239. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
  240. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
  241. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
  242. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
  243. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
  244. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
  245. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
  246. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
  247. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
  248. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
  249. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
  250. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
  251. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
  252. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
  253. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
  254. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
  255. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
  256. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
  257. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
  258. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
  259. rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
  260. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
  261. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
  262. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
  263. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
  264. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
  265. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
  266. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
  267. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
  268. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
  269. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
  270. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
  271. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
  272. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
  273. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
  274. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
  275. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
  276. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
  277. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
  278. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
  279. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
  280. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
  281. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
  282. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
  283. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
  284. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
  285. rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
  286. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
  287. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
  288. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
  289. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
  290. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
  291. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
  292. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
  293. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
  294. rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
  295. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
  296. rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
  297. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
  298. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
  299. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
  300. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
  301. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
  302. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
  303. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
  304. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
  305. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
  306. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
  307. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
  308. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
  309. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
  310. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
  311. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
  312. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
  313. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
  314. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
  315. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
  316. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
  317. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
  318. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
  319. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
  320. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
  321. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
  322. rucio/db/sqla/models.py +1743 -0
  323. rucio/db/sqla/sautils.py +55 -0
  324. rucio/db/sqla/session.py +529 -0
  325. rucio/db/sqla/types.py +206 -0
  326. rucio/db/sqla/util.py +543 -0
  327. rucio/gateway/__init__.py +13 -0
  328. rucio/gateway/account.py +345 -0
  329. rucio/gateway/account_limit.py +363 -0
  330. rucio/gateway/authentication.py +381 -0
  331. rucio/gateway/config.py +227 -0
  332. rucio/gateway/credential.py +70 -0
  333. rucio/gateway/did.py +987 -0
  334. rucio/gateway/dirac.py +83 -0
  335. rucio/gateway/exporter.py +60 -0
  336. rucio/gateway/heartbeat.py +76 -0
  337. rucio/gateway/identity.py +189 -0
  338. rucio/gateway/importer.py +46 -0
  339. rucio/gateway/lifetime_exception.py +121 -0
  340. rucio/gateway/lock.py +153 -0
  341. rucio/gateway/meta_conventions.py +98 -0
  342. rucio/gateway/permission.py +74 -0
  343. rucio/gateway/quarantined_replica.py +79 -0
  344. rucio/gateway/replica.py +538 -0
  345. rucio/gateway/request.py +330 -0
  346. rucio/gateway/rse.py +632 -0
  347. rucio/gateway/rule.py +437 -0
  348. rucio/gateway/scope.py +100 -0
  349. rucio/gateway/subscription.py +280 -0
  350. rucio/gateway/vo.py +126 -0
  351. rucio/rse/__init__.py +96 -0
  352. rucio/rse/protocols/__init__.py +13 -0
  353. rucio/rse/protocols/bittorrent.py +194 -0
  354. rucio/rse/protocols/cache.py +111 -0
  355. rucio/rse/protocols/dummy.py +100 -0
  356. rucio/rse/protocols/gfal.py +708 -0
  357. rucio/rse/protocols/globus.py +243 -0
  358. rucio/rse/protocols/http_cache.py +82 -0
  359. rucio/rse/protocols/mock.py +123 -0
  360. rucio/rse/protocols/ngarc.py +209 -0
  361. rucio/rse/protocols/posix.py +250 -0
  362. rucio/rse/protocols/protocol.py +361 -0
  363. rucio/rse/protocols/rclone.py +365 -0
  364. rucio/rse/protocols/rfio.py +145 -0
  365. rucio/rse/protocols/srm.py +338 -0
  366. rucio/rse/protocols/ssh.py +414 -0
  367. rucio/rse/protocols/storm.py +195 -0
  368. rucio/rse/protocols/webdav.py +594 -0
  369. rucio/rse/protocols/xrootd.py +302 -0
  370. rucio/rse/rsemanager.py +881 -0
  371. rucio/rse/translation.py +260 -0
  372. rucio/tests/__init__.py +13 -0
  373. rucio/tests/common.py +280 -0
  374. rucio/tests/common_server.py +149 -0
  375. rucio/transfertool/__init__.py +13 -0
  376. rucio/transfertool/bittorrent.py +200 -0
  377. rucio/transfertool/bittorrent_driver.py +50 -0
  378. rucio/transfertool/bittorrent_driver_qbittorrent.py +134 -0
  379. rucio/transfertool/fts3.py +1600 -0
  380. rucio/transfertool/fts3_plugins.py +152 -0
  381. rucio/transfertool/globus.py +201 -0
  382. rucio/transfertool/globus_library.py +181 -0
  383. rucio/transfertool/mock.py +89 -0
  384. rucio/transfertool/transfertool.py +221 -0
  385. rucio/vcsversion.py +11 -0
  386. rucio/version.py +45 -0
  387. rucio/web/__init__.py +13 -0
  388. rucio/web/rest/__init__.py +13 -0
  389. rucio/web/rest/flaskapi/__init__.py +13 -0
  390. rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
  391. rucio/web/rest/flaskapi/v1/__init__.py +13 -0
  392. rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
  393. rucio/web/rest/flaskapi/v1/accounts.py +1103 -0
  394. rucio/web/rest/flaskapi/v1/archives.py +102 -0
  395. rucio/web/rest/flaskapi/v1/auth.py +1644 -0
  396. rucio/web/rest/flaskapi/v1/common.py +426 -0
  397. rucio/web/rest/flaskapi/v1/config.py +304 -0
  398. rucio/web/rest/flaskapi/v1/credentials.py +213 -0
  399. rucio/web/rest/flaskapi/v1/dids.py +2340 -0
  400. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  401. rucio/web/rest/flaskapi/v1/export.py +75 -0
  402. rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
  403. rucio/web/rest/flaskapi/v1/identities.py +285 -0
  404. rucio/web/rest/flaskapi/v1/import.py +132 -0
  405. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
  406. rucio/web/rest/flaskapi/v1/locks.py +358 -0
  407. rucio/web/rest/flaskapi/v1/main.py +91 -0
  408. rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
  409. rucio/web/rest/flaskapi/v1/metrics.py +36 -0
  410. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  411. rucio/web/rest/flaskapi/v1/ping.py +88 -0
  412. rucio/web/rest/flaskapi/v1/redirect.py +366 -0
  413. rucio/web/rest/flaskapi/v1/replicas.py +1894 -0
  414. rucio/web/rest/flaskapi/v1/requests.py +998 -0
  415. rucio/web/rest/flaskapi/v1/rses.py +2250 -0
  416. rucio/web/rest/flaskapi/v1/rules.py +854 -0
  417. rucio/web/rest/flaskapi/v1/scopes.py +159 -0
  418. rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
  419. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  420. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  421. rucio/web/rest/flaskapi/v1/traces.py +137 -0
  422. rucio/web/rest/flaskapi/v1/types.py +20 -0
  423. rucio/web/rest/flaskapi/v1/vos.py +278 -0
  424. rucio/web/rest/main.py +18 -0
  425. rucio/web/rest/metrics.py +27 -0
  426. rucio/web/rest/ping.py +27 -0
  427. rucio-37.0.0rc1.data/data/rucio/etc/alembic.ini.template +71 -0
  428. rucio-37.0.0rc1.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  429. rucio-37.0.0rc1.data/data/rucio/etc/globus-config.yml.template +5 -0
  430. rucio-37.0.0rc1.data/data/rucio/etc/ldap.cfg.template +30 -0
  431. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  432. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  433. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  434. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  435. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  436. rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  437. rucio-37.0.0rc1.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  438. rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.atlas.client.template +43 -0
  439. rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.template +241 -0
  440. rucio-37.0.0rc1.data/data/rucio/etc/rucio_multi_vo.cfg.template +217 -0
  441. rucio-37.0.0rc1.data/data/rucio/requirements.server.txt +297 -0
  442. rucio-37.0.0rc1.data/data/rucio/tools/bootstrap.py +34 -0
  443. rucio-37.0.0rc1.data/data/rucio/tools/merge_rucio_configs.py +144 -0
  444. rucio-37.0.0rc1.data/data/rucio/tools/reset_database.py +40 -0
  445. rucio-37.0.0rc1.data/scripts/rucio +133 -0
  446. rucio-37.0.0rc1.data/scripts/rucio-abacus-account +74 -0
  447. rucio-37.0.0rc1.data/scripts/rucio-abacus-collection-replica +46 -0
  448. rucio-37.0.0rc1.data/scripts/rucio-abacus-rse +78 -0
  449. rucio-37.0.0rc1.data/scripts/rucio-admin +97 -0
  450. rucio-37.0.0rc1.data/scripts/rucio-atropos +60 -0
  451. rucio-37.0.0rc1.data/scripts/rucio-auditor +206 -0
  452. rucio-37.0.0rc1.data/scripts/rucio-automatix +50 -0
  453. rucio-37.0.0rc1.data/scripts/rucio-bb8 +57 -0
  454. rucio-37.0.0rc1.data/scripts/rucio-cache-client +141 -0
  455. rucio-37.0.0rc1.data/scripts/rucio-cache-consumer +42 -0
  456. rucio-37.0.0rc1.data/scripts/rucio-conveyor-finisher +58 -0
  457. rucio-37.0.0rc1.data/scripts/rucio-conveyor-poller +66 -0
  458. rucio-37.0.0rc1.data/scripts/rucio-conveyor-preparer +37 -0
  459. rucio-37.0.0rc1.data/scripts/rucio-conveyor-receiver +44 -0
  460. rucio-37.0.0rc1.data/scripts/rucio-conveyor-stager +76 -0
  461. rucio-37.0.0rc1.data/scripts/rucio-conveyor-submitter +139 -0
  462. rucio-37.0.0rc1.data/scripts/rucio-conveyor-throttler +104 -0
  463. rucio-37.0.0rc1.data/scripts/rucio-dark-reaper +53 -0
  464. rucio-37.0.0rc1.data/scripts/rucio-dumper +160 -0
  465. rucio-37.0.0rc1.data/scripts/rucio-follower +44 -0
  466. rucio-37.0.0rc1.data/scripts/rucio-hermes +54 -0
  467. rucio-37.0.0rc1.data/scripts/rucio-judge-cleaner +89 -0
  468. rucio-37.0.0rc1.data/scripts/rucio-judge-evaluator +137 -0
  469. rucio-37.0.0rc1.data/scripts/rucio-judge-injector +44 -0
  470. rucio-37.0.0rc1.data/scripts/rucio-judge-repairer +44 -0
  471. rucio-37.0.0rc1.data/scripts/rucio-kronos +44 -0
  472. rucio-37.0.0rc1.data/scripts/rucio-minos +53 -0
  473. rucio-37.0.0rc1.data/scripts/rucio-minos-temporary-expiration +50 -0
  474. rucio-37.0.0rc1.data/scripts/rucio-necromancer +120 -0
  475. rucio-37.0.0rc1.data/scripts/rucio-oauth-manager +63 -0
  476. rucio-37.0.0rc1.data/scripts/rucio-reaper +83 -0
  477. rucio-37.0.0rc1.data/scripts/rucio-replica-recoverer +248 -0
  478. rucio-37.0.0rc1.data/scripts/rucio-rse-decommissioner +66 -0
  479. rucio-37.0.0rc1.data/scripts/rucio-storage-consistency-actions +74 -0
  480. rucio-37.0.0rc1.data/scripts/rucio-transmogrifier +77 -0
  481. rucio-37.0.0rc1.data/scripts/rucio-undertaker +76 -0
  482. rucio-37.0.0rc1.dist-info/METADATA +92 -0
  483. rucio-37.0.0rc1.dist-info/RECORD +487 -0
  484. rucio-37.0.0rc1.dist-info/WHEEL +5 -0
  485. rucio-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
  486. rucio-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
  487. rucio-37.0.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,152 @@
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 sys
17
+ from typing import TYPE_CHECKING, Any, Optional, TypeVar
18
+
19
+ from rucio.common.config import config_get_int
20
+ from rucio.common.exception import InvalidRequest
21
+ from rucio.common.plugins import PolicyPackageAlgorithms
22
+
23
+ if TYPE_CHECKING:
24
+ from collections.abc import Callable
25
+
26
+ FTS3TapeMetadataPluginType = TypeVar('FTS3TapeMetadataPluginType', bound='FTS3TapeMetadataPlugin')
27
+
28
+
29
+ class FTS3TapeMetadataPlugin(PolicyPackageAlgorithms):
30
+ """
31
+ Add a "archive_metadata" field to a file's transfer parameters.
32
+ Plugins are registered during initialization and called during a transfer with FTS3
33
+ """
34
+
35
+ ALGORITHM_NAME = "fts3_tape_metadata_plugins"
36
+ _INIT_FUNC_NAME = "fts3_plugins_init"
37
+ DEFAULT = "def"
38
+
39
+ def __init__(self, policy_algorithm: str) -> None:
40
+ """
41
+ :param policy_algorithm: policy algorithm identifier - choose from any of the policy package algorithms registered under the `fts3_tape_metadata_plugins` group.
42
+ """
43
+ super().__init__()
44
+ self.transfer_limit = config_get_int(
45
+ "transfers",
46
+ option="metadata_byte_limit",
47
+ raise_exception=False,
48
+ default=4096,
49
+ )
50
+
51
+ if not self._supports(self.ALGORITHM_NAME, policy_algorithm):
52
+ raise ValueError(f'Policy Algorithm {policy_algorithm} not found')
53
+
54
+ if self._supports(self._INIT_FUNC_NAME, policy_algorithm):
55
+ init_func = self._get_one_algorithm(self._INIT_FUNC_NAME, name=policy_algorithm)
56
+ init_func()
57
+
58
+ self.set_in_hints = self._get_one_algorithm(self.ALGORITHM_NAME, name=policy_algorithm)
59
+
60
+ @classmethod
61
+ def _module_init(cls: type[FTS3TapeMetadataPluginType]) -> None:
62
+ cls.register(cls.DEFAULT, func=lambda x: cls._default(cls, x)) # type: ignore
63
+
64
+ @classmethod
65
+ def register(cls: type[FTS3TapeMetadataPluginType], name: str, func: 'Callable', init_func: Optional['Callable'] = None) -> None:
66
+ """
67
+ Register a fts3 transfer plugin
68
+
69
+ :param name: name to register under
70
+ :param func: function called by the plugin
71
+ :param init_func: Initialization requirements for the plugin, defaults to None
72
+ """
73
+ super()._register(cls.ALGORITHM_NAME, algorithm_dict={name: func})
74
+ if init_func is not None:
75
+ super()._register(cls._INIT_FUNC_NAME, algorithm_dict={name: init_func})
76
+
77
+ @staticmethod
78
+ def _collocation(collocation_func: 'Callable', hints: dict[str, Any]) -> dict[str, dict]:
79
+ """
80
+ Wraps a 'collocation' style plugin for formatting
81
+
82
+ :param collocation_func: Function that defines the collocation rules
83
+ :param hints: kwargs utilized by the collocation rules
84
+ :return: Collocation hints produced by the collocation_func, wrapped
85
+ """
86
+ return {"collocation_hints": collocation_func(**hints)}
87
+
88
+ def _default(self, *hints: dict) -> dict:
89
+ return {}
90
+
91
+ def _verify_in_format(self, hint_dict: dict[str, Any]) -> None:
92
+ """Check the to-be-submitted file transfer params are both json encodable and under the size limit for transfer"""
93
+ try:
94
+ hints_json = json.dumps(hint_dict)
95
+ in_tranfer_limit = sys.getsizeof(hints_json) < self.transfer_limit
96
+
97
+ except TypeError as e:
98
+ raise InvalidRequest("Request malformed, cannot encode to JSON", e)
99
+
100
+ if not in_tranfer_limit:
101
+ raise InvalidRequest(
102
+ f"Request too large, decrease to less than {self.transfer_limit}"
103
+ )
104
+
105
+ def hints(self, hint_kwargs: dict) -> dict[str, Any]:
106
+ """
107
+ Produce "archive_metadata" hints for how a transfer should be executed by fts3.
108
+
109
+ :param hint_kwargs: Args passed forward to the plugin algorithm
110
+ :return: Archiving metadata in the format {archive_metadata: {<plugin produced hints>}}
111
+ """
112
+ hints = self.set_in_hints(hint_kwargs)
113
+ self._verify_in_format(hints)
114
+ return {"archive_metadata": hints}
115
+
116
+
117
+ class ActivityBasedTransferPriorityPlugin(FTS3TapeMetadataPlugin):
118
+ def __init__(self, policy_algorithm: str = 'activity') -> None:
119
+ self.register(
120
+ policy_algorithm,
121
+ func=lambda x: self._get_activity_priority(x),
122
+ init_func=self._init_default_priority)
123
+ super().__init__(policy_algorithm)
124
+
125
+ def _init_default_priority(self) -> None:
126
+ self.default_priority = config_get_int(
127
+ "tape_priority",
128
+ option="default",
129
+ raise_exception=False,
130
+ default=20,
131
+ )
132
+
133
+ def _get_activity_priority(self, activity_kwargs: dict[str, str]) -> dict[str, dict]:
134
+ """ Activity Hints - assign a priority based on activity"""
135
+ if "activity" in activity_kwargs:
136
+ activity = activity_kwargs["activity"]
137
+ else:
138
+ raise InvalidRequest("`activity` field not found in passed metadata")
139
+
140
+ priority = config_get_int(
141
+ "tape_priority",
142
+ option=activity,
143
+ raise_exception=False,
144
+ default=self.default_priority,
145
+ )
146
+
147
+ return {"scheduling_hints": {"priority": priority}}
148
+
149
+
150
+ # Register the policies
151
+ FTS3TapeMetadataPlugin._module_init()
152
+ ActivityBasedTransferPriorityPlugin()
@@ -0,0 +1,201 @@
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 logging
16
+
17
+ from rucio.common.constants import RseAttr
18
+ from rucio.common.utils import chunks
19
+ from rucio.db.sqla.constants import RequestState
20
+ from rucio.transfertool.transfertool import TransferStatusReport, Transfertool, TransferToolBuilder
21
+
22
+ from .globus_library import bulk_check_xfers, bulk_submit_xfer, submit_xfer
23
+
24
+
25
+ def bulk_group_transfers(transfer_paths, policy='single', group_bulk=200):
26
+ """
27
+ Group transfers in bulk based on certain criteria
28
+
29
+ :param transfer_paths: List of (potentially multihop) transfer paths to group. Each path is a list of single-hop transfers.
30
+ :param policy: Policy to use to group.
31
+ :param group_bulk: Bulk sizes.
32
+ :return: List of transfer groups
33
+ """
34
+ if policy == 'single':
35
+ group_bulk = 1
36
+
37
+ grouped_jobs = []
38
+ for chunk in chunks(transfer_paths, group_bulk):
39
+ # Globus doesn't support multihop. Get the first hop only.
40
+ transfers = [transfer_path[0] for transfer_path in chunk]
41
+
42
+ grouped_jobs.append({
43
+ 'transfers': transfers,
44
+ # Job params are not used by globus transfertool, but are needed for further common fts/globus code
45
+ 'job_params': {}
46
+ })
47
+
48
+ return grouped_jobs
49
+
50
+
51
+ class GlobusTransferStatusReport(TransferStatusReport):
52
+
53
+ supported_db_fields = [
54
+ 'state',
55
+ 'external_id',
56
+ ]
57
+
58
+ def __init__(self, request_id, external_id, globus_response):
59
+ super().__init__(request_id)
60
+
61
+ if globus_response == 'FAILED':
62
+ new_state = RequestState.FAILED
63
+ elif globus_response == 'SUCCEEDED':
64
+ new_state = RequestState.DONE
65
+ else:
66
+ new_state = RequestState.SUBMITTED
67
+
68
+ self.state = new_state
69
+ self.external_id = None
70
+ if new_state in [RequestState.FAILED, RequestState.DONE]:
71
+ self.external_id = external_id
72
+
73
+ def initialize(self, session, logger=logging.log):
74
+ pass
75
+
76
+ def get_monitor_msg_fields(self, session, logger=logging.log):
77
+ return {'protocol': 'globus'}
78
+
79
+
80
+ class GlobusTransferTool(Transfertool):
81
+ """
82
+ Globus implementation of Transfertool abstract base class
83
+ """
84
+
85
+ external_name = 'globus'
86
+ required_rse_attrs = (RseAttr.GLOBUS_ENDPOINT_ID, )
87
+
88
+ def __init__(self, external_host, logger=logging.log, group_bulk=200, group_policy='single'):
89
+ """
90
+ Initializes the transfertool
91
+
92
+ :param external_host: The external host where the transfertool API is running
93
+ """
94
+ if not external_host:
95
+ external_host = 'Globus Online Transfertool'
96
+ super().__init__(external_host, logger)
97
+ self.group_bulk = group_bulk
98
+ self.group_policy = group_policy
99
+ # TODO: initialize vars from config file here
100
+
101
+ @classmethod
102
+ def submission_builder_for_path(cls, transfer_path, logger=logging.log):
103
+ hop = transfer_path[0]
104
+ if not cls.can_perform_transfer(hop.src.rse, hop.dst.rse):
105
+ logger(logging.WARNING, "Source or destination globus_endpoint_id not set. Skipping {}".format(hop))
106
+ return [], None
107
+
108
+ return [hop], TransferToolBuilder(cls, external_host='Globus Online Transfertool')
109
+
110
+ def group_into_submit_jobs(self, transfer_paths):
111
+ jobs = bulk_group_transfers(transfer_paths, policy=self.group_policy, group_bulk=self.group_bulk)
112
+ return jobs
113
+
114
+ def submit_one(self, files, timeout=None):
115
+ """
116
+ Submit transfers to globus API
117
+
118
+ :param files: List of dictionaries describing the file transfers.
119
+ :param job_params: Dictionary containing key/value pairs, for all transfers.
120
+ :param timeout: Timeout in seconds.
121
+ :returns: Globus transfer identifier.
122
+ """
123
+
124
+ source_path = files[0]['sources'][0]
125
+ self.logger(logging.INFO, 'source_path: %s' % source_path)
126
+
127
+ source_endpoint_id = files[0]['metadata']['source_globus_endpoint_id']
128
+
129
+ # TODO: use prefix from rse_protocol to properly construct destination url
130
+ # parse and assemble dest_path for Globus endpoint
131
+ dest_path = files[0]['destinations'][0]
132
+ self.logger(logging.INFO, 'dest_path: %s' % dest_path)
133
+
134
+ # TODO: rucio.common.utils.construct_url logic adds unnecessary '/other' into file path
135
+ # s = dest_path.split('/') # s.remove('other') # dest_path = '/'.join(s)
136
+
137
+ destination_endpoint_id = files[0]['metadata']['dest_globus_endpoint_id']
138
+ job_label = files[0]['metadata']['request_id']
139
+
140
+ task_id = submit_xfer(source_endpoint_id, destination_endpoint_id, source_path, dest_path, job_label, recursive=False, logger=self.logger)
141
+
142
+ return task_id
143
+
144
+ def submit(self, transfers, job_params, timeout=None):
145
+ """
146
+ Submit a bulk transfer to globus API
147
+
148
+ :param transfers: List of dictionaries describing the file transfers.
149
+ :param job_params: Not used by Globus Transfsertool
150
+ :param timeout: Timeout in seconds.
151
+ :returns: Globus transfer identifier.
152
+ """
153
+
154
+ # TODO: support passing a recursive parameter to Globus
155
+ submitjob = [
156
+ {
157
+ # Some dict elements are not needed by globus transfertool, but are accessed by further common fts/globus code
158
+ 'sources': [transfer.source_url(s) for s in transfer.sources],
159
+ 'destinations': [transfer.dest_url],
160
+ 'metadata': {
161
+ 'src_rse': transfer.src.rse.name,
162
+ 'dst_rse': transfer.dst.rse.name,
163
+ 'scope': str(transfer.rws.scope),
164
+ 'name': transfer.rws.name,
165
+ 'source_globus_endpoint_id': transfer.src.rse.attributes[RseAttr.GLOBUS_ENDPOINT_ID],
166
+ 'dest_globus_endpoint_id': transfer.dst.rse.attributes[RseAttr.GLOBUS_ENDPOINT_ID],
167
+ 'filesize': transfer.rws.byte_count,
168
+ },
169
+ }
170
+ for transfer in transfers
171
+ ]
172
+ self.logger(logging.DEBUG, '... Starting globus xfer ...')
173
+ self.logger(logging.DEBUG, 'job_files: %s' % submitjob)
174
+ task_id = bulk_submit_xfer(submitjob, recursive=False, logger=self.logger)
175
+
176
+ return task_id
177
+
178
+ def bulk_query(self, requests_by_eid, timeout=None):
179
+ """
180
+ Query the status of a bulk of transfers in globus API
181
+
182
+ :param requests_by_eid: dictionary {external_id1: {request_id1: request1, ...}, ...}
183
+ :returns: Transfer status information as a dictionary.
184
+ """
185
+
186
+ job_responses = bulk_check_xfers(requests_by_eid, logger=self.logger)
187
+
188
+ response = {}
189
+ for transfer_id, requests in requests_by_eid.items():
190
+ for request_id in requests:
191
+ response.setdefault(transfer_id, {})[request_id] = GlobusTransferStatusReport(request_id, transfer_id, job_responses[transfer_id])
192
+ return response
193
+
194
+ def bulk_update(self, resps, request_ids):
195
+ pass
196
+
197
+ def cancel(self):
198
+ pass
199
+
200
+ def update_priority(self):
201
+ pass
@@ -0,0 +1,181 @@
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 datetime
16
+ import logging
17
+ import os
18
+
19
+ from rucio.common.config import config_get, config_get_int, get_config_dirs
20
+ from rucio.common.extra import import_extras
21
+ from rucio.core.monitor import MetricManager
22
+
23
+ EXTRA_MODULES = import_extras(['globus_sdk'])
24
+
25
+ if EXTRA_MODULES['globus_sdk']:
26
+ import yaml # pylint: disable=import-error
27
+ from globus_sdk import DeleteData, NativeAppAuthClient, RefreshTokenAuthorizer, TransferClient, TransferData # pylint: disable=import-error
28
+
29
+ METRICS = MetricManager(module=__name__)
30
+
31
+ GLOBUS_AUTH_APP = config_get('conveyor', 'globus_auth_app', False, None)
32
+
33
+
34
+ def load_config(cfg_file='globus-config.yml', logger=logging.log):
35
+ config = None
36
+ config_dir = get_config_dirs()[0]
37
+ if os.path.isfile(os.path.join(config_dir, cfg_file)):
38
+ config = os.path.join(config_dir, cfg_file)
39
+ else:
40
+ logger(logging.ERROR, 'Could not find globus config file')
41
+ raise Exception
42
+ return yaml.safe_load(open(config).read())
43
+
44
+
45
+ def get_transfer_client(logger=logging.log):
46
+ cfg = load_config(logger=logger)
47
+ # cfg = yaml.safe_load(open("/opt/rucio/lib/rucio/transfertool/config.yml"))
48
+ client_id = cfg['globus']['apps'][GLOBUS_AUTH_APP]['client_id']
49
+ auth_client = NativeAppAuthClient(client_id)
50
+ refresh_token = cfg['globus']['apps'][GLOBUS_AUTH_APP]['refresh_token']
51
+ logger(logging.INFO, 'authorizing token...')
52
+ authorizer = RefreshTokenAuthorizer(refresh_token=refresh_token, auth_client=auth_client)
53
+ logger(logging.INFO, 'initializing TransferClient...')
54
+ tc = TransferClient(authorizer=authorizer)
55
+ return tc
56
+
57
+
58
+ def auto_activate_endpoint(tc, ep_id, logger=logging.log):
59
+ r = tc.endpoint_autoactivate(ep_id, if_expires_in=3600)
60
+ if r['code'] == 'AutoActivationFailed':
61
+ logger(logging.CRITICAL, 'Endpoint({}) Not Active! Error! Source message: {}'.format(ep_id, r['message']))
62
+ # sys.exit(1) # TODO: don't want to exit; hook into graceful exit
63
+ elif r['code'] == 'AutoActivated.CachedCredential':
64
+ logger(logging.INFO, 'Endpoint({}) autoactivated using a cached credential.'.format(ep_id))
65
+ elif r['code'] == 'AutoActivated.GlobusOnlineCredential':
66
+ logger(logging.INFO, ('Endpoint({}) autoactivated using a built-in Globus credential.').format(ep_id))
67
+ elif r['code'] == 'AlreadyActivated':
68
+ logger(logging.INFO, 'Endpoint({}) already active until at least {}'.format(ep_id, 3600))
69
+ return r['code']
70
+
71
+
72
+ def submit_xfer(source_endpoint_id, destination_endpoint_id, source_path, dest_path, job_label, recursive=False, logger=logging.log):
73
+ tc = get_transfer_client(logger=logger)
74
+ # as both endpoints are expected to be Globus Server endpoints, send auto-activate commands for both globus endpoints
75
+ auto_activate_endpoint(tc, source_endpoint_id, logger=logger)
76
+ auto_activate_endpoint(tc, destination_endpoint_id, logger=logger)
77
+
78
+ # from Globus... sync_level=checksum means that before files are transferred, Globus will compute checksums on the source and
79
+ # destination files, and only transfer files that have different checksums are transferred. verify_checksum=True means that after
80
+ # a file is transferred, Globus will compute checksums on the source and destination files to verify that the file was transferred
81
+ # correctly. If the checksums do not match, it will redo the transfer of that file.
82
+ # tdata = TransferData(tc, source_endpoint_id, destination_endpoint_id, label=job_label, sync_level="checksum", verify_checksum=True)
83
+ tdata = TransferData(tc, source_endpoint_id, destination_endpoint_id, label=job_label,
84
+ sync_level="checksum", notify_on_succeeded=False, notify_on_failed=False)
85
+ tdata.add_item(source_path, dest_path, recursive=recursive)
86
+
87
+ # logging.info('submitting transfer...')
88
+ transfer_result = tc.submit_transfer(tdata)
89
+ # logging.info("task_id =", transfer_result["task_id"])
90
+
91
+ return transfer_result["task_id"]
92
+
93
+
94
+ def bulk_submit_xfer(submitjob, recursive=False, logger=logging.log):
95
+ cfg = load_config(logger=logger)
96
+ client_id = cfg['globus']['apps'][GLOBUS_AUTH_APP]['client_id']
97
+ auth_client = NativeAppAuthClient(client_id)
98
+ refresh_token = cfg['globus']['apps'][GLOBUS_AUTH_APP]['refresh_token']
99
+ source_endpoint_id = submitjob[0].get('metadata').get('source_globus_endpoint_id')
100
+ destination_endpoint_id = submitjob[0].get('metadata').get('dest_globus_endpoint_id')
101
+ authorizer = RefreshTokenAuthorizer(refresh_token=refresh_token, auth_client=auth_client)
102
+ tc = TransferClient(authorizer=authorizer)
103
+
104
+ # make job_label for task a timestamp
105
+ now = datetime.datetime.utcnow()
106
+ job_label = now.strftime('%Y%m%d%H%M%s')
107
+
108
+ # retrieve globus_task_deadline value to enforce time window to complete transfers
109
+ # default is 2880 minutes or 48 hours
110
+ globus_task_deadline = config_get_int('conveyor', 'globus_task_deadline', False, 2880)
111
+ deadline = now + datetime.timedelta(minutes=globus_task_deadline)
112
+
113
+ # from Globus... sync_level=checksum means that before files are transferred, Globus will compute checksums on the source
114
+ # and destination files, and only transfer files that have different checksums are transferred. verify_checksum=True means
115
+ # that after a file is transferred, Globus will compute checksums on the source and destination files to verify that the
116
+ # file was transferred correctly. If the checksums do not match, it will redo the transfer of that file.
117
+ tdata = TransferData(tc, source_endpoint_id, destination_endpoint_id, label=job_label, sync_level="checksum", deadline=str(deadline))
118
+
119
+ for file in submitjob:
120
+ source_path = file.get('sources')[0]
121
+ dest_path = file.get('destinations')[0]
122
+ filesize = file['metadata']['filesize']
123
+ # TODO: support passing a recursive parameter to Globus
124
+ # md5 = file['metadata']['md5']
125
+ # tdata.add_item(source_path, dest_path, recursive=False, external_checksum=md5)
126
+ tdata.add_item(source_path, dest_path, recursive=False)
127
+ METRICS.counter('submit.filesize').inc(filesize)
128
+
129
+ # logging.info('submitting transfer...')
130
+ transfer_result = tc.submit_transfer(tdata)
131
+ logger(logging.INFO, "transfer_result: %s" % transfer_result)
132
+
133
+ return transfer_result["task_id"]
134
+
135
+
136
+ def check_xfer(task_id, logger=logging.log):
137
+ tc = get_transfer_client(logger=logger)
138
+ transfer = tc.get_task(task_id)
139
+ status = str(transfer["status"])
140
+ return status
141
+
142
+
143
+ def bulk_check_xfers(task_ids, logger=logging.log):
144
+ tc = get_transfer_client(logger=logger)
145
+
146
+ logger(logging.DEBUG, 'task_ids: %s' % task_ids)
147
+
148
+ responses = {}
149
+
150
+ for task_id in task_ids:
151
+ transfer = tc.get_task(str(task_id))
152
+ logger(logging.DEBUG, 'transfer: %s' % transfer)
153
+ status = str(transfer["status"])
154
+ if status == 'SUCCEEDED':
155
+ METRICS.counter('bytes_transferred').inc(transfer['bytes_transferred'])
156
+ METRICS.counter('effective_bytes_per_second').inc(transfer['effective_bytes_per_second'])
157
+ responses[str(task_id)] = status
158
+
159
+ logger(logging.DEBUG, 'responses: %s' % responses)
160
+
161
+ return responses
162
+
163
+
164
+ def send_delete_task(endpoint_id=None, path=None, logger=logging.log):
165
+ tc = get_transfer_client(logger=logger)
166
+ ddata = DeleteData(tc, endpoint_id, recursive=True)
167
+ ddata.add_item(path)
168
+ delete_result = tc.submit_delete(ddata)
169
+
170
+ return delete_result
171
+
172
+
173
+ def send_bulk_delete_task(endpoint_id=None, pfns=None, logger=logging.log):
174
+ tc = get_transfer_client(logger=logger)
175
+ ddata = DeleteData(tc, endpoint_id, recursive=True)
176
+ for pfn in pfns:
177
+ logger(logging.DEBUG, 'pfn: %s' % pfn)
178
+ ddata.add_item(pfn)
179
+ bulk_delete_result = tc.submit_delete(ddata)
180
+
181
+ return bulk_delete_result
@@ -0,0 +1,89 @@
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 itertools
16
+ import logging
17
+ import uuid
18
+ from typing import TYPE_CHECKING, Any, Optional
19
+
20
+ from rucio.db.sqla.constants import RequestState
21
+ from rucio.transfertool.transfertool import TransferStatusReport, Transfertool, TransferToolBuilder
22
+
23
+ if TYPE_CHECKING:
24
+ from collections.abc import Iterable, Mapping, Sequence
25
+
26
+ from rucio.common.types import LoggerFunction
27
+ from rucio.core.request import DirectTransfer
28
+ from rucio.db.sqla.session import Session
29
+
30
+
31
+ class MockTransferStatusReport(TransferStatusReport):
32
+
33
+ supported_db_fields = [
34
+ 'state',
35
+ 'external_id'
36
+ ]
37
+
38
+ def __init__(self, request_id: str, external_id: str):
39
+ super().__init__(request_id)
40
+ self.state = RequestState.DONE
41
+ self.external_id = external_id
42
+
43
+ def initialize(self, session: "Session", logger: "LoggerFunction" = logging.log) -> None:
44
+ pass
45
+
46
+ def get_monitor_msg_fields(self, session: "Session", logger: "LoggerFunction" = logging.log) -> dict[str, Any]:
47
+ return {}
48
+
49
+
50
+ class MockTransfertool(Transfertool):
51
+ """
52
+ Mock implementation of a Rucio transfertool
53
+
54
+ This is not actually used anywhere at the moment
55
+ """
56
+
57
+ external_name = 'mock'
58
+ required_rse_attrs = ()
59
+ supported_schemes = {'mock', 'file'}
60
+
61
+ def __init__(self, external_host: str, logger: "LoggerFunction" = logging.log):
62
+ super(MockTransfertool, self).__init__(external_host, logger)
63
+
64
+ @classmethod
65
+ def submission_builder_for_path(
66
+ cls,
67
+ transfer_path: list["DirectTransfer"],
68
+ logger: "LoggerFunction" = logging.log
69
+ ) -> tuple[list["DirectTransfer"], "TransferToolBuilder"]:
70
+ return transfer_path, TransferToolBuilder(cls, external_host='Mock Transfertool')
71
+
72
+ def group_into_submit_jobs(self, transfers: "Iterable[list[DirectTransfer]]") -> list[dict[str, Any]]:
73
+ return [{'transfers': list(itertools.chain.from_iterable(transfers)), 'job_params': {}}]
74
+
75
+ def submit(self, transfers: "Iterable[DirectTransfer]", job_params: dict[str, str], timeout: Optional[int] = None) -> str:
76
+ return str(uuid.uuid1())
77
+
78
+ def bulk_query(self, requests_by_eid: "Mapping[str, Mapping[str, Any]]", timeout: Optional[int] = None) -> dict[str, dict[str, MockTransferStatusReport]]:
79
+ response = {}
80
+ for transfer_id, requests in requests_by_eid.items():
81
+ for request_id in requests:
82
+ response.setdefault(transfer_id, {})[request_id] = MockTransferStatusReport(request_id, transfer_id)
83
+ return response
84
+
85
+ def cancel(self, transfer_ids: 'Sequence[str]', timeout: Optional[int] = None) -> bool:
86
+ return True
87
+
88
+ def update_priority(self, transfer_id: str, priority: int, timeout: Optional[int] = None) -> bool:
89
+ return True