rucio 32.8.6__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (481) hide show
  1. rucio/__init__.py +18 -0
  2. rucio/alembicrevision.py +16 -0
  3. rucio/api/__init__.py +14 -0
  4. rucio/api/account.py +266 -0
  5. rucio/api/account_limit.py +287 -0
  6. rucio/api/authentication.py +302 -0
  7. rucio/api/config.py +218 -0
  8. rucio/api/credential.py +60 -0
  9. rucio/api/did.py +726 -0
  10. rucio/api/dirac.py +71 -0
  11. rucio/api/exporter.py +60 -0
  12. rucio/api/heartbeat.py +62 -0
  13. rucio/api/identity.py +160 -0
  14. rucio/api/importer.py +46 -0
  15. rucio/api/lifetime_exception.py +95 -0
  16. rucio/api/lock.py +131 -0
  17. rucio/api/meta.py +85 -0
  18. rucio/api/permission.py +72 -0
  19. rucio/api/quarantined_replica.py +69 -0
  20. rucio/api/replica.py +528 -0
  21. rucio/api/request.py +220 -0
  22. rucio/api/rse.py +601 -0
  23. rucio/api/rule.py +335 -0
  24. rucio/api/scope.py +89 -0
  25. rucio/api/subscription.py +255 -0
  26. rucio/api/temporary_did.py +49 -0
  27. rucio/api/vo.py +112 -0
  28. rucio/client/__init__.py +16 -0
  29. rucio/client/accountclient.py +413 -0
  30. rucio/client/accountlimitclient.py +155 -0
  31. rucio/client/baseclient.py +929 -0
  32. rucio/client/client.py +77 -0
  33. rucio/client/configclient.py +113 -0
  34. rucio/client/credentialclient.py +54 -0
  35. rucio/client/didclient.py +691 -0
  36. rucio/client/diracclient.py +48 -0
  37. rucio/client/downloadclient.py +1674 -0
  38. rucio/client/exportclient.py +44 -0
  39. rucio/client/fileclient.py +51 -0
  40. rucio/client/importclient.py +42 -0
  41. rucio/client/lifetimeclient.py +74 -0
  42. rucio/client/lockclient.py +99 -0
  43. rucio/client/metaclient.py +137 -0
  44. rucio/client/pingclient.py +45 -0
  45. rucio/client/replicaclient.py +444 -0
  46. rucio/client/requestclient.py +109 -0
  47. rucio/client/rseclient.py +664 -0
  48. rucio/client/ruleclient.py +287 -0
  49. rucio/client/scopeclient.py +88 -0
  50. rucio/client/subscriptionclient.py +161 -0
  51. rucio/client/touchclient.py +78 -0
  52. rucio/client/uploadclient.py +871 -0
  53. rucio/common/__init__.py +14 -0
  54. rucio/common/cache.py +74 -0
  55. rucio/common/config.py +796 -0
  56. rucio/common/constants.py +92 -0
  57. rucio/common/constraints.py +18 -0
  58. rucio/common/didtype.py +187 -0
  59. rucio/common/dumper/__init__.py +306 -0
  60. rucio/common/dumper/consistency.py +449 -0
  61. rucio/common/dumper/data_models.py +325 -0
  62. rucio/common/dumper/path_parsing.py +65 -0
  63. rucio/common/exception.py +1092 -0
  64. rucio/common/extra.py +37 -0
  65. rucio/common/logging.py +404 -0
  66. rucio/common/pcache.py +1387 -0
  67. rucio/common/policy.py +84 -0
  68. rucio/common/schema/__init__.py +143 -0
  69. rucio/common/schema/atlas.py +411 -0
  70. rucio/common/schema/belleii.py +406 -0
  71. rucio/common/schema/cms.py +478 -0
  72. rucio/common/schema/domatpc.py +399 -0
  73. rucio/common/schema/escape.py +424 -0
  74. rucio/common/schema/generic.py +431 -0
  75. rucio/common/schema/generic_multi_vo.py +410 -0
  76. rucio/common/schema/icecube.py +404 -0
  77. rucio/common/schema/lsst.py +423 -0
  78. rucio/common/stomp_utils.py +160 -0
  79. rucio/common/stopwatch.py +56 -0
  80. rucio/common/test_rucio_server.py +148 -0
  81. rucio/common/types.py +158 -0
  82. rucio/common/utils.py +1946 -0
  83. rucio/core/__init__.py +14 -0
  84. rucio/core/account.py +426 -0
  85. rucio/core/account_counter.py +171 -0
  86. rucio/core/account_limit.py +357 -0
  87. rucio/core/authentication.py +563 -0
  88. rucio/core/config.py +386 -0
  89. rucio/core/credential.py +218 -0
  90. rucio/core/did.py +3102 -0
  91. rucio/core/did_meta_plugins/__init__.py +250 -0
  92. rucio/core/did_meta_plugins/did_column_meta.py +326 -0
  93. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +116 -0
  94. rucio/core/did_meta_plugins/filter_engine.py +573 -0
  95. rucio/core/did_meta_plugins/json_meta.py +215 -0
  96. rucio/core/did_meta_plugins/mongo_meta.py +199 -0
  97. rucio/core/did_meta_plugins/postgres_meta.py +317 -0
  98. rucio/core/dirac.py +208 -0
  99. rucio/core/distance.py +164 -0
  100. rucio/core/exporter.py +59 -0
  101. rucio/core/heartbeat.py +263 -0
  102. rucio/core/identity.py +290 -0
  103. rucio/core/importer.py +248 -0
  104. rucio/core/lifetime_exception.py +377 -0
  105. rucio/core/lock.py +474 -0
  106. rucio/core/message.py +241 -0
  107. rucio/core/meta.py +190 -0
  108. rucio/core/monitor.py +441 -0
  109. rucio/core/naming_convention.py +154 -0
  110. rucio/core/nongrid_trace.py +124 -0
  111. rucio/core/oidc.py +1339 -0
  112. rucio/core/permission/__init__.py +107 -0
  113. rucio/core/permission/atlas.py +1333 -0
  114. rucio/core/permission/belleii.py +1076 -0
  115. rucio/core/permission/cms.py +1166 -0
  116. rucio/core/permission/escape.py +1076 -0
  117. rucio/core/permission/generic.py +1128 -0
  118. rucio/core/permission/generic_multi_vo.py +1148 -0
  119. rucio/core/quarantined_replica.py +190 -0
  120. rucio/core/replica.py +3627 -0
  121. rucio/core/replica_sorter.py +368 -0
  122. rucio/core/request.py +2241 -0
  123. rucio/core/rse.py +1835 -0
  124. rucio/core/rse_counter.py +155 -0
  125. rucio/core/rse_expression_parser.py +460 -0
  126. rucio/core/rse_selector.py +277 -0
  127. rucio/core/rule.py +3419 -0
  128. rucio/core/rule_grouping.py +1473 -0
  129. rucio/core/scope.py +152 -0
  130. rucio/core/subscription.py +316 -0
  131. rucio/core/temporary_did.py +188 -0
  132. rucio/core/topology.py +448 -0
  133. rucio/core/trace.py +361 -0
  134. rucio/core/transfer.py +1233 -0
  135. rucio/core/vo.py +151 -0
  136. rucio/core/volatile_replica.py +123 -0
  137. rucio/daemons/__init__.py +14 -0
  138. rucio/daemons/abacus/__init__.py +14 -0
  139. rucio/daemons/abacus/account.py +106 -0
  140. rucio/daemons/abacus/collection_replica.py +113 -0
  141. rucio/daemons/abacus/rse.py +107 -0
  142. rucio/daemons/atropos/__init__.py +14 -0
  143. rucio/daemons/atropos/atropos.py +243 -0
  144. rucio/daemons/auditor/__init__.py +261 -0
  145. rucio/daemons/auditor/hdfs.py +86 -0
  146. rucio/daemons/auditor/srmdumps.py +284 -0
  147. rucio/daemons/automatix/__init__.py +14 -0
  148. rucio/daemons/automatix/automatix.py +281 -0
  149. rucio/daemons/badreplicas/__init__.py +14 -0
  150. rucio/daemons/badreplicas/minos.py +311 -0
  151. rucio/daemons/badreplicas/minos_temporary_expiration.py +173 -0
  152. rucio/daemons/badreplicas/necromancer.py +200 -0
  153. rucio/daemons/bb8/__init__.py +14 -0
  154. rucio/daemons/bb8/bb8.py +356 -0
  155. rucio/daemons/bb8/common.py +762 -0
  156. rucio/daemons/bb8/nuclei_background_rebalance.py +147 -0
  157. rucio/daemons/bb8/t2_background_rebalance.py +146 -0
  158. rucio/daemons/c3po/__init__.py +14 -0
  159. rucio/daemons/c3po/algorithms/__init__.py +14 -0
  160. rucio/daemons/c3po/algorithms/simple.py +131 -0
  161. rucio/daemons/c3po/algorithms/t2_free_space.py +125 -0
  162. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +127 -0
  163. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +279 -0
  164. rucio/daemons/c3po/c3po.py +342 -0
  165. rucio/daemons/c3po/collectors/__init__.py +14 -0
  166. rucio/daemons/c3po/collectors/agis.py +108 -0
  167. rucio/daemons/c3po/collectors/free_space.py +62 -0
  168. rucio/daemons/c3po/collectors/jedi_did.py +48 -0
  169. rucio/daemons/c3po/collectors/mock_did.py +46 -0
  170. rucio/daemons/c3po/collectors/network_metrics.py +63 -0
  171. rucio/daemons/c3po/collectors/workload.py +110 -0
  172. rucio/daemons/c3po/utils/__init__.py +14 -0
  173. rucio/daemons/c3po/utils/dataset_cache.py +40 -0
  174. rucio/daemons/c3po/utils/expiring_dataset_cache.py +45 -0
  175. rucio/daemons/c3po/utils/expiring_list.py +63 -0
  176. rucio/daemons/c3po/utils/popularity.py +82 -0
  177. rucio/daemons/c3po/utils/timeseries.py +76 -0
  178. rucio/daemons/cache/__init__.py +14 -0
  179. rucio/daemons/cache/consumer.py +191 -0
  180. rucio/daemons/common.py +391 -0
  181. rucio/daemons/conveyor/__init__.py +14 -0
  182. rucio/daemons/conveyor/common.py +530 -0
  183. rucio/daemons/conveyor/finisher.py +492 -0
  184. rucio/daemons/conveyor/poller.py +372 -0
  185. rucio/daemons/conveyor/preparer.py +198 -0
  186. rucio/daemons/conveyor/receiver.py +206 -0
  187. rucio/daemons/conveyor/stager.py +127 -0
  188. rucio/daemons/conveyor/submitter.py +379 -0
  189. rucio/daemons/conveyor/throttler.py +468 -0
  190. rucio/daemons/follower/__init__.py +14 -0
  191. rucio/daemons/follower/follower.py +97 -0
  192. rucio/daemons/hermes/__init__.py +14 -0
  193. rucio/daemons/hermes/hermes.py +738 -0
  194. rucio/daemons/judge/__init__.py +14 -0
  195. rucio/daemons/judge/cleaner.py +149 -0
  196. rucio/daemons/judge/evaluator.py +172 -0
  197. rucio/daemons/judge/injector.py +154 -0
  198. rucio/daemons/judge/repairer.py +144 -0
  199. rucio/daemons/oauthmanager/__init__.py +14 -0
  200. rucio/daemons/oauthmanager/oauthmanager.py +199 -0
  201. rucio/daemons/reaper/__init__.py +14 -0
  202. rucio/daemons/reaper/dark_reaper.py +272 -0
  203. rucio/daemons/reaper/light_reaper.py +255 -0
  204. rucio/daemons/reaper/reaper.py +701 -0
  205. rucio/daemons/replicarecoverer/__init__.py +14 -0
  206. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +487 -0
  207. rucio/daemons/storage/__init__.py +14 -0
  208. rucio/daemons/storage/consistency/__init__.py +14 -0
  209. rucio/daemons/storage/consistency/actions.py +753 -0
  210. rucio/daemons/tracer/__init__.py +14 -0
  211. rucio/daemons/tracer/kronos.py +513 -0
  212. rucio/daemons/transmogrifier/__init__.py +14 -0
  213. rucio/daemons/transmogrifier/transmogrifier.py +753 -0
  214. rucio/daemons/undertaker/__init__.py +14 -0
  215. rucio/daemons/undertaker/undertaker.py +137 -0
  216. rucio/db/__init__.py +14 -0
  217. rucio/db/sqla/__init__.py +38 -0
  218. rucio/db/sqla/constants.py +192 -0
  219. rucio/db/sqla/migrate_repo/__init__.py +14 -0
  220. rucio/db/sqla/migrate_repo/env.py +111 -0
  221. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +71 -0
  222. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +50 -0
  223. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +61 -0
  224. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +46 -0
  225. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +93 -0
  226. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +78 -0
  227. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +46 -0
  228. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +53 -0
  229. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +69 -0
  230. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +42 -0
  231. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +46 -0
  232. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +61 -0
  233. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +42 -0
  234. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +141 -0
  235. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +75 -0
  236. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +75 -0
  237. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +46 -0
  238. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +51 -0
  239. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +135 -0
  240. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +65 -0
  241. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +42 -0
  242. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +66 -0
  243. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +54 -0
  244. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +43 -0
  245. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +46 -0
  246. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +47 -0
  247. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +54 -0
  248. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +39 -0
  249. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +48 -0
  250. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +47 -0
  251. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +48 -0
  252. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +59 -0
  253. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +47 -0
  254. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +72 -0
  255. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +46 -0
  256. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +45 -0
  257. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +48 -0
  258. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +48 -0
  259. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +42 -0
  260. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +69 -0
  261. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +46 -0
  262. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +78 -0
  263. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +62 -0
  264. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +74 -0
  265. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +44 -0
  266. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +67 -0
  267. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +134 -0
  268. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +58 -0
  269. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +79 -0
  270. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +61 -0
  271. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +45 -0
  272. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +46 -0
  273. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +65 -0
  274. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +42 -0
  275. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +46 -0
  276. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +46 -0
  277. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +80 -0
  278. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +43 -0
  279. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +61 -0
  280. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +47 -0
  281. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +46 -0
  282. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +52 -0
  283. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +42 -0
  284. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +65 -0
  285. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +46 -0
  286. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +47 -0
  287. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +45 -0
  288. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +46 -0
  289. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +48 -0
  290. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +50 -0
  291. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +59 -0
  292. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +48 -0
  293. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +108 -0
  294. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +57 -0
  295. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +51 -0
  296. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +50 -0
  297. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +46 -0
  298. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +42 -0
  299. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +93 -0
  300. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +73 -0
  301. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +52 -0
  302. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +45 -0
  303. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +46 -0
  304. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +54 -0
  305. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +48 -0
  306. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +70 -0
  307. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +48 -0
  308. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +95 -0
  309. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +55 -0
  310. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +74 -0
  311. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +78 -0
  312. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +49 -0
  313. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +124 -0
  314. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +60 -0
  315. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +53 -0
  316. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +56 -0
  317. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +67 -0
  318. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +50 -0
  319. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +46 -0
  320. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +92 -0
  321. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +42 -0
  322. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +46 -0
  323. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +147 -0
  324. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +78 -0
  325. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +53 -0
  326. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +74 -0
  327. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +56 -0
  328. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +46 -0
  329. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +68 -0
  330. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +48 -0
  331. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +149 -0
  332. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +106 -0
  333. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +47 -0
  334. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +45 -0
  335. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +105 -0
  336. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +52 -0
  337. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +106 -0
  338. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +30 -0
  339. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +75 -0
  340. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +49 -0
  341. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +45 -0
  342. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +38 -0
  343. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +44 -0
  344. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +46 -0
  345. rucio/db/sqla/models.py +1834 -0
  346. rucio/db/sqla/sautils.py +48 -0
  347. rucio/db/sqla/session.py +470 -0
  348. rucio/db/sqla/types.py +207 -0
  349. rucio/db/sqla/util.py +521 -0
  350. rucio/rse/__init__.py +97 -0
  351. rucio/rse/protocols/__init__.py +14 -0
  352. rucio/rse/protocols/cache.py +123 -0
  353. rucio/rse/protocols/dummy.py +112 -0
  354. rucio/rse/protocols/gfal.py +701 -0
  355. rucio/rse/protocols/globus.py +243 -0
  356. rucio/rse/protocols/gsiftp.py +93 -0
  357. rucio/rse/protocols/http_cache.py +83 -0
  358. rucio/rse/protocols/mock.py +124 -0
  359. rucio/rse/protocols/ngarc.py +210 -0
  360. rucio/rse/protocols/posix.py +251 -0
  361. rucio/rse/protocols/protocol.py +530 -0
  362. rucio/rse/protocols/rclone.py +365 -0
  363. rucio/rse/protocols/rfio.py +137 -0
  364. rucio/rse/protocols/srm.py +339 -0
  365. rucio/rse/protocols/ssh.py +414 -0
  366. rucio/rse/protocols/storm.py +207 -0
  367. rucio/rse/protocols/webdav.py +547 -0
  368. rucio/rse/protocols/xrootd.py +295 -0
  369. rucio/rse/rsemanager.py +752 -0
  370. rucio/tests/__init__.py +14 -0
  371. rucio/tests/common.py +244 -0
  372. rucio/tests/common_server.py +132 -0
  373. rucio/transfertool/__init__.py +14 -0
  374. rucio/transfertool/fts3.py +1484 -0
  375. rucio/transfertool/globus.py +200 -0
  376. rucio/transfertool/globus_library.py +182 -0
  377. rucio/transfertool/mock.py +81 -0
  378. rucio/transfertool/transfertool.py +212 -0
  379. rucio/vcsversion.py +11 -0
  380. rucio/version.py +46 -0
  381. rucio/web/__init__.py +14 -0
  382. rucio/web/rest/__init__.py +14 -0
  383. rucio/web/rest/flaskapi/__init__.py +14 -0
  384. rucio/web/rest/flaskapi/authenticated_bp.py +28 -0
  385. rucio/web/rest/flaskapi/v1/__init__.py +14 -0
  386. rucio/web/rest/flaskapi/v1/accountlimits.py +234 -0
  387. rucio/web/rest/flaskapi/v1/accounts.py +1088 -0
  388. rucio/web/rest/flaskapi/v1/archives.py +100 -0
  389. rucio/web/rest/flaskapi/v1/auth.py +1642 -0
  390. rucio/web/rest/flaskapi/v1/common.py +385 -0
  391. rucio/web/rest/flaskapi/v1/config.py +305 -0
  392. rucio/web/rest/flaskapi/v1/credentials.py +213 -0
  393. rucio/web/rest/flaskapi/v1/dids.py +2204 -0
  394. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  395. rucio/web/rest/flaskapi/v1/export.py +77 -0
  396. rucio/web/rest/flaskapi/v1/heartbeats.py +129 -0
  397. rucio/web/rest/flaskapi/v1/identities.py +263 -0
  398. rucio/web/rest/flaskapi/v1/import.py +133 -0
  399. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +315 -0
  400. rucio/web/rest/flaskapi/v1/locks.py +360 -0
  401. rucio/web/rest/flaskapi/v1/main.py +83 -0
  402. rucio/web/rest/flaskapi/v1/meta.py +226 -0
  403. rucio/web/rest/flaskapi/v1/metrics.py +37 -0
  404. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  405. rucio/web/rest/flaskapi/v1/ping.py +89 -0
  406. rucio/web/rest/flaskapi/v1/redirect.py +366 -0
  407. rucio/web/rest/flaskapi/v1/replicas.py +1866 -0
  408. rucio/web/rest/flaskapi/v1/requests.py +841 -0
  409. rucio/web/rest/flaskapi/v1/rses.py +2204 -0
  410. rucio/web/rest/flaskapi/v1/rules.py +824 -0
  411. rucio/web/rest/flaskapi/v1/scopes.py +161 -0
  412. rucio/web/rest/flaskapi/v1/subscriptions.py +646 -0
  413. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  414. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  415. rucio/web/rest/flaskapi/v1/tmp_dids.py +115 -0
  416. rucio/web/rest/flaskapi/v1/traces.py +100 -0
  417. rucio/web/rest/flaskapi/v1/vos.py +280 -0
  418. rucio/web/rest/main.py +19 -0
  419. rucio/web/rest/metrics.py +28 -0
  420. rucio-32.8.6.data/data/rucio/etc/alembic.ini.template +71 -0
  421. rucio-32.8.6.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  422. rucio-32.8.6.data/data/rucio/etc/globus-config.yml.template +5 -0
  423. rucio-32.8.6.data/data/rucio/etc/ldap.cfg.template +30 -0
  424. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  425. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  426. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  427. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  428. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  429. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  430. rucio-32.8.6.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  431. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.atlas.client.template +42 -0
  432. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.template +257 -0
  433. rucio-32.8.6.data/data/rucio/etc/rucio_multi_vo.cfg.template +234 -0
  434. rucio-32.8.6.data/data/rucio/requirements.txt +55 -0
  435. rucio-32.8.6.data/data/rucio/tools/bootstrap.py +34 -0
  436. rucio-32.8.6.data/data/rucio/tools/merge_rucio_configs.py +147 -0
  437. rucio-32.8.6.data/data/rucio/tools/reset_database.py +40 -0
  438. rucio-32.8.6.data/scripts/rucio +2540 -0
  439. rucio-32.8.6.data/scripts/rucio-abacus-account +75 -0
  440. rucio-32.8.6.data/scripts/rucio-abacus-collection-replica +47 -0
  441. rucio-32.8.6.data/scripts/rucio-abacus-rse +79 -0
  442. rucio-32.8.6.data/scripts/rucio-admin +2434 -0
  443. rucio-32.8.6.data/scripts/rucio-atropos +61 -0
  444. rucio-32.8.6.data/scripts/rucio-auditor +199 -0
  445. rucio-32.8.6.data/scripts/rucio-automatix +51 -0
  446. rucio-32.8.6.data/scripts/rucio-bb8 +58 -0
  447. rucio-32.8.6.data/scripts/rucio-c3po +86 -0
  448. rucio-32.8.6.data/scripts/rucio-cache-client +135 -0
  449. rucio-32.8.6.data/scripts/rucio-cache-consumer +43 -0
  450. rucio-32.8.6.data/scripts/rucio-conveyor-finisher +59 -0
  451. rucio-32.8.6.data/scripts/rucio-conveyor-poller +67 -0
  452. rucio-32.8.6.data/scripts/rucio-conveyor-preparer +38 -0
  453. rucio-32.8.6.data/scripts/rucio-conveyor-receiver +44 -0
  454. rucio-32.8.6.data/scripts/rucio-conveyor-stager +77 -0
  455. rucio-32.8.6.data/scripts/rucio-conveyor-submitter +140 -0
  456. rucio-32.8.6.data/scripts/rucio-conveyor-throttler +105 -0
  457. rucio-32.8.6.data/scripts/rucio-dark-reaper +54 -0
  458. rucio-32.8.6.data/scripts/rucio-dumper +159 -0
  459. rucio-32.8.6.data/scripts/rucio-follower +45 -0
  460. rucio-32.8.6.data/scripts/rucio-hermes +55 -0
  461. rucio-32.8.6.data/scripts/rucio-judge-cleaner +90 -0
  462. rucio-32.8.6.data/scripts/rucio-judge-evaluator +138 -0
  463. rucio-32.8.6.data/scripts/rucio-judge-injector +45 -0
  464. rucio-32.8.6.data/scripts/rucio-judge-repairer +45 -0
  465. rucio-32.8.6.data/scripts/rucio-kronos +45 -0
  466. rucio-32.8.6.data/scripts/rucio-light-reaper +53 -0
  467. rucio-32.8.6.data/scripts/rucio-minos +54 -0
  468. rucio-32.8.6.data/scripts/rucio-minos-temporary-expiration +51 -0
  469. rucio-32.8.6.data/scripts/rucio-necromancer +121 -0
  470. rucio-32.8.6.data/scripts/rucio-oauth-manager +64 -0
  471. rucio-32.8.6.data/scripts/rucio-reaper +84 -0
  472. rucio-32.8.6.data/scripts/rucio-replica-recoverer +249 -0
  473. rucio-32.8.6.data/scripts/rucio-storage-consistency-actions +75 -0
  474. rucio-32.8.6.data/scripts/rucio-transmogrifier +78 -0
  475. rucio-32.8.6.data/scripts/rucio-undertaker +77 -0
  476. rucio-32.8.6.dist-info/METADATA +83 -0
  477. rucio-32.8.6.dist-info/RECORD +481 -0
  478. rucio-32.8.6.dist-info/WHEEL +5 -0
  479. rucio-32.8.6.dist-info/licenses/AUTHORS.rst +94 -0
  480. rucio-32.8.6.dist-info/licenses/LICENSE +201 -0
  481. rucio-32.8.6.dist-info/top_level.txt +1 -0
rucio/core/monitor.py ADDED
@@ -0,0 +1,441 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """
17
+ Graphite and prometheus metrics
18
+ """
19
+
20
+ import __main__ as main
21
+ import atexit
22
+ import logging
23
+ import os
24
+ import string
25
+ from abc import abstractmethod
26
+ from collections.abc import Callable, Iterable, Sequence
27
+ from datetime import datetime, timedelta
28
+ from functools import wraps
29
+ from pathlib import Path
30
+ from threading import Lock
31
+ from typing import Any, Optional, TypeVar, Union
32
+
33
+ from prometheus_client import (Counter, Gauge, Histogram, REGISTRY, CollectorRegistry, generate_latest, multiprocess,
34
+ push_to_gateway, start_http_server, values)
35
+ from statsd import StatsClient
36
+
37
+ from rucio.common.config import config_get, config_get_bool, config_get_int
38
+ from rucio.common.stopwatch import Stopwatch
39
+ from rucio.common.utils import retrying
40
+
41
+ _T = TypeVar('_T')
42
+ _M = TypeVar('_M', bound="_MultiMetric")
43
+
44
+ PROMETHEUS_MULTIPROC_DIR = os.environ.get('PROMETHEUS_MULTIPROC_DIR', os.environ.get('prometheus_multiproc_dir', None))
45
+
46
+
47
+ def cleanup_prometheus_files_at_exit():
48
+ if PROMETHEUS_MULTIPROC_DIR:
49
+ multiprocess.mark_process_dead(os.getpid())
50
+
51
+
52
+ class MultiprocessMutexValue(values.MultiProcessValue()):
53
+ """
54
+ MultiprocessValue protected by mutex
55
+
56
+ Rucio usually is deployed using the apache MPM module, which means that it both uses multiple
57
+ subprocesses, and multiple threads per subprocess.
58
+ """
59
+ def __init__(self, *args, **kwargs):
60
+ super().__init__(*args, **kwargs)
61
+ self._lock = Lock()
62
+
63
+ def inc(self, amount):
64
+ with self._lock:
65
+ return super().inc(amount)
66
+
67
+ def set(self, value):
68
+ with self._lock:
69
+ return super().set(value)
70
+
71
+ def get(self):
72
+ with self._lock:
73
+ return super().get()
74
+
75
+
76
+ if PROMETHEUS_MULTIPROC_DIR:
77
+ os.makedirs(PROMETHEUS_MULTIPROC_DIR, exist_ok=True)
78
+ values.ValueClass = MultiprocessMutexValue
79
+
80
+ atexit.register(cleanup_prometheus_files_at_exit)
81
+
82
+
83
+ SERVER = config_get('monitor', 'carbon_server', raise_exception=False, default=None)
84
+ PORT = config_get_int('monitor', 'carbon_port', raise_exception=False, default=8125)
85
+ SCOPE = config_get('monitor', 'user_scope', raise_exception=False, default='rucio')
86
+ STATSD_CLIENT = None
87
+ if SERVER is not None:
88
+ STATSD_CLIENT = StatsClient(host=SERVER, port=PORT, prefix=SCOPE)
89
+
90
+ ENABLE_METRICS = config_get_bool('monitor', 'enable_metrics', raise_exception=False, default=False)
91
+ if ENABLE_METRICS:
92
+ METRICS_PORT = config_get_int('monitor', 'metrics_port', raise_exception=False, default=8080)
93
+ start_http_server(METRICS_PORT, registry=REGISTRY)
94
+
95
+ COUNTERS = {}
96
+ GAUGES = {}
97
+ TIMINGS = {}
98
+ METRICS_LOCK = Lock()
99
+
100
+
101
+ _HISTOGRAM_DEFAULT_BUCKETS = Histogram.DEFAULT_BUCKETS
102
+
103
+
104
+ def _cleanup_old_prometheus_files(path, file_pattern, cleanup_delay, logger):
105
+ """cleanup behind processes which didn't finish gracefully."""
106
+
107
+ oldest_accepted_mtime = datetime.now() - timedelta(seconds=cleanup_delay)
108
+ for file in Path(path).glob(file_pattern):
109
+ if not file.is_file():
110
+ continue
111
+
112
+ file_mtime = datetime.fromtimestamp(file.stat().st_mtime)
113
+
114
+ if file_mtime < oldest_accepted_mtime:
115
+ logger(logging.INFO, 'Cleaning up prometheus db file %s', file)
116
+ try:
117
+ os.remove(file)
118
+ except FileNotFoundError:
119
+ # Probably file already removed by another concurrent process
120
+ pass
121
+
122
+
123
+ def cleanup_old_prometheus_files(logger=logging.log):
124
+ path = PROMETHEUS_MULTIPROC_DIR
125
+ if path:
126
+ _cleanup_old_prometheus_files(path, file_pattern='gauge_live*.db', cleanup_delay=timedelta(hours=1).total_seconds(), logger=logger)
127
+ _cleanup_old_prometheus_files(path, file_pattern='*.db', cleanup_delay=timedelta(days=7).total_seconds(), logger=logger)
128
+
129
+
130
+ @retrying(retry_on_exception=lambda _: True,
131
+ wait_fixed=500,
132
+ stop_max_attempt_number=2)
133
+ def generate_prometheus_metrics():
134
+ cleanup_old_prometheus_files()
135
+
136
+ registry = CollectorRegistry()
137
+ multiprocess.MultiProcessCollector(registry)
138
+ return generate_latest(registry)
139
+
140
+
141
+ class _MultiMetric:
142
+ """
143
+ Thin wrapper class allowing to record both prometheus and statsd metrics.
144
+
145
+ Inspired by the prometheus metric behavior: uses labels to parametrize metrics.
146
+ In case of statsd, metrics are formatted using str.format(**labels). The prometheus
147
+ ones using metric.labels(**labels) calls.
148
+
149
+ If the prometheus metric string is not provided, it is derived from the statsd one.
150
+
151
+ If `labelnames` is not provided, tries to extract them from the metric name by parsing
152
+ it as a format string.
153
+ """
154
+
155
+ def __init__(
156
+ self,
157
+ statsd: str,
158
+ prom: Optional[Union[str, Counter, Gauge, Histogram]] = None,
159
+ documentation: Optional[str] = None,
160
+ labelnames: Optional[Sequence[str]] = None,
161
+ registry: Optional[CollectorRegistry] = None
162
+ ):
163
+ """
164
+ :param statsd: a string, eventually with keyword placeholders for the str.format(**labels) call
165
+ :param prom: a string prometheus metric name; or an instantiated prometheus metric object
166
+ """
167
+ self._registry = registry or REGISTRY
168
+ self._documentation = documentation or ''
169
+ self._statsd = statsd
170
+ if not prom:
171
+ parsed_format = list(string.Formatter().parse(statsd))
172
+ # automatically generate a prometheus metric name
173
+ #
174
+ # remove '.{label}' from the string for each `label`
175
+ # substituted dots with underscores
176
+ if labelnames is None:
177
+ labelnames = tuple(field_name for _, field_name, _, _ in parsed_format if field_name)
178
+ prom = ''.join(literal_text.rstrip('.').replace('.', '_') for literal_text, *_ in parsed_format)
179
+ labelnames = labelnames or ()
180
+ if isinstance(prom, str):
181
+ self._prom = self.init_prometheus_metric(prom, self._documentation, labelnames=labelnames)
182
+ else:
183
+ self._prom = prom
184
+
185
+ self._labelnames = labelnames
186
+
187
+ @abstractmethod
188
+ def init_prometheus_metric(self, name: str, documentation: Optional[str], labelnames: Sequence[str] = ()):
189
+ pass
190
+
191
+ def labels(self: _M, **labelkwargs) -> _M:
192
+ if not labelkwargs:
193
+ return self
194
+
195
+ return self.__class__(
196
+ prom=self._prom.labels(**labelkwargs),
197
+ statsd=self._statsd.format(**labelkwargs),
198
+ documentation=self._documentation,
199
+ labelnames=self._labelnames,
200
+ registry=self._registry,
201
+ )
202
+
203
+
204
+ class _MultiCounter(_MultiMetric):
205
+
206
+ def inc(self, delta=1):
207
+ delta = abs(delta)
208
+ self._prom.inc(delta)
209
+ if STATSD_CLIENT:
210
+ STATSD_CLIENT.incr(self._statsd, delta)
211
+
212
+ def init_prometheus_metric(self, name: str, documentation: Optional[str], labelnames: Sequence[str] = ()):
213
+ return Counter(name, documentation, labelnames=labelnames, registry=self._registry)
214
+
215
+
216
+ class _MultiGauge(_MultiMetric):
217
+
218
+ def set(self, value):
219
+ self._prom.set(value)
220
+ if STATSD_CLIENT:
221
+ STATSD_CLIENT.gauge(self._statsd, value)
222
+
223
+ def init_prometheus_metric(self, name: str, documentation: Optional[str], labelnames: Sequence[str] = ()):
224
+ return Gauge(name, documentation, labelnames=labelnames, registry=self._registry)
225
+
226
+
227
+ class _MultiTiming(_MultiMetric):
228
+
229
+ def __init__(
230
+ self,
231
+ statsd: str,
232
+ prom: Optional[str] = None,
233
+ documentation: Optional[str] = None,
234
+ labelnames: Optional[Sequence[str]] = None,
235
+ registry: Optional[CollectorRegistry] = None,
236
+ buckets: Iterable[float] = _HISTOGRAM_DEFAULT_BUCKETS,
237
+ ) -> None:
238
+ self._stopwatch = None
239
+ self._histogram_buckets = tuple(buckets)
240
+ super().__init__(statsd, prom, documentation, labelnames, registry)
241
+
242
+ def observe(self, value: float):
243
+ self._prom.observe(value)
244
+ if STATSD_CLIENT:
245
+ STATSD_CLIENT.timing(self._statsd, value * 1000)
246
+
247
+ def init_prometheus_metric(self, name: str, documentation: Optional[str], labelnames: Sequence[str] = ()):
248
+ return Histogram(name, documentation, labelnames=labelnames, registry=self._registry, buckets=self._histogram_buckets)
249
+
250
+ def __enter__(self):
251
+ self._stopwatch = Stopwatch()
252
+ return self
253
+
254
+ def __exit__(self, typ, value, tb):
255
+ if self._stopwatch:
256
+ self._stopwatch.stop()
257
+ self.observe(self._stopwatch.elapsed)
258
+
259
+
260
+ def _fetch_or_create_metric(
261
+ name: str,
262
+ labelnames: Optional[Sequence[str]],
263
+ container: dict[str, _T],
264
+ factory: Callable[[str, Optional[Sequence[str]]], _T]
265
+ ) -> "_T":
266
+ metric = container.get(name)
267
+ if not metric:
268
+ with METRICS_LOCK:
269
+ metric = container.get(name)
270
+ if not metric:
271
+ container[name] = metric = factory(name, labelnames)
272
+ return metric
273
+
274
+
275
+ def _fetch_or_create_counter(
276
+ name: str,
277
+ labelnames: Optional[Sequence[str]] = None,
278
+ documentation: Optional[str] = None,
279
+ registry: Optional[CollectorRegistry] = None,
280
+ ) -> _MultiCounter:
281
+ return _fetch_or_create_metric(
282
+ name=name,
283
+ labelnames=labelnames,
284
+ container=COUNTERS,
285
+ factory=lambda _name, _labelnames: _MultiCounter(statsd=_name, labelnames=_labelnames,
286
+ documentation=documentation, registry=registry)
287
+ )
288
+
289
+
290
+ def _fetch_or_create_gauge(
291
+ name: str,
292
+ labelnames: Optional[Sequence[str]] = None,
293
+ documentation: Optional[str] = None,
294
+ registry: Optional[CollectorRegistry] = None,
295
+ ) -> _MultiGauge:
296
+ return _fetch_or_create_metric(
297
+ name=name,
298
+ labelnames=labelnames,
299
+ container=GAUGES,
300
+ factory=lambda _name, _labelnames: _MultiGauge(statsd=_name, labelnames=_labelnames,
301
+ documentation=documentation, registry=registry)
302
+ )
303
+
304
+
305
+ def _fetch_or_create_timer(
306
+ name: str,
307
+ labelnames: Optional[Sequence[str]] = None,
308
+ documentation: Optional[str] = None,
309
+ registry: Optional[CollectorRegistry] = None,
310
+ buckets: Iterable[float] = _HISTOGRAM_DEFAULT_BUCKETS
311
+ ) -> _MultiTiming:
312
+ return _fetch_or_create_metric(
313
+ name=name,
314
+ labelnames=labelnames,
315
+ container=TIMINGS,
316
+ factory=lambda _name, _labels: _MultiTiming(statsd=_name, labelnames=_labels, documentation=documentation,
317
+ registry=registry, buckets=buckets)
318
+ )
319
+
320
+
321
+ class MetricManager:
322
+
323
+ """
324
+ Wrapper for metrics which prefixes them automatically with the given prefix or,
325
+ alternatively, with the path of the module.
326
+ """
327
+
328
+ def __init__(self, prefix: Optional[str] = None, module: Optional[str] = None,
329
+ registry: Optional[CollectorRegistry] = None, push_gateways: Optional[Sequence[str]] = None):
330
+ if prefix:
331
+ self.prefix = prefix
332
+ elif module:
333
+ self.prefix = module
334
+ else:
335
+ self.prefix = None
336
+ self.registry = registry or REGISTRY
337
+ self.push_gateways = push_gateways or []
338
+
339
+ def full_name(self, name: str):
340
+ if self.prefix:
341
+ return f'{self.prefix}.{name}'
342
+ return name
343
+
344
+ def get_registry(self) -> CollectorRegistry:
345
+ return self.registry
346
+
347
+ def counter(
348
+ self,
349
+ name: str,
350
+ *,
351
+ labelnames: Optional[Sequence[str]] = None,
352
+ documentation: Optional[str] = None,
353
+ ) -> _MultiCounter:
354
+ """
355
+ Log a counter.
356
+
357
+ :param name: The name (suffix) of the counter to be retrieved
358
+ :param labelnames: optional labels used to parametrize the metric
359
+ :param documentation: optional prometheus documentation for this metric
360
+ """
361
+ return _fetch_or_create_counter(name=self.full_name(name), labelnames=labelnames, documentation=documentation)
362
+
363
+ def gauge(
364
+ self,
365
+ name: str,
366
+ *,
367
+ labelnames: Optional[Sequence[str]] = None,
368
+ documentation: Optional[str] = None,
369
+ ) -> _MultiGauge:
370
+ """
371
+ Log gauge information for a single stat
372
+
373
+ :param name: The name (suffix) of the counter to be retrieved
374
+ :param labelnames: optional labels used to parametrize the metric
375
+ :param documentation: optional prometheus documentation for this metric
376
+ """
377
+ return _fetch_or_create_gauge(name=self.full_name(name), labelnames=labelnames, documentation=documentation)
378
+
379
+ def timer(
380
+ self,
381
+ name: str,
382
+ *,
383
+ labelnames: Optional[Sequence[str]] = None,
384
+ documentation: Optional[str] = None,
385
+ buckets: Iterable[float] = _HISTOGRAM_DEFAULT_BUCKETS
386
+ ) -> _MultiTiming:
387
+ """
388
+ Log a time measurement.
389
+
390
+ :param name: The name (suffix) of the counter to be retrieved
391
+ :param labelnames: optional labels used to parametrize the metric
392
+ :param documentation: optional prometheus documentation for this metric
393
+ :param buckets: Optional iterable of histogram bucket separators.
394
+ """
395
+ return _fetch_or_create_timer(name=self.full_name(name), labelnames=labelnames, documentation=documentation, buckets=buckets)
396
+
397
+ def time_it(self, original_function=None, *, buckets=_HISTOGRAM_DEFAULT_BUCKETS):
398
+ """
399
+ Function decorator which records a timer: the amount of time spent in the function.
400
+ """
401
+ def _decorator(func):
402
+ @wraps(func)
403
+ def _wrapper(*args, **kwargs):
404
+ with self.timer(name=func.__name__, buckets=buckets):
405
+ return func(*args, **kwargs)
406
+ return _wrapper
407
+ if original_function:
408
+ return _decorator(original_function)
409
+ return _decorator
410
+
411
+ def count_it(self, original_function=None):
412
+ """
413
+ Function decorator which records a counter: how many times the function was executed.
414
+ """
415
+ def _decorator(func):
416
+ @wraps(func)
417
+ def _wrapper(*args, **kwargs):
418
+ try:
419
+ return func(*args, **kwargs)
420
+ finally:
421
+ _fetch_or_create_counter(name=self.full_name(func.__name__) + '_cnt').inc()
422
+ return _wrapper
423
+ if original_function:
424
+ return _decorator(original_function)
425
+ return _decorator
426
+
427
+ def push_metrics_to_gw(self, job: Optional[str] = None, grouping_key: Optional[dict[str, Any]] = None) -> None:
428
+ """
429
+ Push the metrics out to the prometheus push gateways. This is useful for short-running programs which don't
430
+ live long enough to be reliably scraped in the prometheus pull model.
431
+ """
432
+
433
+ if not job:
434
+ job = Path(main.__file__).stem
435
+ grouping_key = grouping_key or {}
436
+
437
+ for server in self.push_gateways:
438
+ try:
439
+ push_to_gateway(server.strip(), job=job, registry=self.registry, grouping_key=grouping_key)
440
+ except:
441
+ continue
@@ -0,0 +1,154 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright European Organization for Nuclear Research (CERN) since 2012
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from re import match, compile, error
17
+ from traceback import format_exc
18
+ from typing import TYPE_CHECKING
19
+
20
+ from dogpile.cache.api import NO_VALUE
21
+ from sqlalchemy.exc import IntegrityError
22
+
23
+ from rucio.common.cache import make_region_memcached
24
+ from rucio.common.exception import Duplicate, RucioException, InvalidObject
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 sqlalchemy.orm import Session
31
+
32
+ REGION = make_region_memcached(expiration_time=900)
33
+
34
+
35
+ @transactional_session
36
+ def add_naming_convention(scope, regexp, convention_type, *, session: "Session"):
37
+ """
38
+ add a naming convention for a given scope
39
+
40
+ :param scope: the name for the scope.
41
+ :param regexp: the regular expression to validate the name.
42
+ :param convention_type: the did_type on which the regexp should apply.
43
+ :param session: The database session in use.
44
+ """
45
+ # validate the regular expression
46
+ try:
47
+ compile(regexp)
48
+ except error:
49
+ raise RucioException('Invalid regular expression %s!' % regexp)
50
+
51
+ new_convention = models.NamingConvention(scope=scope,
52
+ regexp=regexp,
53
+ convention_type=convention_type)
54
+ try:
55
+ new_convention.save(session=session)
56
+ except IntegrityError:
57
+ raise Duplicate('Naming convention already exists!')
58
+ except:
59
+ raise RucioException(str(format_exc()))
60
+
61
+
62
+ @read_session
63
+ def get_naming_convention(scope, convention_type, *, session: "Session"):
64
+ """
65
+ Get the naming convention for a given scope
66
+
67
+ :param scope: the name for the scope.
68
+ :param convention_type: the did_type on which the regexp should apply.
69
+ :param session: The database session in use.
70
+
71
+ :returns: the regular expression.
72
+ """
73
+ query = session.query(models.NamingConvention.regexp).\
74
+ filter(models.NamingConvention.scope == scope).\
75
+ filter(models.NamingConvention.convention_type == convention_type)
76
+ for row in query:
77
+ return row[0]
78
+
79
+
80
+ @transactional_session
81
+ def delete_naming_convention(scope, convention_type, *, session: "Session"):
82
+ """
83
+ delete a naming convention for a given scope
84
+
85
+ :param scope: the name for the scope.
86
+ :param regexp: the regular expression to validate the name. (DEPRECATED)
87
+ :param convention_type: the did_type on which the regexp should apply.
88
+ :param session: The database session in use.
89
+ """
90
+ REGION.delete(scope.internal)
91
+ return session.query(models.NamingConvention) \
92
+ .filter_by(scope=scope, convention_type=convention_type) \
93
+ .delete()
94
+
95
+
96
+ @read_session
97
+ def list_naming_conventions(*, session: "Session"):
98
+ """
99
+ List all naming conventions.
100
+
101
+ :param session: The database session in use.
102
+
103
+ :returns: a list of dictionaries.
104
+ """
105
+ query = session.query(models.NamingConvention.scope,
106
+ models.NamingConvention.regexp)
107
+ return [row._asdict() for row in query]
108
+
109
+
110
+ @read_session
111
+ def validate_name(scope, name, did_type, *, session: "Session"):
112
+ """
113
+ Validate a name according to a naming convention.
114
+
115
+ :param scope: the name for the scope.
116
+ :param name: the name.
117
+ :param did_type: the type of did.
118
+
119
+ :param session: The database session in use.
120
+
121
+ :returns: a dictionary with metadata.
122
+ """
123
+ if scope.external.startswith('user'):
124
+ return {'project': 'user'}
125
+ elif scope.external.startswith('group'):
126
+ return {'project': 'group'}
127
+
128
+ # Check if naming convention can be found in cache region
129
+ regexp = REGION.get(scope.internal)
130
+ if regexp is NO_VALUE: # no cached entry found
131
+ regexp = get_naming_convention(scope=scope,
132
+ convention_type=KeyType.DATASET,
133
+ session=session)
134
+ regexp and REGION.set(scope.internal, regexp)
135
+
136
+ if not regexp:
137
+ return
138
+
139
+ # Validate with regexp
140
+ groups = match(regexp, str(name))
141
+ if groups:
142
+ meta = groups.groupdict()
143
+ # Hack to get task_id from version
144
+ if 'version' in meta and meta['version']:
145
+ matched = match(r'(?P<version>\w+)_tid(?P<task_id>\d+)_\w+$', meta['version'])
146
+ if matched:
147
+ meta['version'] = matched.groupdict()['version']
148
+ meta['task_id'] = int(matched.groupdict()['task_id'])
149
+ if 'run_number' in meta and meta['run_number']:
150
+ meta['run_number'] = int(meta['run_number'])
151
+ return meta
152
+
153
+ print(f"Provided name {name} doesn't match the naming convention {regexp}")
154
+ raise InvalidObject(f"Provided name {name} doesn't match the naming convention {regexp}")