rucio 32.8.6__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (481) hide show
  1. rucio/__init__.py +18 -0
  2. rucio/alembicrevision.py +16 -0
  3. rucio/api/__init__.py +14 -0
  4. rucio/api/account.py +266 -0
  5. rucio/api/account_limit.py +287 -0
  6. rucio/api/authentication.py +302 -0
  7. rucio/api/config.py +218 -0
  8. rucio/api/credential.py +60 -0
  9. rucio/api/did.py +726 -0
  10. rucio/api/dirac.py +71 -0
  11. rucio/api/exporter.py +60 -0
  12. rucio/api/heartbeat.py +62 -0
  13. rucio/api/identity.py +160 -0
  14. rucio/api/importer.py +46 -0
  15. rucio/api/lifetime_exception.py +95 -0
  16. rucio/api/lock.py +131 -0
  17. rucio/api/meta.py +85 -0
  18. rucio/api/permission.py +72 -0
  19. rucio/api/quarantined_replica.py +69 -0
  20. rucio/api/replica.py +528 -0
  21. rucio/api/request.py +220 -0
  22. rucio/api/rse.py +601 -0
  23. rucio/api/rule.py +335 -0
  24. rucio/api/scope.py +89 -0
  25. rucio/api/subscription.py +255 -0
  26. rucio/api/temporary_did.py +49 -0
  27. rucio/api/vo.py +112 -0
  28. rucio/client/__init__.py +16 -0
  29. rucio/client/accountclient.py +413 -0
  30. rucio/client/accountlimitclient.py +155 -0
  31. rucio/client/baseclient.py +929 -0
  32. rucio/client/client.py +77 -0
  33. rucio/client/configclient.py +113 -0
  34. rucio/client/credentialclient.py +54 -0
  35. rucio/client/didclient.py +691 -0
  36. rucio/client/diracclient.py +48 -0
  37. rucio/client/downloadclient.py +1674 -0
  38. rucio/client/exportclient.py +44 -0
  39. rucio/client/fileclient.py +51 -0
  40. rucio/client/importclient.py +42 -0
  41. rucio/client/lifetimeclient.py +74 -0
  42. rucio/client/lockclient.py +99 -0
  43. rucio/client/metaclient.py +137 -0
  44. rucio/client/pingclient.py +45 -0
  45. rucio/client/replicaclient.py +444 -0
  46. rucio/client/requestclient.py +109 -0
  47. rucio/client/rseclient.py +664 -0
  48. rucio/client/ruleclient.py +287 -0
  49. rucio/client/scopeclient.py +88 -0
  50. rucio/client/subscriptionclient.py +161 -0
  51. rucio/client/touchclient.py +78 -0
  52. rucio/client/uploadclient.py +871 -0
  53. rucio/common/__init__.py +14 -0
  54. rucio/common/cache.py +74 -0
  55. rucio/common/config.py +796 -0
  56. rucio/common/constants.py +92 -0
  57. rucio/common/constraints.py +18 -0
  58. rucio/common/didtype.py +187 -0
  59. rucio/common/dumper/__init__.py +306 -0
  60. rucio/common/dumper/consistency.py +449 -0
  61. rucio/common/dumper/data_models.py +325 -0
  62. rucio/common/dumper/path_parsing.py +65 -0
  63. rucio/common/exception.py +1092 -0
  64. rucio/common/extra.py +37 -0
  65. rucio/common/logging.py +404 -0
  66. rucio/common/pcache.py +1387 -0
  67. rucio/common/policy.py +84 -0
  68. rucio/common/schema/__init__.py +143 -0
  69. rucio/common/schema/atlas.py +411 -0
  70. rucio/common/schema/belleii.py +406 -0
  71. rucio/common/schema/cms.py +478 -0
  72. rucio/common/schema/domatpc.py +399 -0
  73. rucio/common/schema/escape.py +424 -0
  74. rucio/common/schema/generic.py +431 -0
  75. rucio/common/schema/generic_multi_vo.py +410 -0
  76. rucio/common/schema/icecube.py +404 -0
  77. rucio/common/schema/lsst.py +423 -0
  78. rucio/common/stomp_utils.py +160 -0
  79. rucio/common/stopwatch.py +56 -0
  80. rucio/common/test_rucio_server.py +148 -0
  81. rucio/common/types.py +158 -0
  82. rucio/common/utils.py +1946 -0
  83. rucio/core/__init__.py +14 -0
  84. rucio/core/account.py +426 -0
  85. rucio/core/account_counter.py +171 -0
  86. rucio/core/account_limit.py +357 -0
  87. rucio/core/authentication.py +563 -0
  88. rucio/core/config.py +386 -0
  89. rucio/core/credential.py +218 -0
  90. rucio/core/did.py +3102 -0
  91. rucio/core/did_meta_plugins/__init__.py +250 -0
  92. rucio/core/did_meta_plugins/did_column_meta.py +326 -0
  93. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +116 -0
  94. rucio/core/did_meta_plugins/filter_engine.py +573 -0
  95. rucio/core/did_meta_plugins/json_meta.py +215 -0
  96. rucio/core/did_meta_plugins/mongo_meta.py +199 -0
  97. rucio/core/did_meta_plugins/postgres_meta.py +317 -0
  98. rucio/core/dirac.py +208 -0
  99. rucio/core/distance.py +164 -0
  100. rucio/core/exporter.py +59 -0
  101. rucio/core/heartbeat.py +263 -0
  102. rucio/core/identity.py +290 -0
  103. rucio/core/importer.py +248 -0
  104. rucio/core/lifetime_exception.py +377 -0
  105. rucio/core/lock.py +474 -0
  106. rucio/core/message.py +241 -0
  107. rucio/core/meta.py +190 -0
  108. rucio/core/monitor.py +441 -0
  109. rucio/core/naming_convention.py +154 -0
  110. rucio/core/nongrid_trace.py +124 -0
  111. rucio/core/oidc.py +1339 -0
  112. rucio/core/permission/__init__.py +107 -0
  113. rucio/core/permission/atlas.py +1333 -0
  114. rucio/core/permission/belleii.py +1076 -0
  115. rucio/core/permission/cms.py +1166 -0
  116. rucio/core/permission/escape.py +1076 -0
  117. rucio/core/permission/generic.py +1128 -0
  118. rucio/core/permission/generic_multi_vo.py +1148 -0
  119. rucio/core/quarantined_replica.py +190 -0
  120. rucio/core/replica.py +3627 -0
  121. rucio/core/replica_sorter.py +368 -0
  122. rucio/core/request.py +2241 -0
  123. rucio/core/rse.py +1835 -0
  124. rucio/core/rse_counter.py +155 -0
  125. rucio/core/rse_expression_parser.py +460 -0
  126. rucio/core/rse_selector.py +277 -0
  127. rucio/core/rule.py +3419 -0
  128. rucio/core/rule_grouping.py +1473 -0
  129. rucio/core/scope.py +152 -0
  130. rucio/core/subscription.py +316 -0
  131. rucio/core/temporary_did.py +188 -0
  132. rucio/core/topology.py +448 -0
  133. rucio/core/trace.py +361 -0
  134. rucio/core/transfer.py +1233 -0
  135. rucio/core/vo.py +151 -0
  136. rucio/core/volatile_replica.py +123 -0
  137. rucio/daemons/__init__.py +14 -0
  138. rucio/daemons/abacus/__init__.py +14 -0
  139. rucio/daemons/abacus/account.py +106 -0
  140. rucio/daemons/abacus/collection_replica.py +113 -0
  141. rucio/daemons/abacus/rse.py +107 -0
  142. rucio/daemons/atropos/__init__.py +14 -0
  143. rucio/daemons/atropos/atropos.py +243 -0
  144. rucio/daemons/auditor/__init__.py +261 -0
  145. rucio/daemons/auditor/hdfs.py +86 -0
  146. rucio/daemons/auditor/srmdumps.py +284 -0
  147. rucio/daemons/automatix/__init__.py +14 -0
  148. rucio/daemons/automatix/automatix.py +281 -0
  149. rucio/daemons/badreplicas/__init__.py +14 -0
  150. rucio/daemons/badreplicas/minos.py +311 -0
  151. rucio/daemons/badreplicas/minos_temporary_expiration.py +173 -0
  152. rucio/daemons/badreplicas/necromancer.py +200 -0
  153. rucio/daemons/bb8/__init__.py +14 -0
  154. rucio/daemons/bb8/bb8.py +356 -0
  155. rucio/daemons/bb8/common.py +762 -0
  156. rucio/daemons/bb8/nuclei_background_rebalance.py +147 -0
  157. rucio/daemons/bb8/t2_background_rebalance.py +146 -0
  158. rucio/daemons/c3po/__init__.py +14 -0
  159. rucio/daemons/c3po/algorithms/__init__.py +14 -0
  160. rucio/daemons/c3po/algorithms/simple.py +131 -0
  161. rucio/daemons/c3po/algorithms/t2_free_space.py +125 -0
  162. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +127 -0
  163. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +279 -0
  164. rucio/daemons/c3po/c3po.py +342 -0
  165. rucio/daemons/c3po/collectors/__init__.py +14 -0
  166. rucio/daemons/c3po/collectors/agis.py +108 -0
  167. rucio/daemons/c3po/collectors/free_space.py +62 -0
  168. rucio/daemons/c3po/collectors/jedi_did.py +48 -0
  169. rucio/daemons/c3po/collectors/mock_did.py +46 -0
  170. rucio/daemons/c3po/collectors/network_metrics.py +63 -0
  171. rucio/daemons/c3po/collectors/workload.py +110 -0
  172. rucio/daemons/c3po/utils/__init__.py +14 -0
  173. rucio/daemons/c3po/utils/dataset_cache.py +40 -0
  174. rucio/daemons/c3po/utils/expiring_dataset_cache.py +45 -0
  175. rucio/daemons/c3po/utils/expiring_list.py +63 -0
  176. rucio/daemons/c3po/utils/popularity.py +82 -0
  177. rucio/daemons/c3po/utils/timeseries.py +76 -0
  178. rucio/daemons/cache/__init__.py +14 -0
  179. rucio/daemons/cache/consumer.py +191 -0
  180. rucio/daemons/common.py +391 -0
  181. rucio/daemons/conveyor/__init__.py +14 -0
  182. rucio/daemons/conveyor/common.py +530 -0
  183. rucio/daemons/conveyor/finisher.py +492 -0
  184. rucio/daemons/conveyor/poller.py +372 -0
  185. rucio/daemons/conveyor/preparer.py +198 -0
  186. rucio/daemons/conveyor/receiver.py +206 -0
  187. rucio/daemons/conveyor/stager.py +127 -0
  188. rucio/daemons/conveyor/submitter.py +379 -0
  189. rucio/daemons/conveyor/throttler.py +468 -0
  190. rucio/daemons/follower/__init__.py +14 -0
  191. rucio/daemons/follower/follower.py +97 -0
  192. rucio/daemons/hermes/__init__.py +14 -0
  193. rucio/daemons/hermes/hermes.py +738 -0
  194. rucio/daemons/judge/__init__.py +14 -0
  195. rucio/daemons/judge/cleaner.py +149 -0
  196. rucio/daemons/judge/evaluator.py +172 -0
  197. rucio/daemons/judge/injector.py +154 -0
  198. rucio/daemons/judge/repairer.py +144 -0
  199. rucio/daemons/oauthmanager/__init__.py +14 -0
  200. rucio/daemons/oauthmanager/oauthmanager.py +199 -0
  201. rucio/daemons/reaper/__init__.py +14 -0
  202. rucio/daemons/reaper/dark_reaper.py +272 -0
  203. rucio/daemons/reaper/light_reaper.py +255 -0
  204. rucio/daemons/reaper/reaper.py +701 -0
  205. rucio/daemons/replicarecoverer/__init__.py +14 -0
  206. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +487 -0
  207. rucio/daemons/storage/__init__.py +14 -0
  208. rucio/daemons/storage/consistency/__init__.py +14 -0
  209. rucio/daemons/storage/consistency/actions.py +753 -0
  210. rucio/daemons/tracer/__init__.py +14 -0
  211. rucio/daemons/tracer/kronos.py +513 -0
  212. rucio/daemons/transmogrifier/__init__.py +14 -0
  213. rucio/daemons/transmogrifier/transmogrifier.py +753 -0
  214. rucio/daemons/undertaker/__init__.py +14 -0
  215. rucio/daemons/undertaker/undertaker.py +137 -0
  216. rucio/db/__init__.py +14 -0
  217. rucio/db/sqla/__init__.py +38 -0
  218. rucio/db/sqla/constants.py +192 -0
  219. rucio/db/sqla/migrate_repo/__init__.py +14 -0
  220. rucio/db/sqla/migrate_repo/env.py +111 -0
  221. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +71 -0
  222. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +50 -0
  223. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +61 -0
  224. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +46 -0
  225. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +93 -0
  226. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +78 -0
  227. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +46 -0
  228. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +53 -0
  229. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +69 -0
  230. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +42 -0
  231. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +46 -0
  232. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +61 -0
  233. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +42 -0
  234. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +141 -0
  235. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +75 -0
  236. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +75 -0
  237. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +46 -0
  238. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +51 -0
  239. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +135 -0
  240. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +65 -0
  241. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +42 -0
  242. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +66 -0
  243. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +54 -0
  244. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +43 -0
  245. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +46 -0
  246. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +47 -0
  247. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +54 -0
  248. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +39 -0
  249. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +48 -0
  250. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +47 -0
  251. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +48 -0
  252. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +59 -0
  253. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +47 -0
  254. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +72 -0
  255. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +46 -0
  256. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +45 -0
  257. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +48 -0
  258. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +48 -0
  259. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +42 -0
  260. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +69 -0
  261. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +46 -0
  262. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +78 -0
  263. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +62 -0
  264. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +74 -0
  265. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +44 -0
  266. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +67 -0
  267. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +134 -0
  268. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +58 -0
  269. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +79 -0
  270. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +61 -0
  271. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +45 -0
  272. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +46 -0
  273. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +65 -0
  274. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +42 -0
  275. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +46 -0
  276. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +46 -0
  277. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +80 -0
  278. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +43 -0
  279. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +61 -0
  280. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +47 -0
  281. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +46 -0
  282. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +52 -0
  283. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +42 -0
  284. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +65 -0
  285. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +46 -0
  286. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +47 -0
  287. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +45 -0
  288. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +46 -0
  289. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +48 -0
  290. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +50 -0
  291. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +59 -0
  292. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +48 -0
  293. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +108 -0
  294. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +57 -0
  295. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +51 -0
  296. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +50 -0
  297. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +46 -0
  298. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +42 -0
  299. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +93 -0
  300. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +73 -0
  301. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +52 -0
  302. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +45 -0
  303. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +46 -0
  304. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +54 -0
  305. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +48 -0
  306. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +70 -0
  307. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +48 -0
  308. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +95 -0
  309. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +55 -0
  310. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +74 -0
  311. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +78 -0
  312. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +49 -0
  313. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +124 -0
  314. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +60 -0
  315. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +53 -0
  316. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +56 -0
  317. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +67 -0
  318. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +50 -0
  319. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +46 -0
  320. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +92 -0
  321. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +42 -0
  322. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +46 -0
  323. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +147 -0
  324. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +78 -0
  325. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +53 -0
  326. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +74 -0
  327. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +56 -0
  328. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +46 -0
  329. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +68 -0
  330. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +48 -0
  331. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +149 -0
  332. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +106 -0
  333. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +47 -0
  334. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +45 -0
  335. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +105 -0
  336. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +52 -0
  337. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +106 -0
  338. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +30 -0
  339. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +75 -0
  340. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +49 -0
  341. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +45 -0
  342. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +38 -0
  343. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +44 -0
  344. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +46 -0
  345. rucio/db/sqla/models.py +1834 -0
  346. rucio/db/sqla/sautils.py +48 -0
  347. rucio/db/sqla/session.py +470 -0
  348. rucio/db/sqla/types.py +207 -0
  349. rucio/db/sqla/util.py +521 -0
  350. rucio/rse/__init__.py +97 -0
  351. rucio/rse/protocols/__init__.py +14 -0
  352. rucio/rse/protocols/cache.py +123 -0
  353. rucio/rse/protocols/dummy.py +112 -0
  354. rucio/rse/protocols/gfal.py +701 -0
  355. rucio/rse/protocols/globus.py +243 -0
  356. rucio/rse/protocols/gsiftp.py +93 -0
  357. rucio/rse/protocols/http_cache.py +83 -0
  358. rucio/rse/protocols/mock.py +124 -0
  359. rucio/rse/protocols/ngarc.py +210 -0
  360. rucio/rse/protocols/posix.py +251 -0
  361. rucio/rse/protocols/protocol.py +530 -0
  362. rucio/rse/protocols/rclone.py +365 -0
  363. rucio/rse/protocols/rfio.py +137 -0
  364. rucio/rse/protocols/srm.py +339 -0
  365. rucio/rse/protocols/ssh.py +414 -0
  366. rucio/rse/protocols/storm.py +207 -0
  367. rucio/rse/protocols/webdav.py +547 -0
  368. rucio/rse/protocols/xrootd.py +295 -0
  369. rucio/rse/rsemanager.py +752 -0
  370. rucio/tests/__init__.py +14 -0
  371. rucio/tests/common.py +244 -0
  372. rucio/tests/common_server.py +132 -0
  373. rucio/transfertool/__init__.py +14 -0
  374. rucio/transfertool/fts3.py +1484 -0
  375. rucio/transfertool/globus.py +200 -0
  376. rucio/transfertool/globus_library.py +182 -0
  377. rucio/transfertool/mock.py +81 -0
  378. rucio/transfertool/transfertool.py +212 -0
  379. rucio/vcsversion.py +11 -0
  380. rucio/version.py +46 -0
  381. rucio/web/__init__.py +14 -0
  382. rucio/web/rest/__init__.py +14 -0
  383. rucio/web/rest/flaskapi/__init__.py +14 -0
  384. rucio/web/rest/flaskapi/authenticated_bp.py +28 -0
  385. rucio/web/rest/flaskapi/v1/__init__.py +14 -0
  386. rucio/web/rest/flaskapi/v1/accountlimits.py +234 -0
  387. rucio/web/rest/flaskapi/v1/accounts.py +1088 -0
  388. rucio/web/rest/flaskapi/v1/archives.py +100 -0
  389. rucio/web/rest/flaskapi/v1/auth.py +1642 -0
  390. rucio/web/rest/flaskapi/v1/common.py +385 -0
  391. rucio/web/rest/flaskapi/v1/config.py +305 -0
  392. rucio/web/rest/flaskapi/v1/credentials.py +213 -0
  393. rucio/web/rest/flaskapi/v1/dids.py +2204 -0
  394. rucio/web/rest/flaskapi/v1/dirac.py +116 -0
  395. rucio/web/rest/flaskapi/v1/export.py +77 -0
  396. rucio/web/rest/flaskapi/v1/heartbeats.py +129 -0
  397. rucio/web/rest/flaskapi/v1/identities.py +263 -0
  398. rucio/web/rest/flaskapi/v1/import.py +133 -0
  399. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +315 -0
  400. rucio/web/rest/flaskapi/v1/locks.py +360 -0
  401. rucio/web/rest/flaskapi/v1/main.py +83 -0
  402. rucio/web/rest/flaskapi/v1/meta.py +226 -0
  403. rucio/web/rest/flaskapi/v1/metrics.py +37 -0
  404. rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
  405. rucio/web/rest/flaskapi/v1/ping.py +89 -0
  406. rucio/web/rest/flaskapi/v1/redirect.py +366 -0
  407. rucio/web/rest/flaskapi/v1/replicas.py +1866 -0
  408. rucio/web/rest/flaskapi/v1/requests.py +841 -0
  409. rucio/web/rest/flaskapi/v1/rses.py +2204 -0
  410. rucio/web/rest/flaskapi/v1/rules.py +824 -0
  411. rucio/web/rest/flaskapi/v1/scopes.py +161 -0
  412. rucio/web/rest/flaskapi/v1/subscriptions.py +646 -0
  413. rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
  414. rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
  415. rucio/web/rest/flaskapi/v1/tmp_dids.py +115 -0
  416. rucio/web/rest/flaskapi/v1/traces.py +100 -0
  417. rucio/web/rest/flaskapi/v1/vos.py +280 -0
  418. rucio/web/rest/main.py +19 -0
  419. rucio/web/rest/metrics.py +28 -0
  420. rucio-32.8.6.data/data/rucio/etc/alembic.ini.template +71 -0
  421. rucio-32.8.6.data/data/rucio/etc/alembic_offline.ini.template +74 -0
  422. rucio-32.8.6.data/data/rucio/etc/globus-config.yml.template +5 -0
  423. rucio-32.8.6.data/data/rucio/etc/ldap.cfg.template +30 -0
  424. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
  425. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
  426. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
  427. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
  428. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
  429. rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
  430. rucio-32.8.6.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
  431. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.atlas.client.template +42 -0
  432. rucio-32.8.6.data/data/rucio/etc/rucio.cfg.template +257 -0
  433. rucio-32.8.6.data/data/rucio/etc/rucio_multi_vo.cfg.template +234 -0
  434. rucio-32.8.6.data/data/rucio/requirements.txt +55 -0
  435. rucio-32.8.6.data/data/rucio/tools/bootstrap.py +34 -0
  436. rucio-32.8.6.data/data/rucio/tools/merge_rucio_configs.py +147 -0
  437. rucio-32.8.6.data/data/rucio/tools/reset_database.py +40 -0
  438. rucio-32.8.6.data/scripts/rucio +2540 -0
  439. rucio-32.8.6.data/scripts/rucio-abacus-account +75 -0
  440. rucio-32.8.6.data/scripts/rucio-abacus-collection-replica +47 -0
  441. rucio-32.8.6.data/scripts/rucio-abacus-rse +79 -0
  442. rucio-32.8.6.data/scripts/rucio-admin +2434 -0
  443. rucio-32.8.6.data/scripts/rucio-atropos +61 -0
  444. rucio-32.8.6.data/scripts/rucio-auditor +199 -0
  445. rucio-32.8.6.data/scripts/rucio-automatix +51 -0
  446. rucio-32.8.6.data/scripts/rucio-bb8 +58 -0
  447. rucio-32.8.6.data/scripts/rucio-c3po +86 -0
  448. rucio-32.8.6.data/scripts/rucio-cache-client +135 -0
  449. rucio-32.8.6.data/scripts/rucio-cache-consumer +43 -0
  450. rucio-32.8.6.data/scripts/rucio-conveyor-finisher +59 -0
  451. rucio-32.8.6.data/scripts/rucio-conveyor-poller +67 -0
  452. rucio-32.8.6.data/scripts/rucio-conveyor-preparer +38 -0
  453. rucio-32.8.6.data/scripts/rucio-conveyor-receiver +44 -0
  454. rucio-32.8.6.data/scripts/rucio-conveyor-stager +77 -0
  455. rucio-32.8.6.data/scripts/rucio-conveyor-submitter +140 -0
  456. rucio-32.8.6.data/scripts/rucio-conveyor-throttler +105 -0
  457. rucio-32.8.6.data/scripts/rucio-dark-reaper +54 -0
  458. rucio-32.8.6.data/scripts/rucio-dumper +159 -0
  459. rucio-32.8.6.data/scripts/rucio-follower +45 -0
  460. rucio-32.8.6.data/scripts/rucio-hermes +55 -0
  461. rucio-32.8.6.data/scripts/rucio-judge-cleaner +90 -0
  462. rucio-32.8.6.data/scripts/rucio-judge-evaluator +138 -0
  463. rucio-32.8.6.data/scripts/rucio-judge-injector +45 -0
  464. rucio-32.8.6.data/scripts/rucio-judge-repairer +45 -0
  465. rucio-32.8.6.data/scripts/rucio-kronos +45 -0
  466. rucio-32.8.6.data/scripts/rucio-light-reaper +53 -0
  467. rucio-32.8.6.data/scripts/rucio-minos +54 -0
  468. rucio-32.8.6.data/scripts/rucio-minos-temporary-expiration +51 -0
  469. rucio-32.8.6.data/scripts/rucio-necromancer +121 -0
  470. rucio-32.8.6.data/scripts/rucio-oauth-manager +64 -0
  471. rucio-32.8.6.data/scripts/rucio-reaper +84 -0
  472. rucio-32.8.6.data/scripts/rucio-replica-recoverer +249 -0
  473. rucio-32.8.6.data/scripts/rucio-storage-consistency-actions +75 -0
  474. rucio-32.8.6.data/scripts/rucio-transmogrifier +78 -0
  475. rucio-32.8.6.data/scripts/rucio-undertaker +77 -0
  476. rucio-32.8.6.dist-info/METADATA +83 -0
  477. rucio-32.8.6.dist-info/RECORD +481 -0
  478. rucio-32.8.6.dist-info/WHEEL +5 -0
  479. rucio-32.8.6.dist-info/licenses/AUTHORS.rst +94 -0
  480. rucio-32.8.6.dist-info/licenses/LICENSE +201 -0
  481. rucio-32.8.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1088 @@
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 datetime import datetime
17
+ from json import dumps
18
+
19
+ from flask import Flask, Response, request, redirect, jsonify
20
+
21
+ from rucio.api.account import add_account, del_account, get_account_info, list_accounts, list_identities, \
22
+ list_account_attributes, add_account_attribute, del_account_attribute, update_account, get_usage_history
23
+ from rucio.api.account_limit import get_local_account_limits, get_local_account_limit, get_local_account_usage, \
24
+ get_global_account_limit, get_global_account_limits, get_global_account_usage
25
+ from rucio.api.identity import add_account_identity, del_account_identity
26
+ from rucio.api.rule import list_replication_rules
27
+ from rucio.api.scope import add_scope, get_scopes
28
+ from rucio.common.exception import AccountNotFound, Duplicate, AccessDenied, RuleNotFound, RSENotFound, \
29
+ IdentityError, CounterNotFound, ScopeNotFound, InvalidObject
30
+ from rucio.common.utils import APIEncoder, render_json
31
+ from rucio.web.rest.flaskapi.authenticated_bp import AuthenticatedBlueprint
32
+ from rucio.web.rest.flaskapi.v1.common import response_headers, check_accept_header_wrapper_flask, \
33
+ try_stream, generate_http_error_flask, ErrorHandlingMethodView, json_parameters, param_get
34
+
35
+
36
+ class Attributes(ErrorHandlingMethodView):
37
+
38
+ @check_accept_header_wrapper_flask(['application/json'])
39
+ def get(self, account):
40
+ """
41
+ ---
42
+ summary: List attributes
43
+ description: List all attributes for an account.
44
+ tags:
45
+ - Account
46
+ parameters:
47
+ - name: account
48
+ in: path
49
+ description: The account identifier.
50
+ schema:
51
+ type: string
52
+ style: simple
53
+ responses:
54
+ 200:
55
+ description: OK
56
+ content:
57
+ application/json:
58
+ schema:
59
+ type: array
60
+ items:
61
+ type: object
62
+ description: An account attribute.
63
+ properties:
64
+ key:
65
+ description: The key of the account attribute.
66
+ type: string
67
+ value:
68
+ description: The value of the account attribute.
69
+ type: string
70
+ 401:
71
+ description: Invalid Auth Token
72
+ 404:
73
+ description: No account found for the given id.
74
+ 406:
75
+ description: Not acceptable.
76
+ """
77
+ try:
78
+ attribs = list_account_attributes(account, vo=request.environ.get('vo'))
79
+ except AccountNotFound as error:
80
+ return generate_http_error_flask(404, error)
81
+
82
+ return jsonify(attribs)
83
+
84
+ def post(self, account, key):
85
+ """
86
+ ---
87
+ summary: Create attribute
88
+ description: Create an attribute to an account.
89
+ tags:
90
+ - Account
91
+ parameters:
92
+ - name: account
93
+ in: path
94
+ description: The account identifier.
95
+ schema:
96
+ type: string
97
+ style: simple
98
+ - name: key
99
+ in: path
100
+ description: The key of the account attribute.
101
+ schema:
102
+ type: string
103
+ style: simple
104
+ requestBody:
105
+ content:
106
+ 'application/json':
107
+ schema:
108
+ type: object
109
+ required:
110
+ - value
111
+ properties:
112
+ key:
113
+ description: The key of the attribute. This would override the key defined in path.
114
+ type: string
115
+ value:
116
+ description: The value of the attribute.
117
+ type: string
118
+ responses:
119
+ 201:
120
+ description: OK
121
+ content:
122
+ application/json:
123
+ schema:
124
+ type: string
125
+ enum: ["Created"]
126
+ 401:
127
+ description: Invalid Auth Token
128
+ 404:
129
+ description: No account found for the given id.
130
+ 409:
131
+ description: Attribute already exists
132
+ """
133
+ parameters = json_parameters()
134
+ value = param_get(parameters, 'value')
135
+ try:
136
+ add_account_attribute(key=key, value=value, account=account, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
137
+ except AccessDenied as error:
138
+ return generate_http_error_flask(401, error)
139
+ except Duplicate as error:
140
+ return generate_http_error_flask(409, error)
141
+ except AccountNotFound as error:
142
+ return generate_http_error_flask(404, error)
143
+
144
+ return 'Created', 201
145
+
146
+ def delete(self, account, key):
147
+ """
148
+ ---
149
+ summary: Delete attribute
150
+ description: Delete an attribute of an account.
151
+ tags:
152
+ - Account
153
+ parameters:
154
+ - name: account
155
+ in: path
156
+ description: The account identifier.
157
+ schema:
158
+ type: string
159
+ style: simple
160
+ - name: key
161
+ in: path
162
+ description: The key of the account attribute to remove.
163
+ schema:
164
+ type: string
165
+ style: simple
166
+ responses:
167
+ 200:
168
+ description: OK
169
+ 401:
170
+ description: Invalid Auth Token
171
+ 404:
172
+ description: No account found for the given id.
173
+ """
174
+ try:
175
+ del_account_attribute(account=account, key=key, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
176
+ except AccessDenied as error:
177
+ return generate_http_error_flask(401, error)
178
+ except AccountNotFound as error:
179
+ return generate_http_error_flask(404, error)
180
+
181
+ return '', 200
182
+
183
+
184
+ class Scopes(ErrorHandlingMethodView):
185
+ @check_accept_header_wrapper_flask(['application/json'])
186
+ def get(self, account):
187
+ """
188
+ ---
189
+ summary: List scopes
190
+ description: List all scopse for an account.
191
+ tags:
192
+ - Account
193
+ parameters:
194
+ - name: account
195
+ in: path
196
+ description: The account identifier.
197
+ schema:
198
+ type: string
199
+ style: simple
200
+ responses:
201
+ 200:
202
+ description: OK
203
+ content:
204
+ application/x-json-stream:
205
+ schema:
206
+ description: All scopes for the account.
207
+ type: array
208
+ items:
209
+ description: A scope
210
+ type: string
211
+ 401:
212
+ description: Invalid Auth Token
213
+ 404:
214
+ description: No account or scope found for the given id.
215
+ 406:
216
+ description: Not acceptable
217
+ """
218
+ try:
219
+ scopes = get_scopes(account, vo=request.environ.get('vo'))
220
+ except AccountNotFound as error:
221
+ return generate_http_error_flask(404, error)
222
+
223
+ if not len(scopes):
224
+ return generate_http_error_flask(404, ScopeNotFound.__name__, f"no scopes found for account ID '{account}'")
225
+
226
+ return jsonify(scopes)
227
+
228
+ def post(self, account, scope):
229
+ """
230
+ ---
231
+ summary: Create scope
232
+ description: Creates a scopse with the given name for an account.
233
+ tags:
234
+ - Account
235
+ parameters:
236
+ - name: account
237
+ in: path
238
+ description: The account identifier.
239
+ schema:
240
+ type: string
241
+ style: simple
242
+ - name: scope
243
+ in: path
244
+ description: The scope name.
245
+ schema:
246
+ type: string
247
+ style: simple
248
+ responses:
249
+ 201:
250
+ description: OK
251
+ content:
252
+ application/json:
253
+ schema:
254
+ type: string
255
+ enum: ["Created"]
256
+ 400:
257
+ description: Not acceptable
258
+ 401:
259
+ description: Invalid Auth Token
260
+ 404:
261
+ description: No account found.
262
+ 409:
263
+ description: Scope already exists.
264
+ """
265
+ try:
266
+ add_scope(scope, account, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
267
+ except InvalidObject as error:
268
+ return generate_http_error_flask(400, error)
269
+ except AccessDenied as error:
270
+ return generate_http_error_flask(401, error)
271
+ except Duplicate as error:
272
+ return generate_http_error_flask(409, error)
273
+ except AccountNotFound as error:
274
+ return generate_http_error_flask(404, error)
275
+
276
+ return 'Created', 201
277
+
278
+
279
+ class AccountParameter(ErrorHandlingMethodView):
280
+ """ create, update, get and disable rucio accounts. """
281
+
282
+ @check_accept_header_wrapper_flask(['application/json'])
283
+ def get(self, account):
284
+ """
285
+ ---
286
+ summary: List account parameters
287
+ description: Lists all parameters for an account.
288
+ tags:
289
+ - Account
290
+ parameters:
291
+ - name: account
292
+ in: path
293
+ description: The account identifier.
294
+ schema:
295
+ type: string
296
+ style: simple
297
+ responses:
298
+ 201:
299
+ description: OK
300
+ content:
301
+ application/json:
302
+ schema:
303
+ type: object
304
+ properties:
305
+ account:
306
+ description: The account identifier.
307
+ type: string
308
+ account_type:
309
+ description: The account type.
310
+ type: string
311
+ status:
312
+ description: The account status.
313
+ type: string
314
+ email:
315
+ description: The email for the account.
316
+ type: string
317
+ suspended_at:
318
+ description: Datetime if the account was suspended.
319
+ type: string
320
+ deleted_at:
321
+ description: Datetime if the account was deleted.
322
+ type: string
323
+ 401:
324
+ description: Invalid Auth Token
325
+ 404:
326
+ description: No account found.
327
+ 406:
328
+ description: Not acceptable
329
+ """
330
+ if account == 'whoami':
331
+ # Redirect to the account uri
332
+ frontend = request.headers.get('X-Requested-Host', default=None)
333
+ if frontend:
334
+ return redirect(f'{frontend}/accounts/{request.environ.get("issuer")}', code=302)
335
+ return redirect(request.environ.get('issuer'), code=303)
336
+
337
+ try:
338
+ acc = get_account_info(account, vo=request.environ.get('vo'))
339
+ except AccountNotFound as error:
340
+ return generate_http_error_flask(404, error)
341
+ except AccessDenied as error:
342
+ return generate_http_error_flask(401, error)
343
+
344
+ accdict = acc.to_dict()
345
+
346
+ for key, value in accdict.items():
347
+ if isinstance(value, datetime):
348
+ accdict[key] = value.strftime('%Y-%m-%dT%H:%M:%S')
349
+
350
+ return Response(render_json(**accdict), content_type="application/json")
351
+
352
+ def put(self, account):
353
+ """
354
+ ---
355
+ summary: Update
356
+ description: Update a parameter for an account.
357
+ tags:
358
+ - Account
359
+ parameters:
360
+ - name: account
361
+ in: path
362
+ description: The account identifier.
363
+ schema:
364
+ type: string
365
+ style: simple
366
+ requestBody:
367
+ content:
368
+ 'application/json':
369
+ schema:
370
+ description: Json object with key-value pairs corresponding to the new values of the parameters.
371
+ type: object
372
+ responses:
373
+ 200:
374
+ description: OK
375
+ 401:
376
+ description: Invalid Auth Token
377
+ 404:
378
+ description: No account found.
379
+ 400:
380
+ description: Unknown status
381
+ """
382
+ parameters = json_parameters()
383
+ for key, value in parameters.items():
384
+ try:
385
+ update_account(account, key=key, value=value, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
386
+ except ValueError:
387
+ return generate_http_error_flask(400, ValueError.__name__, f'Unknown value {value}')
388
+ except AccessDenied as error:
389
+ return generate_http_error_flask(401, error)
390
+ except AccountNotFound as error:
391
+ return generate_http_error_flask(404, error)
392
+
393
+ return '', 200
394
+
395
+ def post(self, account):
396
+ """
397
+ ---
398
+ summary: Create
399
+ description: Create an account.
400
+ tags:
401
+ - Account
402
+ parameters:
403
+ - name: account
404
+ in: path
405
+ description: The account identifier.
406
+ schema:
407
+ type: string
408
+ style: simple
409
+ requestBody:
410
+ content:
411
+ 'application/json':
412
+ schema:
413
+ type: object
414
+ required:
415
+ - type
416
+ - email
417
+ properties:
418
+ type:
419
+ description: The account type.
420
+ type: string
421
+ enum: ["USER", "GROUP", "SERVICE"]
422
+ email:
423
+ description: The email for the account.
424
+ type: string
425
+ responses:
426
+ 201:
427
+ description: OK
428
+ content:
429
+ application/json:
430
+ schema:
431
+ type: string
432
+ enum: ["Created"]
433
+ 401:
434
+ description: Invalid Auth Token
435
+ 409:
436
+ description: Account already exists
437
+ 400:
438
+ description: Unknown status
439
+ """
440
+ parameters = json_parameters()
441
+ type_param = param_get(parameters, 'type')
442
+ email = param_get(parameters, 'email')
443
+ try:
444
+ add_account(account, type_param, email, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
445
+ except Duplicate as error:
446
+ return generate_http_error_flask(409, error)
447
+ except AccessDenied as error:
448
+ return generate_http_error_flask(401, error)
449
+ except InvalidObject as error:
450
+ return generate_http_error_flask(400, error)
451
+
452
+ return 'Created', 201
453
+
454
+ def delete(self, account):
455
+ """
456
+ ---
457
+ summary: Delete
458
+ description: Delete an account.
459
+ tags:
460
+ - Account
461
+ parameters:
462
+ - name: account
463
+ in: path
464
+ description: The account identifier.
465
+ schema:
466
+ type: string
467
+ style: simple
468
+ responses:
469
+ 201:
470
+ description: OK
471
+ 401:
472
+ description: Invalid Auth Token
473
+ 404:
474
+ description: Account not found
475
+ """
476
+ try:
477
+ del_account(account, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
478
+ except AccessDenied as error:
479
+ return generate_http_error_flask(401, error)
480
+ except AccountNotFound as error:
481
+ return generate_http_error_flask(404, error)
482
+
483
+ return '', 200
484
+
485
+
486
+ class Account(ErrorHandlingMethodView):
487
+ @check_accept_header_wrapper_flask(['application/x-json-stream'])
488
+ def get(self):
489
+ """
490
+ ---
491
+ summary: List
492
+ description: List all accounts.
493
+ tags:
494
+ - Account
495
+ responses:
496
+ 200:
497
+ description: OK
498
+ content:
499
+ application/x-json-stream:
500
+ schema:
501
+ type: array
502
+ items:
503
+ type: object
504
+ properties:
505
+ account:
506
+ description: The account identifier.
507
+ type: string
508
+ type:
509
+ description: The type.
510
+ type: string
511
+ email:
512
+ description: The email.
513
+ type: string
514
+ 401:
515
+ description: Invalid Auth Token
516
+ """
517
+
518
+ def generate(_filter, vo):
519
+ for account in list_accounts(filter_=_filter, vo=vo):
520
+ yield render_json(**account) + "\n"
521
+
522
+ return try_stream(generate(_filter=dict(request.args.items(multi=False)), vo=request.environ.get('vo')))
523
+
524
+
525
+ class LocalAccountLimits(ErrorHandlingMethodView):
526
+ @check_accept_header_wrapper_flask(['application/json'])
527
+ def get(self, account, rse=None):
528
+ """
529
+ ---
530
+ summary: Get local limit
531
+ description: Get the current local limits for an account on a specific RSE.
532
+ tags:
533
+ - Account
534
+ parameters:
535
+ - name: account
536
+ in: path
537
+ description: The account identifier.
538
+ schema:
539
+ type: string
540
+ style: simple
541
+ - name: rse
542
+ in: path
543
+ description: The rse identifier.
544
+ schema:
545
+ type: string
546
+ style: simple
547
+ responses:
548
+ 200:
549
+ description: OK
550
+ content:
551
+ application/json:
552
+ schema:
553
+ description: Json object with rse identifiers as keys and account limits in bytes as values.
554
+ type: object
555
+ 401:
556
+ description: Invalid Auth Token
557
+ 404:
558
+ description: RSE not found
559
+ 406:
560
+ description: Not Acceptable
561
+ """
562
+ try:
563
+ if rse:
564
+ limits = get_local_account_limit(account=account, rse=rse, vo=request.environ.get('vo'))
565
+ else:
566
+ limits = get_local_account_limits(account=account, vo=request.environ.get('vo'))
567
+ except RSENotFound as error:
568
+ return generate_http_error_flask(404, error)
569
+
570
+ return Response(render_json(**limits), content_type="application/json")
571
+
572
+
573
+ class GlobalAccountLimits(ErrorHandlingMethodView):
574
+ @check_accept_header_wrapper_flask(['application/json'])
575
+ def get(self, account, rse_expression=None):
576
+ """
577
+ ---
578
+ summary: Get gloabl limit
579
+ description: Get the current gloabl limits for an account on a specific RSE expression.
580
+ tags:
581
+ - Account
582
+ parameters:
583
+ - name: account
584
+ in: path
585
+ description: The account identifier.
586
+ schema:
587
+ type: string
588
+ style: simple
589
+ - name: rse_expression
590
+ in: path
591
+ description: The rse identifier.
592
+ schema:
593
+ type: string
594
+ style: simple
595
+ responses:
596
+ 200:
597
+ description: OK
598
+ content:
599
+ application/json:
600
+ schema:
601
+ description: Json object with rse expression as keys and limits in bytes as values.
602
+ type: object
603
+ 401:
604
+ description: Invalid Auth Token
605
+ 404:
606
+ description: RSE not found
607
+ 406:
608
+ description: Not Acceptable
609
+ """
610
+ try:
611
+ if rse_expression:
612
+ limits = get_global_account_limit(account=account, rse_expression=rse_expression, vo=request.environ.get('vo'))
613
+ else:
614
+ limits = get_global_account_limits(account=account, vo=request.environ.get('vo'))
615
+ except RSENotFound as error:
616
+ return generate_http_error_flask(404, error)
617
+
618
+ return Response(render_json(**limits), content_type="application/json")
619
+
620
+
621
+ class Identities(ErrorHandlingMethodView):
622
+ def post(self, account):
623
+ """
624
+ ---
625
+ summary: Create identity
626
+ description: Grant an account identity access to an account.
627
+ tags:
628
+ - Account
629
+ parameters:
630
+ - name: account
631
+ in: path
632
+ description: The account identifier.
633
+ schema:
634
+ type: string
635
+ style: simple
636
+ requestBody:
637
+ content:
638
+ 'application/json':
639
+ schema:
640
+ type: object
641
+ required:
642
+ - identity
643
+ - authtype
644
+ - email
645
+ properties:
646
+ identity:
647
+ description: The identity.
648
+ type: string
649
+ authtype:
650
+ description: The authtype.
651
+ type: string
652
+ email:
653
+ description: The email.
654
+ type: string
655
+ password:
656
+ description: The password.
657
+ type: string
658
+ default: none
659
+ default:
660
+ description: Should this be the default account?
661
+ type: string
662
+ default: false
663
+ responses:
664
+ 201:
665
+ description: OK
666
+ content:
667
+ application/json:
668
+ schema:
669
+ type: string
670
+ enum: ["Created"]
671
+ 401:
672
+ description: Invalid Auth Token
673
+ 404:
674
+ description: Account not found
675
+ 409:
676
+ description: Already exists
677
+ 400:
678
+ description: Parameter missing
679
+ """
680
+ parameters = json_parameters()
681
+ identity = param_get(parameters, 'identity')
682
+ authtype = param_get(parameters, 'authtype')
683
+ email = param_get(parameters, 'email')
684
+ try:
685
+ add_account_identity(
686
+ identity_key=identity,
687
+ id_type=authtype,
688
+ account=account,
689
+ email=email,
690
+ password=param_get(parameters, 'password', default=None),
691
+ issuer=request.environ.get('issuer'),
692
+ default=param_get(parameters, 'default', default=False),
693
+ vo=request.environ.get('vo'),
694
+ )
695
+ except AccessDenied as error:
696
+ return generate_http_error_flask(401, error)
697
+ except Duplicate as error:
698
+ return generate_http_error_flask(409, error)
699
+ except AccountNotFound as error:
700
+ return generate_http_error_flask(404, error)
701
+ except IdentityError as error:
702
+ return generate_http_error_flask(400, error)
703
+
704
+ return 'Created', 201
705
+
706
+ @check_accept_header_wrapper_flask(['application/x-json-stream'])
707
+ def get(self, account):
708
+ """
709
+ ---
710
+ summary: List identities
711
+ description: Lists all identities for an account.
712
+ tags:
713
+ - Account
714
+ parameters:
715
+ - name: account
716
+ in: path
717
+ description: The account identifier.
718
+ schema:
719
+ type: string
720
+ style: simple
721
+ responses:
722
+ 200:
723
+ description: OK
724
+ content:
725
+ application/x-json-stream:
726
+ schema:
727
+ type: array
728
+ items:
729
+ type: array
730
+ minItems: 2
731
+ maxItems: 2
732
+ items:
733
+ type: string
734
+ 401:
735
+ description: Invalid Auth Token
736
+ 404:
737
+ description: Account not found
738
+ 406:
739
+ description: Not acceptable
740
+ """
741
+ try:
742
+ def generate(vo):
743
+ for identity in list_identities(account, vo=vo):
744
+ yield render_json(**identity) + "\n"
745
+
746
+ return try_stream(generate(request.environ.get('vo')))
747
+ except AccountNotFound as error:
748
+ return generate_http_error_flask(404, error)
749
+
750
+ def delete(self, account):
751
+ """
752
+ ---
753
+ summary: Delete identity
754
+ description: Delete an account identity.
755
+ tags:
756
+ - Account
757
+ parameters:
758
+ - name: account
759
+ in: path
760
+ description: The account identifier.
761
+ schema:
762
+ type: string
763
+ style: simple
764
+ requestBody:
765
+ content:
766
+ 'application/json':
767
+ schema:
768
+ type: object
769
+ required:
770
+ - identity
771
+ - authtype
772
+ properties:
773
+ identity:
774
+ description: The identity.
775
+ type: string
776
+ authtype:
777
+ description: The authtype.
778
+ type: string
779
+ responses:
780
+ 200:
781
+ description: OK
782
+ 401:
783
+ description: Invalid Auth Token
784
+ 404:
785
+ description: Account or identity not found
786
+ """
787
+ parameters = json_parameters()
788
+ identity = param_get(parameters, 'identity')
789
+ authtype = param_get(parameters, 'authtype')
790
+ try:
791
+ del_account_identity(identity, authtype, account, request.environ.get('issuer'), vo=request.environ.get('vo'))
792
+ except AccessDenied as error:
793
+ return generate_http_error_flask(401, error)
794
+ except (AccountNotFound, IdentityError) as error:
795
+ return generate_http_error_flask(404, error)
796
+
797
+ return '', 200
798
+
799
+
800
+ class Rules(ErrorHandlingMethodView):
801
+
802
+ @check_accept_header_wrapper_flask(['application/x-json-stream'])
803
+ def get(self, account):
804
+ """
805
+ ---
806
+ summary: List rules
807
+ description: Lists all rules for an account.
808
+ tags:
809
+ - Account
810
+ parameters:
811
+ - name: account
812
+ in: path
813
+ description: The account identifier.
814
+ schema:
815
+ type: string
816
+ style: simple
817
+ responses:
818
+ 200:
819
+ description: OK
820
+ content:
821
+ application/x-json-stream:
822
+ schema:
823
+ type: array
824
+ items:
825
+ type: string
826
+ 401:
827
+ description: Invalid Auth Token
828
+ 404:
829
+ description: Account or rule not found
830
+ 406:
831
+ description: Not acceptable
832
+ """
833
+ filters = {'account': account}
834
+ filters.update(request.args)
835
+ try:
836
+ def generate(vo):
837
+ for rule in list_replication_rules(filters=filters, vo=vo):
838
+ yield dumps(rule, cls=APIEncoder) + '\n'
839
+
840
+ return try_stream(generate(vo=request.environ.get('vo')))
841
+ except RuleNotFound as error:
842
+ return generate_http_error_flask(404, error)
843
+
844
+
845
+ class UsageHistory(ErrorHandlingMethodView):
846
+
847
+ @check_accept_header_wrapper_flask(['application/json'])
848
+ def get(self, account, rse):
849
+ """
850
+ ---
851
+ summary: Get account usage history
852
+ description: Returns the account usage history.
853
+ tags:
854
+ - Account
855
+ parameters:
856
+ - name: account
857
+ in: path
858
+ description: The account identifier.
859
+ schema:
860
+ type: string
861
+ style: simple
862
+ - name: rse
863
+ in: path
864
+ description: The rse identifier.
865
+ schema:
866
+ type: string
867
+ style: simple
868
+ responses:
869
+ 200:
870
+ description: OK
871
+ content:
872
+ application/json:
873
+ schema:
874
+ type: array
875
+ items:
876
+ type: object
877
+ properties:
878
+ bytes:
879
+ description: The number of bytes used.
880
+ type: integer
881
+ files:
882
+ description: The files.
883
+ type: string
884
+ updated_at:
885
+ description: When the data was provided.
886
+ type: string
887
+ 401:
888
+ description: Invalid Auth Token
889
+ 404:
890
+ description: Account not found
891
+ 406:
892
+ description: Not acceptable
893
+ """
894
+ try:
895
+ usage = get_usage_history(account=account, rse=rse, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
896
+ except (AccountNotFound, CounterNotFound) as error:
897
+ return generate_http_error_flask(404, error)
898
+ except AccessDenied as error:
899
+ return generate_http_error_flask(401, error)
900
+
901
+ for entry in usage:
902
+ for key, value in entry.items():
903
+ if isinstance(value, datetime):
904
+ entry[key] = value.strftime('%Y-%m-%dT%H:%M:%S')
905
+
906
+ return jsonify(usage)
907
+
908
+
909
+ class LocalUsage(ErrorHandlingMethodView):
910
+
911
+ @check_accept_header_wrapper_flask(['application/x-json-stream'])
912
+ def get(self, account, rse=None):
913
+ """
914
+ ---
915
+ summary: Get local account usage
916
+ description: Returns the local account usage.
917
+ tags:
918
+ - Account
919
+ parameters:
920
+ - name: account
921
+ in: path
922
+ description: The account identifier.
923
+ schema:
924
+ type: string
925
+ style: simple
926
+ - name: rse
927
+ in: path
928
+ description: The rse identifier.
929
+ schema:
930
+ type: string
931
+ style: simple
932
+ responses:
933
+ 200:
934
+ description: OK
935
+ content:
936
+ application/x-json-stream:
937
+ schema:
938
+ type: array
939
+ items:
940
+ type: object
941
+ properties:
942
+ rse_id:
943
+ description: The rse id.
944
+ type: string
945
+ bytes:
946
+ description: The number of bytes used.
947
+ type: integer
948
+ bytes_limit:
949
+ description: The maximum number of bytes.
950
+ type: integer
951
+ bytes_remaining:
952
+ description: The remaining number of bytes.
953
+ type: integer
954
+ 401:
955
+ description: Invalid Auth Token
956
+ 404:
957
+ description: Account or rse not found
958
+ 406:
959
+ description: Not acceptable
960
+ """
961
+ try:
962
+ def generate(issuer, vo):
963
+ for usage in get_local_account_usage(account=account, rse=rse, issuer=issuer, vo=vo):
964
+ yield dumps(usage, cls=APIEncoder) + '\n'
965
+
966
+ return try_stream(generate(issuer=request.environ.get('issuer'), vo=request.environ.get('vo')))
967
+ except (AccountNotFound, RSENotFound) as error:
968
+ return generate_http_error_flask(404, error)
969
+ except AccessDenied as error:
970
+ return generate_http_error_flask(401, error)
971
+
972
+
973
+ class GlobalUsage(ErrorHandlingMethodView):
974
+
975
+ @check_accept_header_wrapper_flask(['application/x-json-stream'])
976
+ def get(self, account, rse_expression=None):
977
+ """
978
+ ---
979
+ summary: Get local account usage
980
+ description: Returns the local account usage.
981
+ tags:
982
+ - Account
983
+ parameters:
984
+ - name: account
985
+ in: path
986
+ description: The account identifier.
987
+ schema:
988
+ type: string
989
+ style: simple
990
+ - name: rse_expression
991
+ in: path
992
+ description: The rse expression.
993
+ schema:
994
+ type: string
995
+ style: simple
996
+ responses:
997
+ 200:
998
+ description: OK
999
+ content:
1000
+ application/x-json-stream:
1001
+ schema:
1002
+ type: array
1003
+ items:
1004
+ type: object
1005
+ properties:
1006
+ rse_expression:
1007
+ description: The rse expression.
1008
+ type: string
1009
+ bytes:
1010
+ description: The number of bytes used.
1011
+ type: integer
1012
+ bytes_limit:
1013
+ description: The maximum number of bytes.
1014
+ type: integer
1015
+ bytes_remaining:
1016
+ description: The remaining number of bytes.
1017
+ type: integer
1018
+ 401:
1019
+ description: Invalid Auth Token
1020
+ 404:
1021
+ description: Account or rse not found
1022
+ 406:
1023
+ description: Not acceptable
1024
+ """
1025
+ try:
1026
+ def generate(vo, issuer):
1027
+ for usage in get_global_account_usage(account=account, rse_expression=rse_expression, issuer=issuer, vo=vo):
1028
+ yield dumps(usage, cls=APIEncoder) + '\n'
1029
+
1030
+ return try_stream(generate(vo=request.environ.get('vo'), issuer=request.environ.get('issuer')))
1031
+ except (AccountNotFound, RSENotFound) as error:
1032
+ return generate_http_error_flask(404, error)
1033
+ except AccessDenied as error:
1034
+ return generate_http_error_flask(401, error)
1035
+
1036
+
1037
+ def blueprint(with_doc=False):
1038
+ bp = AuthenticatedBlueprint('accounts', __name__, url_prefix='/accounts')
1039
+
1040
+ attributes_view = Attributes.as_view('attributes')
1041
+ bp.add_url_rule('/<account>/attr/', view_func=attributes_view, methods=['get', ])
1042
+ bp.add_url_rule('/<account>/attr/<key>', view_func=attributes_view, methods=['post', 'delete'])
1043
+ scopes_view = Scopes.as_view('scopes')
1044
+ bp.add_url_rule('/<account>/scopes/', view_func=scopes_view, methods=['get', ])
1045
+ bp.add_url_rule('/<account>/scopes/<scope>', view_func=scopes_view, methods=['post', ])
1046
+ local_account_limits_view = LocalAccountLimits.as_view('local_account_limit')
1047
+ bp.add_url_rule('/<account>/limits/local', view_func=local_account_limits_view, methods=['get', ])
1048
+ bp.add_url_rule('/<account>/limits', view_func=local_account_limits_view, methods=['get', ])
1049
+ bp.add_url_rule('/<account>/limits/local/<rse>', view_func=local_account_limits_view, methods=['get', ])
1050
+ bp.add_url_rule('/<account>/limits/<rse>', view_func=local_account_limits_view, methods=['get', ])
1051
+ global_account_limits_view = GlobalAccountLimits.as_view('global_account_limit')
1052
+ bp.add_url_rule('/<account>/limits/global', view_func=global_account_limits_view, methods=['get', ])
1053
+ bp.add_url_rule('/<account>/limits/global/<rse_expression>', view_func=global_account_limits_view, methods=['get', ])
1054
+ identities_view = Identities.as_view('identities')
1055
+ bp.add_url_rule('/<account>/identities', view_func=identities_view, methods=['get', 'post', 'delete'])
1056
+ rules_view = Rules.as_view('rules')
1057
+ bp.add_url_rule('/<account>/rules', view_func=rules_view, methods=['get', ])
1058
+ usagehistory_view = UsageHistory.as_view('usagehistory')
1059
+ bp.add_url_rule('/<account>/usage/history/<rse>', view_func=usagehistory_view, methods=['get', ])
1060
+ usage_view = LocalUsage.as_view('usage')
1061
+ bp.add_url_rule('/<account>/usage/local', view_func=usage_view, methods=['get', ])
1062
+ bp.add_url_rule('/<account>/usage', view_func=usage_view, methods=['get', ])
1063
+ if not with_doc:
1064
+ # for backwards-compatibility
1065
+ # rule without trailing slash needs to be added before rule with trailing slash
1066
+ bp.add_url_rule('/<account>/usage/', view_func=usage_view, methods=['get', ])
1067
+ bp.add_url_rule('/<account>/usage/local/<rse>', view_func=usage_view, methods=['get', ])
1068
+ bp.add_url_rule('/<account>/usage/<rse>', view_func=usage_view, methods=['get', ])
1069
+ global_usage_view = GlobalUsage.as_view('global_usage')
1070
+ bp.add_url_rule('/<account>/usage/global', view_func=global_usage_view, methods=['get', ])
1071
+ bp.add_url_rule('/<account>/usage/global/<rse_expression>', view_func=global_usage_view, methods=['get', ])
1072
+ account_parameter_view = AccountParameter.as_view('account_parameter')
1073
+ bp.add_url_rule('/<account>', view_func=account_parameter_view, methods=['get', 'put', 'post', 'delete'])
1074
+ account_view = Account.as_view('account')
1075
+ if not with_doc:
1076
+ # rule without trailing slash needs to be added before rule with trailing slash
1077
+ bp.add_url_rule('', view_func=account_view, methods=['get', ])
1078
+ bp.add_url_rule('/', view_func=account_view, methods=['get', ])
1079
+
1080
+ bp.after_request(response_headers)
1081
+ return bp
1082
+
1083
+
1084
+ def make_doc():
1085
+ """ Only used for sphinx documentation """
1086
+ doc_app = Flask(__name__)
1087
+ doc_app.register_blueprint(blueprint(with_doc=True))
1088
+ return doc_app