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
rucio/core/monitor.py ADDED
@@ -0,0 +1,447 @@
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
+ """
16
+ Graphite and prometheus metrics
17
+ """
18
+
19
+ import atexit
20
+ import logging
21
+ import os
22
+ import string
23
+ from abc import abstractmethod
24
+ from collections.abc import Callable, Iterable, Sequence
25
+ from datetime import datetime, timedelta
26
+ from functools import wraps
27
+ from pathlib import Path
28
+ from threading import Lock
29
+ from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
30
+
31
+ from prometheus_client import REGISTRY, CollectorRegistry, Counter, Gauge, Histogram, generate_latest, multiprocess, push_to_gateway, start_http_server, values
32
+ from statsd import StatsClient
33
+
34
+ import __main__ as main
35
+ from rucio.common.config import config_get, config_get_bool, config_get_int
36
+ from rucio.common.stopwatch import Stopwatch
37
+ from rucio.common.utils import retrying
38
+
39
+ if TYPE_CHECKING:
40
+ from rucio.common.types import LoggerFunction
41
+
42
+ _T = TypeVar('_T')
43
+ _M = TypeVar('_M', bound="_MultiMetric")
44
+
45
+ PROMETHEUS_MULTIPROC_DIR = os.environ.get('PROMETHEUS_MULTIPROC_DIR', os.environ.get('prometheus_multiproc_dir', None))
46
+
47
+
48
+ def cleanup_prometheus_files_at_exit() -> None:
49
+ if PROMETHEUS_MULTIPROC_DIR:
50
+ multiprocess.mark_process_dead(os.getpid())
51
+
52
+
53
+ class MultiprocessMutexValue(values.MultiProcessValue()):
54
+ """
55
+ MultiprocessValue protected by mutex
56
+
57
+ Rucio usually is deployed using the apache MPM module, which means that it both uses multiple
58
+ subprocesses, and multiple threads per subprocess.
59
+ """
60
+ def __init__(self, *args, **kwargs):
61
+ super().__init__(*args, **kwargs)
62
+ self._lock = Lock()
63
+
64
+ def inc(self, amount):
65
+ with self._lock:
66
+ return super().inc(amount)
67
+
68
+ def set(self, value):
69
+ with self._lock:
70
+ return super().set(value)
71
+
72
+ def get(self):
73
+ with self._lock:
74
+ return super().get()
75
+
76
+
77
+ if PROMETHEUS_MULTIPROC_DIR:
78
+ os.makedirs(PROMETHEUS_MULTIPROC_DIR, exist_ok=True)
79
+ values.ValueClass = MultiprocessMutexValue
80
+
81
+ atexit.register(cleanup_prometheus_files_at_exit)
82
+
83
+
84
+ SERVER = config_get('monitor', 'carbon_server', raise_exception=False, default=None)
85
+ PORT = config_get_int('monitor', 'carbon_port', raise_exception=False, default=8125)
86
+ SCOPE = config_get('monitor', 'user_scope', raise_exception=False, default='rucio')
87
+ STATSD_CLIENT = None
88
+ if SERVER is not None:
89
+ STATSD_CLIENT = StatsClient(host=SERVER, port=PORT, prefix=SCOPE)
90
+
91
+ ENABLE_METRICS = config_get_bool('monitor', 'enable_metrics', raise_exception=False, default=False)
92
+ if ENABLE_METRICS:
93
+ METRICS_PORT = config_get_int('monitor', 'metrics_port', raise_exception=False, default=8080)
94
+ start_http_server(METRICS_PORT, registry=REGISTRY)
95
+
96
+ COUNTERS = {}
97
+ GAUGES = {}
98
+ TIMINGS = {}
99
+ METRICS_LOCK = Lock()
100
+
101
+
102
+ _HISTOGRAM_DEFAULT_BUCKETS = Histogram.DEFAULT_BUCKETS
103
+
104
+
105
+ def _cleanup_old_prometheus_files(
106
+ path: str,
107
+ file_pattern: str,
108
+ cleanup_delay: float,
109
+ logger: "LoggerFunction"
110
+ ) -> None:
111
+ """cleanup behind processes which didn't finish gracefully."""
112
+
113
+ oldest_accepted_mtime = datetime.now() - timedelta(seconds=cleanup_delay)
114
+ for file in Path(path).glob(file_pattern):
115
+ if not file.is_file():
116
+ continue
117
+
118
+ file_mtime = datetime.fromtimestamp(file.stat().st_mtime)
119
+
120
+ if file_mtime < oldest_accepted_mtime:
121
+ logger(logging.INFO, 'Cleaning up prometheus db file %s', file)
122
+ try:
123
+ os.remove(file)
124
+ except FileNotFoundError:
125
+ # Probably file already removed by another concurrent process
126
+ pass
127
+
128
+
129
+ def cleanup_old_prometheus_files(logger: "LoggerFunction" = logging.log) -> None:
130
+ path = PROMETHEUS_MULTIPROC_DIR
131
+ if path:
132
+ _cleanup_old_prometheus_files(path, file_pattern='gauge_live*.db', cleanup_delay=timedelta(hours=1).total_seconds(), logger=logger)
133
+ _cleanup_old_prometheus_files(path, file_pattern='*.db', cleanup_delay=timedelta(days=7).total_seconds(), logger=logger)
134
+
135
+
136
+ @retrying(retry_on_exception=lambda _: True,
137
+ wait_fixed=500,
138
+ stop_max_attempt_number=2)
139
+ def generate_prometheus_metrics() -> bytes:
140
+ cleanup_old_prometheus_files()
141
+
142
+ registry = CollectorRegistry()
143
+ multiprocess.MultiProcessCollector(registry)
144
+ return generate_latest(registry)
145
+
146
+
147
+ class _MultiMetric:
148
+ """
149
+ Thin wrapper class allowing to record both prometheus and statsd metrics.
150
+
151
+ Inspired by the prometheus metric behavior: uses labels to parametrize metrics.
152
+ In case of statsd, metrics are formatted using str.format(**labels). The prometheus
153
+ ones using metric.labels(**labels) calls.
154
+
155
+ If the prometheus metric string is not provided, it is derived from the statsd one.
156
+
157
+ If `labelnames` is not provided, tries to extract them from the metric name by parsing
158
+ it as a format string.
159
+ """
160
+
161
+ def __init__(
162
+ self,
163
+ statsd: str,
164
+ prom: Optional[Union[str, Counter, Gauge, Histogram]] = None,
165
+ documentation: Optional[str] = None,
166
+ labelnames: Optional[Sequence[str]] = None,
167
+ registry: Optional[CollectorRegistry] = None
168
+ ):
169
+ """
170
+ :param statsd: a string, eventually with keyword placeholders for the str.format(**labels) call
171
+ :param prom: a string prometheus metric name; or an instantiated prometheus metric object
172
+ """
173
+ self._registry = registry or REGISTRY
174
+ self._documentation = documentation or ''
175
+ self._statsd = statsd
176
+ if not prom:
177
+ parsed_format = list(string.Formatter().parse(statsd))
178
+ # automatically generate a prometheus metric name
179
+ #
180
+ # remove '.{label}' from the string for each `label`
181
+ # substituted dots with underscores
182
+ if labelnames is None:
183
+ labelnames = tuple(field_name for _, field_name, _, _ in parsed_format if field_name)
184
+ prom = ''.join(literal_text.rstrip('.').replace('.', '_') for literal_text, *_ in parsed_format)
185
+ labelnames = labelnames or ()
186
+ if isinstance(prom, str):
187
+ self._prom = self.init_prometheus_metric(prom, self._documentation, labelnames=labelnames)
188
+ else:
189
+ self._prom = prom
190
+
191
+ self._labelnames = labelnames
192
+
193
+ @abstractmethod
194
+ def init_prometheus_metric(self, name: str, documentation: Optional[str], labelnames: Sequence[str] = ()):
195
+ pass
196
+
197
+ def labels(self: _M, **labelkwargs) -> _M:
198
+ if not labelkwargs:
199
+ return self
200
+
201
+ return self.__class__(
202
+ prom=self._prom.labels(**labelkwargs),
203
+ statsd=self._statsd.format(**labelkwargs),
204
+ documentation=self._documentation,
205
+ labelnames=self._labelnames,
206
+ registry=self._registry,
207
+ )
208
+
209
+
210
+ class _MultiCounter(_MultiMetric):
211
+
212
+ def inc(self, delta=1):
213
+ delta = abs(delta)
214
+ self._prom.inc(delta)
215
+ if STATSD_CLIENT:
216
+ STATSD_CLIENT.incr(self._statsd, delta)
217
+
218
+ def init_prometheus_metric(self, name: str, documentation: str, labelnames: Sequence[str] = ()) -> Counter:
219
+ return Counter(name, documentation, labelnames=labelnames, registry=self._registry)
220
+
221
+
222
+ class _MultiGauge(_MultiMetric):
223
+
224
+ def set(self, value):
225
+ self._prom.set(value)
226
+ if STATSD_CLIENT:
227
+ STATSD_CLIENT.gauge(self._statsd, value)
228
+
229
+ def init_prometheus_metric(self, name: str, documentation: str, labelnames: Sequence[str] = ()) -> Gauge:
230
+ return Gauge(name, documentation, labelnames=labelnames, registry=self._registry)
231
+
232
+
233
+ class _MultiTiming(_MultiMetric):
234
+
235
+ def __init__(
236
+ self,
237
+ statsd: str,
238
+ prom: Optional[str] = None,
239
+ documentation: Optional[str] = None,
240
+ labelnames: Optional[Sequence[str]] = None,
241
+ registry: Optional[CollectorRegistry] = None,
242
+ buckets: Iterable[float] = _HISTOGRAM_DEFAULT_BUCKETS,
243
+ ) -> None:
244
+ self._stopwatch = None
245
+ self._histogram_buckets = tuple(buckets)
246
+ super().__init__(statsd, prom, documentation, labelnames, registry)
247
+
248
+ def observe(self, value: float):
249
+ self._prom.observe(value)
250
+ if STATSD_CLIENT:
251
+ STATSD_CLIENT.timing(self._statsd, value * 1000)
252
+
253
+ def init_prometheus_metric(self, name: str, documentation: str, labelnames: Sequence[str] = ()) -> Histogram:
254
+ return Histogram(name, documentation, labelnames=labelnames, registry=self._registry, buckets=self._histogram_buckets)
255
+
256
+ def __enter__(self):
257
+ self._stopwatch = Stopwatch()
258
+ return self
259
+
260
+ def __exit__(self, typ, value, tb):
261
+ if self._stopwatch:
262
+ self._stopwatch.stop()
263
+ self.observe(self._stopwatch.elapsed)
264
+
265
+
266
+ def _fetch_or_create_metric(
267
+ name: str,
268
+ labelnames: Optional[Sequence[str]],
269
+ container: dict[str, _T],
270
+ factory: Callable[[str, Optional[Sequence[str]]], _T]
271
+ ) -> "_T":
272
+ metric = container.get(name)
273
+ if not metric:
274
+ with METRICS_LOCK:
275
+ metric = container.get(name)
276
+ if not metric:
277
+ container[name] = metric = factory(name, labelnames)
278
+ return metric
279
+
280
+
281
+ def _fetch_or_create_counter(
282
+ name: str,
283
+ labelnames: Optional[Sequence[str]] = None,
284
+ documentation: Optional[str] = None,
285
+ registry: Optional[CollectorRegistry] = None,
286
+ ) -> _MultiCounter:
287
+ return _fetch_or_create_metric(
288
+ name=name,
289
+ labelnames=labelnames,
290
+ container=COUNTERS,
291
+ factory=lambda _name, _labelnames: _MultiCounter(statsd=_name, labelnames=_labelnames,
292
+ documentation=documentation, registry=registry)
293
+ )
294
+
295
+
296
+ def _fetch_or_create_gauge(
297
+ name: str,
298
+ labelnames: Optional[Sequence[str]] = None,
299
+ documentation: Optional[str] = None,
300
+ registry: Optional[CollectorRegistry] = None,
301
+ ) -> _MultiGauge:
302
+ return _fetch_or_create_metric(
303
+ name=name,
304
+ labelnames=labelnames,
305
+ container=GAUGES,
306
+ factory=lambda _name, _labelnames: _MultiGauge(statsd=_name, labelnames=_labelnames,
307
+ documentation=documentation, registry=registry)
308
+ )
309
+
310
+
311
+ def _fetch_or_create_timer(
312
+ name: str,
313
+ labelnames: Optional[Sequence[str]] = None,
314
+ documentation: Optional[str] = None,
315
+ registry: Optional[CollectorRegistry] = None,
316
+ buckets: Iterable[float] = _HISTOGRAM_DEFAULT_BUCKETS
317
+ ) -> _MultiTiming:
318
+ return _fetch_or_create_metric(
319
+ name=name,
320
+ labelnames=labelnames,
321
+ container=TIMINGS,
322
+ factory=lambda _name, _labels: _MultiTiming(statsd=_name, labelnames=_labels, documentation=documentation,
323
+ registry=registry, buckets=buckets)
324
+ )
325
+
326
+
327
+ class MetricManager:
328
+
329
+ """
330
+ Wrapper for metrics which prefixes them automatically with the given prefix or,
331
+ alternatively, with the path of the module.
332
+ """
333
+
334
+ def __init__(self, prefix: Optional[str] = None, module: Optional[str] = None,
335
+ registry: Optional[CollectorRegistry] = None, push_gateways: Optional[Sequence[str]] = None):
336
+ if prefix:
337
+ self.prefix = prefix
338
+ elif module:
339
+ self.prefix = module
340
+ else:
341
+ self.prefix = None
342
+ self.registry = registry or REGISTRY
343
+ self.push_gateways = push_gateways or []
344
+
345
+ def full_name(self, name: str) -> str:
346
+ if self.prefix:
347
+ return f'{self.prefix}.{name}'
348
+ return name
349
+
350
+ def get_registry(self) -> CollectorRegistry:
351
+ return self.registry
352
+
353
+ def counter(
354
+ self,
355
+ name: str,
356
+ *,
357
+ labelnames: Optional[Sequence[str]] = None,
358
+ documentation: Optional[str] = None,
359
+ ) -> _MultiCounter:
360
+ """
361
+ Log a counter.
362
+
363
+ :param name: The name (suffix) of the counter to be retrieved
364
+ :param labelnames: optional labels used to parametrize the metric
365
+ :param documentation: optional prometheus documentation for this metric
366
+ """
367
+ return _fetch_or_create_counter(name=self.full_name(name), labelnames=labelnames, documentation=documentation)
368
+
369
+ def gauge(
370
+ self,
371
+ name: str,
372
+ *,
373
+ labelnames: Optional[Sequence[str]] = None,
374
+ documentation: Optional[str] = None,
375
+ ) -> _MultiGauge:
376
+ """
377
+ Log gauge information for a single stat
378
+
379
+ :param name: The name (suffix) of the counter to be retrieved
380
+ :param labelnames: optional labels used to parametrize the metric
381
+ :param documentation: optional prometheus documentation for this metric
382
+ """
383
+ return _fetch_or_create_gauge(name=self.full_name(name), labelnames=labelnames, documentation=documentation)
384
+
385
+ def timer(
386
+ self,
387
+ name: str,
388
+ *,
389
+ labelnames: Optional[Sequence[str]] = None,
390
+ documentation: Optional[str] = None,
391
+ buckets: Iterable[float] = _HISTOGRAM_DEFAULT_BUCKETS
392
+ ) -> _MultiTiming:
393
+ """
394
+ Log a time measurement.
395
+
396
+ :param name: The name (suffix) of the counter to be retrieved
397
+ :param labelnames: optional labels used to parametrize the metric
398
+ :param documentation: optional prometheus documentation for this metric
399
+ :param buckets: Optional iterable of histogram bucket separators.
400
+ """
401
+ return _fetch_or_create_timer(name=self.full_name(name), labelnames=labelnames, documentation=documentation, buckets=buckets)
402
+
403
+ def time_it(self, original_function=None, *, buckets=_HISTOGRAM_DEFAULT_BUCKETS):
404
+ """
405
+ Function decorator which records a timer: the amount of time spent in the function.
406
+ """
407
+ def _decorator(func):
408
+ @wraps(func)
409
+ def _wrapper(*args, **kwargs):
410
+ with self.timer(name=func.__name__, buckets=buckets):
411
+ return func(*args, **kwargs)
412
+ return _wrapper
413
+ if original_function:
414
+ return _decorator(original_function)
415
+ return _decorator
416
+
417
+ def count_it(self, original_function=None):
418
+ """
419
+ Function decorator which records a counter: how many times the function was executed.
420
+ """
421
+ def _decorator(func):
422
+ @wraps(func)
423
+ def _wrapper(*args, **kwargs):
424
+ try:
425
+ return func(*args, **kwargs)
426
+ finally:
427
+ _fetch_or_create_counter(name=self.full_name(func.__name__) + '_cnt').inc()
428
+ return _wrapper
429
+ if original_function:
430
+ return _decorator(original_function)
431
+ return _decorator
432
+
433
+ def push_metrics_to_gw(self, job: Optional[str] = None, grouping_key: Optional[dict[str, Any]] = None) -> None:
434
+ """
435
+ Push the metrics out to the prometheus push gateways. This is useful for short-running programs which don't
436
+ live long enough to be reliably scraped in the prometheus pull model.
437
+ """
438
+
439
+ if not job:
440
+ job = Path(main.__file__).stem
441
+ grouping_key = grouping_key or {}
442
+
443
+ for server in self.push_gateways:
444
+ try:
445
+ push_to_gateway(server.strip(), job=job, registry=self.registry, grouping_key=grouping_key)
446
+ except:
447
+ continue
@@ -0,0 +1,195 @@
1
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from re import compile, error, match
16
+ from traceback import format_exc
17
+ from typing import TYPE_CHECKING, Any, Optional, cast
18
+
19
+ from dogpile.cache.api import NO_VALUE
20
+ from sqlalchemy import and_, delete, select
21
+ from sqlalchemy.exc import IntegrityError
22
+
23
+ from rucio.common.cache import make_region_memcached
24
+ from rucio.common.exception import Duplicate, InvalidObject, RucioException
25
+ from rucio.db.sqla import models
26
+ from rucio.db.sqla.constants import KeyType
27
+ from rucio.db.sqla.session import read_session, transactional_session
28
+
29
+ if TYPE_CHECKING:
30
+ from typing import TypedDict
31
+
32
+ from sqlalchemy.orm import Session
33
+
34
+ from rucio.common.types import InternalScope
35
+
36
+ class NamingConventionDict(TypedDict):
37
+ scope: InternalScope
38
+ regexp: str
39
+
40
+ REGION = make_region_memcached(expiration_time=900)
41
+
42
+
43
+ @transactional_session
44
+ def add_naming_convention(
45
+ scope: "InternalScope",
46
+ regexp: str,
47
+ convention_type: KeyType,
48
+ *,
49
+ session: "Session"
50
+ ) -> None:
51
+ """
52
+ add a naming convention for a given scope
53
+
54
+ :param scope: the name for the scope.
55
+ :param regexp: the regular expression to validate the name.
56
+ :param convention_type: the did_type on which the regexp should apply.
57
+ :param session: The database session in use.
58
+ """
59
+ # validate the regular expression
60
+ try:
61
+ compile(regexp)
62
+ except error:
63
+ raise RucioException('Invalid regular expression %s!' % regexp)
64
+
65
+ new_convention = models.NamingConvention(scope=scope,
66
+ regexp=regexp,
67
+ convention_type=convention_type)
68
+ try:
69
+ new_convention.save(session=session)
70
+ except IntegrityError:
71
+ raise Duplicate('Naming convention already exists!')
72
+ except:
73
+ raise RucioException(str(format_exc()))
74
+
75
+
76
+ @read_session
77
+ def get_naming_convention(
78
+ scope: "InternalScope",
79
+ convention_type: KeyType,
80
+ *,
81
+ session: "Session"
82
+ ) -> Optional[str]:
83
+ """
84
+ Get the naming convention for a given scope
85
+
86
+ :param scope: the name for the scope.
87
+ :param convention_type: the did_type on which the regexp should apply.
88
+ :param session: The database session in use.
89
+
90
+ :returns: the regular expression.
91
+ """
92
+ stmt = select(
93
+ models.NamingConvention.regexp
94
+ ).where(
95
+ and_(models.NamingConvention.scope == scope,
96
+ models.NamingConvention.convention_type == convention_type)
97
+ )
98
+ return session.execute(stmt).scalar()
99
+
100
+
101
+ @transactional_session
102
+ def delete_naming_convention(
103
+ scope: "InternalScope",
104
+ convention_type: KeyType,
105
+ *,
106
+ session: "Session"
107
+ ) -> int:
108
+ """
109
+ delete a naming convention for a given scope
110
+
111
+ :param scope: the name for the scope.
112
+ :param regexp: the regular expression to validate the name. (DEPRECATED)
113
+ :param convention_type: the did_type on which the regexp should apply.
114
+ :param session: The database session in use.
115
+ """
116
+ if scope.internal is not None:
117
+ REGION.delete(scope.internal)
118
+ stmt = delete(
119
+ models.NamingConvention
120
+ ).where(
121
+ and_(models.NamingConvention.scope == scope,
122
+ models.NamingConvention.convention_type == convention_type)
123
+ )
124
+ return session.execute(stmt).rowcount
125
+
126
+
127
+ @read_session
128
+ def list_naming_conventions(*, session: "Session") -> list["NamingConventionDict"]:
129
+ """
130
+ List all naming conventions.
131
+
132
+ :param session: The database session in use.
133
+
134
+ :returns: a list of dictionaries.
135
+ """
136
+ stmt = select(
137
+ models.NamingConvention.scope,
138
+ models.NamingConvention.regexp
139
+ )
140
+ return [cast("NamingConventionDict", row._asdict()) for row in session.execute(stmt).all()]
141
+
142
+
143
+ @read_session
144
+ def validate_name(
145
+ scope: "InternalScope",
146
+ name: str,
147
+ did_type: str,
148
+ *,
149
+ session: "Session"
150
+ ) -> Optional[dict[str, Any]]:
151
+ """
152
+ Validate a name according to a naming convention.
153
+
154
+ :param scope: the name for the scope.
155
+ :param name: the name.
156
+ :param did_type: the type of did.
157
+
158
+ :param session: The database session in use.
159
+
160
+ :returns: a dictionary with metadata.
161
+ """
162
+ if scope.external is not None:
163
+ if scope.external.startswith('user'):
164
+ return {'project': 'user'}
165
+ elif scope.external.startswith('group'):
166
+ return {'project': 'group'}
167
+
168
+ # Check if naming convention can be found in cache region
169
+ regexp = REGION.get(scope.internal)
170
+ if regexp is NO_VALUE: # no cached entry found
171
+ regexp = get_naming_convention(scope=scope,
172
+ convention_type=KeyType.DATASET,
173
+ session=session)
174
+ if scope.internal is not None:
175
+ regexp and REGION.set(scope.internal, regexp)
176
+
177
+ if not regexp:
178
+ return
179
+
180
+ # Validate with regexp
181
+ groups = match(regexp, str(name)) # type: ignore
182
+ if groups:
183
+ meta = groups.groupdict()
184
+ # Hack to get task_id from version
185
+ if 'version' in meta and meta['version']:
186
+ matched = match(r'(?P<version>\w+)_tid(?P<task_id>\d+)_\w+$', meta['version'])
187
+ if matched:
188
+ meta['version'] = matched.groupdict()['version']
189
+ meta['task_id'] = int(matched.groupdict()['task_id'])
190
+ if 'run_number' in meta and meta['run_number']:
191
+ meta['run_number'] = int(meta['run_number'])
192
+ return meta
193
+
194
+ print(f"Provided name {name} doesn't match the naming convention {regexp}")
195
+ raise InvalidObject(f"Provided name {name} doesn't match the naming convention {regexp}")