diff --git a/Pipfile b/Pipfile index 3e38d67..d93370c 100644 --- a/Pipfile +++ b/Pipfile @@ -28,6 +28,8 @@ django-rest-framework = "*" django-rest-knox = "*" pydantic = "*" django-impersonate = "*" +attrs = "*" +cattrs = "*" [dev-packages] Werkzeug = "*" diff --git a/Pipfile.lock b/Pipfile.lock index bb4ce85..c05fef4 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7506ae469e603912e515368a9dcc5fe5bfdc9fdc9e5ef35b5742448afd54dfc9" + "sha256": "4d90a6ca6314e3a30f2fe68f8c42c837dcc3d7fe707bcf6833e5e64b6798856d" }, "pipfile-spec": 6, "requires": { @@ -18,11 +18,11 @@ "default": { "amqp": { "hashes": [ - "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637", - "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd" + "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2", + "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432" ], "markers": "python_version >= '3.6'", - "version": "==5.2.0" + "version": "==5.3.1" }, "annotated-types": { "hashes": [ @@ -77,11 +77,19 @@ }, "async-timeout": { "hashes": [ - "sha256:49675ec889daacfe65ff66d2dde7dd1447a6f4b2f23721022e4ba121f8772a85", - "sha256:904719a4bd6e0520047d0ddae220aabee67b877f7ca17bf8cea20f67f6247ae0" + "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", + "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3" ], "markers": "python_full_version < '3.11.3'", - "version": "==5.0.0" + "version": "==5.0.1" + }, + "attrs": { + "hashes": [ + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" + ], + "index": "pypi", + "version": "==24.2.0" }, "billiard": { "hashes": [ @@ -91,6 +99,14 @@ "markers": "python_version >= '3.7'", "version": "==4.2.1" }, + "cattrs": { + "hashes": [ + "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", + "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85" + ], + "index": "pypi", + "version": "==24.1.2" + }, "celery": { "hashes": [ "sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64", @@ -339,35 +355,37 @@ }, "cryptography": { "hashes": [ - "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", - "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", - "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa", - "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83", - "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff", - "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", - "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", - "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664", - "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08", - "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", - "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", - "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", - "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", - "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", - "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", - "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", - "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3", - "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", - "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", - "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", - "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c", - "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", - "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", - "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", - "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7", - "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", - "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7" - ], - "version": "==43.0.3" + "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", + "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731", + "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", + "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", + "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", + "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385", + "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c", + "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", + "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", + "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", + "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", + "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", + "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c", + "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba", + "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", + "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", + "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", + "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", + "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa", + "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", + "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", + "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", + "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", + "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", + "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", + "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", + "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", + "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756", + "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4" + ], + "version": "==44.0.0" }, "defusedxml": { "hashes": [ @@ -470,6 +488,14 @@ "markers": "python_version >= '3.8'", "version": "==3.15.2" }, + "exceptiongroup": { + "hashes": [ + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + ], + "markers": "python_version < '3.11'", + "version": "==1.2.2" + }, "hiredis": { "hashes": [ "sha256:00018f22f38530768b73ea86c11f47e8d4df65facd4e562bd78773bd1baef35e", @@ -683,117 +709,128 @@ }, "pydantic": { "hashes": [ - "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", - "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" + "sha256:2bc2d7f17232e0841cbba4641e65ba1eb6fafb3a08de3a091ff3ce14a197c4fa", + "sha256:cfb96e45951117c3024e6b67b25cdc33a3cb7b2fa62e239f7af1378358a1d99e" ], "index": "pypi", - "version": "==2.9.2" + "version": "==2.10.2" }, "pydantic-core": { "hashes": [ - "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", - "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", - "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", - "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", - "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", - "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", - "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", - "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", - "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", - "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", - "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", - "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", - "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", - "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", - "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", - "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", - "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", - "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", - "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", - "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", - "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", - "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", - "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", - "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", - "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", - "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", - "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", - "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", - "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", - "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", - "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", - "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", - "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", - "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", - "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", - "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", - "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", - "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", - "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", - "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", - "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", - "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", - "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", - "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", - "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", - "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", - "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", - "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", - "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", - "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", - "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", - "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", - "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", - "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", - "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", - "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", - "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", - "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", - "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", - "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", - "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", - "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", - "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", - "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", - "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", - "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", - "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", - "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", - "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", - "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", - "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", - "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", - "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", - "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", - "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", - "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", - "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", - "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", - "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", - "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", - "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", - "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", - "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", - "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", - "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", - "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", - "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", - "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", - "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607" + "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9", + "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b", + "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c", + "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529", + "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc", + "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854", + "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d", + "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278", + "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a", + "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c", + "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f", + "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27", + "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f", + "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac", + "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2", + "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97", + "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a", + "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919", + "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9", + "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4", + "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c", + "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131", + "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5", + "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd", + "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089", + "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107", + "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6", + "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60", + "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf", + "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5", + "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08", + "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05", + "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2", + "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e", + "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c", + "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17", + "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62", + "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23", + "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be", + "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067", + "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02", + "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f", + "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235", + "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840", + "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5", + "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807", + "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16", + "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c", + "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864", + "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e", + "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a", + "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35", + "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737", + "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a", + "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3", + "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52", + "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05", + "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31", + "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89", + "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de", + "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6", + "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36", + "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c", + "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154", + "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb", + "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e", + "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd", + "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3", + "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f", + "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78", + "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960", + "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618", + "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08", + "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4", + "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c", + "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c", + "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330", + "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8", + "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792", + "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025", + "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9", + "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f", + "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01", + "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337", + "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4", + "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f", + "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd", + "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51", + "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab", + "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc", + "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676", + "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381", + "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed", + "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb", + "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967", + "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073", + "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae", + "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c", + "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206", + "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b" ], "markers": "python_version >= '3.8'", - "version": "==2.23.4" + "version": "==2.27.1" }, "pyjwt": { "extras": [ "crypto" ], "hashes": [ - "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", - "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" + "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", + "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb" ], - "markers": "python_version >= '3.8'", - "version": "==2.9.0" + "markers": "python_version >= '3.9'", + "version": "==2.10.1" }, "python-crontab": { "hashes": [ @@ -891,11 +928,11 @@ }, "sqlparse": { "hashes": [ - "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4", - "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e" + "sha256:9e37b35e16d1cc652a2545f0997c1deb23ea28fa1f3eefe609eee3063c3b105f", + "sha256:e99bc85c78160918c3e1d9230834ab8d80fc06c59d03f8db2618f65f65dda55e" ], "markers": "python_version >= '3.8'", - "version": "==0.5.1" + "version": "==0.5.2" }, "text-unidecode": { "hashes": [ @@ -909,7 +946,7 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version < '3.13'", + "markers": "python_version < '3.11'", "version": "==4.12.2" }, "tzdata": { diff --git a/adminsec/tests/test_views_api.py b/adminsec/tests/test_views_api.py index b52ed1f..a888019 100644 --- a/adminsec/tests/test_views_api.py +++ b/adminsec/tests/test_views_api.py @@ -25,9 +25,9 @@ class ApiTestCase(TestCase): def setUp(self): super().setUp() # Create usersec.models records. - self.hpcuser_user = HpcUserFactory() self.hpcuser_group = HpcGroupFactory() - self.hpcuser_project = HpcProjectFactory() + self.hpcuser_user = HpcUserFactory(primary_group=self.hpcuser_group) + self.hpcuser_project = HpcProjectFactory(group=self.hpcuser_group) # Create Django users. self.user_user = self.make_user("user") self.user_staff = self.make_user("staff") @@ -52,6 +52,7 @@ def setUp(self): ) # Create HpcProjectCreateRequest. self.hpcprojectcreaterequest = HpcProjectCreateRequestFactory( + group=self.hpcuser_group, requester=self.user_user, status=REQUEST_STATUS_ACTIVE, ) @@ -625,3 +626,72 @@ def test_delete_fail(self): self.response_405() else: self.response_403() + + +class TestHpcAccessStatusApiView(ApiTestCase): + """Tests for the HpcAccessStatusApiView.""" + + def test_get_succeed(self): + """Test the GET method (staff users can do).""" + + self.maxDiff = None + + expected = { + "hpc_users": [ + { + "uid": self.hpcuser_user.user.uid, + "email": self.hpcuser_user.user.email, + "full_name": "User Name", + "first_name": self.hpcuser_user.user.first_name, + "last_name": self.hpcuser_user.user.last_name, + "phone_number": None, + "primary_group": self.hpcuser_group.name, + "resources_requested": self.hpcuser_user.resources_requested, + "status": "INITIAL", + "description": self.hpcuser_user.description, + "username": self.hpcuser_user.username, + "expiration": self.hpcuser_user.expiration.strftime("%Y-%m-%dT%H:%M:%SZ"), + "home_directory": self.hpcuser_user.home_directory, + "login_shell": self.hpcuser_user.login_shell, + } + ], + "hpc_groups": [ + { + "owner": None, + "delegate": None, + "resources_requested": self.hpcuser_group.resources_requested, + "status": "INITIAL", + "description": self.hpcuser_group.description, + "name": self.hpcuser_group.name, + "folders": self.hpcuser_group.folders, + "expiration": self.hpcuser_group.expiration.strftime("%Y-%m-%dT%H:%M:%SZ"), + "gid": self.hpcuser_group.gid, + } + ], + "hpc_projects": [ + { + "gid": self.hpcuser_project.gid, + "group": self.hpcuser_group.name, + "delegate": None, + "resources_requested": self.hpcuser_project.resources_requested, + "status": "INITIAL", + "description": self.hpcuser_project.description, + "name": self.hpcuser_project.name, + "folders": self.hpcuser_project.folders, + "expiration": self.hpcuser_project.expiration.strftime("%Y-%m-%dT%H:%M:%SZ"), + "members": [], + } + ], + } + for user in [self.user_staff, self.user_admin, self.user_hpcadmin]: + with self.login(user): + self.get("adminsec:api-hpcaccess-status") + self.response_200() + self.assertEqual(self.last_response.json(), expected) + + def test_get_fail(self): + """Test the GET method (non-staff cannot do).""" + for user in [self.user_user]: + with self.login(user): + self.get("adminsec:api-hpcaccess-status") + self.response_403() diff --git a/adminsec/urls.py b/adminsec/urls.py index 61164ca..ae3f276 100644 --- a/adminsec/urls.py +++ b/adminsec/urls.py @@ -318,6 +318,11 @@ view=views_api.HpcProjectCreateRequestRetrieveUpdateApiView.as_view(), name="api-hpcprojectcreaterequest-retrieveupdate", ), + path( + "api/hpcaccess-status/", + view=views_api.HpcAccessStatusApiView.as_view(), + name="api-hpcaccess-status", + ), ] urlpatterns = urlpatterns_ui + urlpatterns_api diff --git a/adminsec/views_api.py b/adminsec/views_api.py index 42323ec..2d03357 100644 --- a/adminsec/views_api.py +++ b/adminsec/views_api.py @@ -2,9 +2,11 @@ import re +import attr from rest_framework.exceptions import ValidationError from rest_framework.generics import ( ListAPIView, + RetrieveAPIView, RetrieveUpdateAPIView, get_object_or_404, ) @@ -24,6 +26,7 @@ HpcUser, ) from usersec.serializers import ( + HpcAccessStatusSerializer, HpcGroupCreateRequestSerializer, HpcGroupSerializer, HpcProjectCreateRequestSerializer, @@ -215,3 +218,27 @@ def perform_update(self, serializer): raise ValidationError(errors) super().perform_update(serializer) + + +@attr.s(frozen=True) +class HpcAccessStatus: + """Class to hold the status of the HPC access system.""" + + hpc_users: dict = attr.ib() + hpc_groups: dict = attr.ib() + hpc_projects: dict = attr.ib() + + +class HpcAccessStatusApiView(RetrieveAPIView): + """API view for listing all users.""" + + serializer_class = HpcAccessStatusSerializer + permission_classes = [IsAdminUser | IsHpcAdminUser] + + def get_object(self): + """Return the object to be used in the view.""" + return HpcAccessStatus( + hpc_users=HpcUser.objects.all(), + hpc_groups=HpcGroup.objects.all(), + hpc_projects=HpcProject.objects.all(), + ) diff --git a/usersec/serializers.py b/usersec/serializers.py index d51ea11..1115cf6 100644 --- a/usersec/serializers.py +++ b/usersec/serializers.py @@ -97,23 +97,28 @@ class Meta: ] -class HpcUserLookupSerializer(serializers.ModelSerializer): - """Serializer for HpcUser model for lookup purposes.""" +class HpcUserStatusSerializer(HpcUserAbstractSerializer, serializers.ModelSerializer): + """Serializer for HpcUser model.""" primary_group = serializers.SlugRelatedField(slug_field="name", read_only=True) - username = serializers.CharField(read_only=True) - full_name = serializers.SerializerMethodField() - - def get_full_name(self, obj) -> str: - return obj.user.name class Meta: model = HpcUser fields = [ - "id", - "username", - "primary_group", + "uid", + "email", "full_name", + "first_name", + "last_name", + "phone_number", + "primary_group", + "resources_requested", + "status", + "description", + "username", + "expiration", + "home_directory", + "login_shell", ] @@ -184,6 +189,26 @@ class Meta: ] +class HpcGroupStatusSerializer(HpcGroupAbstractSerializer, serializers.ModelSerializer): + """Serializer for HpcGroup model.""" + + owner = serializers.SlugRelatedField(slug_field="username", read_only=True) + + class Meta: + model = HpcUser + fields = [ + "owner", + "delegate", + "resources_requested", + "status", + "description", + "name", + "folders", + "expiration", + "gid", + ] + + class HpcProjectAbstractSerializer(HpcObjectAbstractSerializer): """Common base class for HPC project serializers.""" @@ -240,6 +265,29 @@ class Meta: ] +class HpcProjectStatusSerializer(HpcProjectAbstractSerializer, serializers.ModelSerializer): + """Serializer for HpcProject model.""" + + group = serializers.SlugRelatedField(slug_field="name", read_only=True) + delegate = serializers.SlugRelatedField(slug_field="username", read_only=True) + members = serializers.SlugRelatedField(slug_field="username", many=True, read_only=True) + + class Meta: + model = HpcUser + fields = [ + "gid", + "group", + "delegate", + "resources_requested", + "status", + "description", + "name", + "folders", + "expiration", + "members", + ] + + class HpcRequestAbstractSerializer(HpcObjectAbstractSerializer): """Common base class for HPC request serializers.""" @@ -377,3 +425,40 @@ class Meta: fields = HpcProjectCreateRequestAbstractSerializer.Meta.fields + [ "version", ] + + +class HpcUserLookupSerializer(serializers.ModelSerializer): + """Serializer for HpcUser model for lookup purposes.""" + + primary_group = serializers.SlugRelatedField(slug_field="name", read_only=True) + username = serializers.CharField(read_only=True) + full_name = serializers.SerializerMethodField() + + def get_full_name(self, obj) -> str: + return obj.user.name + + class Meta: + model = HpcUser + fields = [ + "id", + "username", + "primary_group", + "full_name", + ] + + +class HpcAccessStatusSerializer(serializers.Serializer): + """Serializer for HpcAccessStatus model.""" + + hpc_users = serializers.SerializerMethodField() + hpc_groups = serializers.SerializerMethodField() + hpc_projects = serializers.SerializerMethodField() + + def get_hpc_users(self, obj): + return HpcUserStatusSerializer(obj.hpc_users, many=True).data + + def get_hpc_groups(self, obj): + return HpcGroupStatusSerializer(obj.hpc_groups, many=True).data + + def get_hpc_projects(self, obj): + return HpcProjectStatusSerializer(obj.hpc_projects, many=True).data diff --git a/utils/cli/hpc_access_cli/main.py b/utils/cli/hpc_access_cli/main.py index 8368aa6..f217599 100644 --- a/utils/cli/hpc_access_cli/main.py +++ b/utils/cli/hpc_access_cli/main.py @@ -16,6 +16,7 @@ TargetStateBuilder, TargetStateComparison, convert_to_hpcaccess_state, + convert_to_hpcaccess_state_v2, deploy_hpcaccess_state, fs_validation, gather_hpcaccess_state, @@ -79,6 +80,20 @@ def dump_data( console_out.print_json(data=hpcaccess_state.model_dump(mode="json")) +@app.command("state-dump-v2") +def dump_data_v2( + config_path: Annotated[ + str, typer.Option(..., help="path to configuration file") + ] = "/etc/hpc-access-cli/config.json", +): + """dump system state as hpc-access state""" + settings = load_settings(config_path) + console_err.print_json(data=settings.model_dump(mode="json")) + system_state = gather_system_state(settings) + hpcaccess_state = convert_to_hpcaccess_state_v2(system_state) + console_out.print_json(data=hpcaccess_state.model_dump(mode="json")) + + @app.command("state-sync") def sync_data( config_path: Annotated[ diff --git a/utils/cli/hpc_access_cli/models.py b/utils/cli/hpc_access_cli/models.py index 6b27395..95d3d16 100644 --- a/utils/cli/hpc_access_cli/models.py +++ b/utils/cli/hpc_access_cli/models.py @@ -273,6 +273,37 @@ class HpcUser(BaseModel): current_version: int +class HpcUserV2(BaseModel): + """A user as read from the hpc-access API.""" + + #: The UUID of the primary ``HpcGroup``. + primary_group: Optional[str] + #: Description of the record. + description: Optional[str] + #: The user's email address. + email: Optional[str] + #: The full name of the user. + full_name: str + #: The first name fo the user. + first_name: Optional[str] + #: The last name of the user. + last_name: Optional[str] + #: The office phone number of the user. + phone_number: Optional[str] + #: The requested resources. + resources_requested: Optional[ResourceDataUser] + #: The status of the record. + status: Status + #: The POSIX UID of the user. + uid: int + #: The username of the record. + username: str + #: The home directory. + home_directory: str + #: The login shell + login_shell: str + + class HpcGroup(BaseModel): """A group as read from the hpc-access API.""" @@ -302,6 +333,27 @@ class HpcGroup(BaseModel): current_version: int +class HpcGroupV2(BaseModel): + """A group as read from the hpc-access API.""" + + #: The owning ``HpcUser``. + owner: str + #: Description of the record. + description: Optional[str] + #: The delegate. + delegate: Optional[str] + #: The requested resources. + resources_requested: Optional[ResourceData] + #: The status of the record. + status: Status + #: The POSIX GID of the corresponding Unix group. + gid: Optional[int] + #: The name of the record. + name: str + #: The folders of the group. + folders: GroupFolders + + class HpcProject(BaseModel): """A project as read from the hpc-access API.""" @@ -333,6 +385,29 @@ class HpcProject(BaseModel): members: List[UUID] +class HpcProjectV2(BaseModel): + """A project as read from the hpc-access API.""" + + #: The owning ``HpcGroup``, owner of group is owner of project. + group: Optional[str] + #: Description of the record. + description: Optional[str] + #: The delegate for the project. + delegate: Optional[str] + #: The requested resources. + resources_requested: Optional[ResourceData] + #: The status of the record. + status: Status + #: The POSIX GID of the corresponding Unix group. + gid: Optional[int] + #: The name of the record. + name: str + #: The folders of the group. + folders: GroupFolders + #: The project's member user UUIDs. + members: List[str] + + class SystemState(BaseModel): """System state retrieved from LDAP and file system.""" @@ -352,6 +427,14 @@ class HpcaccessState(BaseModel): hpc_projects: Dict[UUID, HpcProject] +class HpcaccessStateV2(BaseModel): + """State as loaded from hpc-access.""" + + hpc_users: List[HpcUserV2] + hpc_groups: List[HpcGroupV2] + hpc_projects: List[HpcProjectV2] + + @enum.unique class StateOperation(enum.Enum): """Operation to perform on the state.""" diff --git a/utils/cli/hpc_access_cli/states.py b/utils/cli/hpc_access_cli/states.py index a9cbb45..2fcbc73 100644 --- a/utils/cli/hpc_access_cli/states.py +++ b/utils/cli/hpc_access_cli/states.py @@ -40,9 +40,13 @@ Gecos, GroupFolders, HpcaccessState, + HpcaccessStateV2, HpcGroup, + HpcGroupV2, HpcProject, + HpcProjectV2, HpcUser, + HpcUserV2, LdapGroup, LdapGroupOp, LdapUser, @@ -99,6 +103,7 @@ def gather_hpcaccess_state(settings: HpcaccessSettings) -> HpcaccessState: def deploy_hpcaccess_state(settings: HpcaccessSettings, state: HpcaccessState) -> None: """Deploy the state.""" + # TODO add uid/gid console_err.log("Deploying hpc-access users, groups, and projects...") rest_client = HpcaccessClient(settings) for u in state.hpc_users.values(): @@ -495,6 +500,8 @@ def build_hpcuser(u: LdapUser, quotas: Dict[str, str]) -> HpcUser: primary_group = group_uuids.get(group_by_gid_number[u.gid_number].cn) else: primary_group = None + if not primary_group.startswith(POSIX_AG_PREFIX) and not primary_group == "hpc-alumnis": + console_err.log(f"User belongs to group that is not a group ({primary_group}, {u.uid})") return HpcUser( uuid=user_uuids[u.uid], primary_group=primary_group, @@ -617,6 +624,156 @@ def build_hpcproject(p: LdapGroup, quotas: Dict[str, str]) -> Optional[HpcProjec ) +def convert_to_hpcaccess_state_v2(system_state: SystemState) -> HpcaccessStateV2: + """Convert hpc-access to system state. + + Note that this will make up the UUIDs. + """ + # create UUID mapping from user/groupnames + user_by_uid = {u.uid: u for u in system_state.ldap_users.values()} + user_by_dn = {u.dn: u for u in system_state.ldap_users.values()} + group_by_name = {strip_prefix(g.cn): g for g in system_state.ldap_groups.values()} + group_by_gid_number = {g.gid_number: g for g in system_state.ldap_groups.values()} + group_by_owner_dn: Dict[str, LdapGroup] = {} + for g in system_state.ldap_groups.values(): + if g.owner_dn: + group_by_owner_dn[user_by_dn[g.owner_dn].dn] = g + user_quotas: Dict[str, ResourceDataUser] = {} + group_quotas: Dict[str, ResourceData] = {} + for fs_data in system_state.fs_directories.values(): + try: + entity, name, resource = fs_validation(fs_data) + except ValueError as e: + console_err.log(f"WARNING: {e}") + continue + + quota_bytes = fs_data.quota_bytes if fs_data.quota_bytes is not None else 0 + + if entity == ENTITY_USERS: + if name not in user_by_uid: + console_err.log(f"WARNING: user {name} not found") + continue + if name not in user_quotas: + user_quotas[name] = {} + user_quotas[name][resource] = quota_bytes / 1024**3 + elif entity in (ENTITY_GROUPS, ENTITY_PROJECTS): + if name not in group_by_name: + console_err.log(f"WARNING: group {name} not found") + continue + if name not in group_quotas: + group_quotas[name] = {} + group_quotas[name][resource] = quota_bytes / 1024**4 + + def build_hpcuser(u: LdapUser, quotas: Dict[str, str]) -> HpcUserV2: + if u.login_shell != LOGIN_SHELL_DISABLED: + status = Status.ACTIVE + else: + status = Status.EXPIRED + if u.gid_number and u.gid_number in group_by_gid_number: + primary_group = group_by_gid_number[u.gid_number].cn + else: + primary_group = None + if not primary_group.startswith(POSIX_AG_PREFIX) and not primary_group == "hpc-alumnis": + console_err.log(f"User belongs to group that is not a group ({primary_group}, {u.uid})") + return HpcUserV2( + primary_group=strip_prefix(primary_group, prefix=POSIX_AG_PREFIX), + description=None, + full_name=u.cn, + first_name=u.given_name, + last_name=u.sn, + email=u.mail, + phone_number=u.gecos.office_phone if u.gecos else None, + resources_requested=ResourceDataUser(**quotas), + status=status, + uid=u.uid_number, + username=u.uid, + home_directory=u.home_directory, + login_shell=u.login_shell, + ) + + def build_hpcgroup(g: LdapGroup, quotas: Dict[str, str]) -> Optional[HpcGroupV2]: + name = strip_prefix(g.cn, POSIX_AG_PREFIX) + if not g.owner_dn: + console_err.log(f"no owner DN for {g.cn}, skipping") + return + return HpcGroupV2( + name=name, + description=g.description, + owner=user_by_dn[g.owner_dn].uid, + delegate=user_by_dn[g.delegate_dns[0]].uid if g.delegate_dns else None, + resources_requested=ResourceData(**quotas), + status=Status.ACTIVE, + gid=g.gid_number, + folders=GroupFolders( + tier1_work=f"{BASE_PATH_TIER1}/work/groups/{name}", + tier1_scratch=f"{BASE_PATH_TIER1}/scratch/groups/{name}", + tier2_mirrored=f"{BASE_PATH_TIER2}/mirrored/groups/{name}", + tier2_unmirrored=f"{BASE_PATH_TIER2}/unmirrored/groups/{name}", + ), + ) + + def build_hpcproject(p: LdapGroup, quotas: Dict[str, str]) -> Optional[HpcProjectV2]: + name = strip_prefix(p.cn, POSIX_PROJECT_PREFIX) + if not p.owner_dn: + console_err.log(f"no owner DN for {p.cn}, skipping") + return + members = [] + for uid in p.member_uids: + uid = uid.strip() + user = user_by_uid[uid] + members.append(user.uid) + gid_number = user_by_dn[p.owner_dn].gid_number + if not gid_number: + group = None + else: + group = group_by_gid_number[gid_number].cn + return HpcProjectV2( + name=name, + description=g.description, + group=group, + delegate=user_by_dn[p.delegate_dns[0]].uid if p.delegate_dns else None, + resources_requested=ResourceData(**quotas), + status=Status.ACTIVE, + gid=p.gid_number, + folders=GroupFolders( + tier1_work=f"{BASE_PATH_TIER1}/work/projects/{name}", + tier1_scratch=f"{BASE_PATH_TIER1}/scratch/projects/{name}", + tier2_mirrored=f"{BASE_PATH_TIER2}/mirrored/projects/{name}", + tier2_unmirrored=f"{BASE_PATH_TIER2}/unmirrored/projects/{name}", + ), + members=members, + ) + + # construct the resulting state + hpc_users = [] + hpc_groups = [] + hpc_projects = [] + + for u in system_state.ldap_users.values(): + hpc_user = build_hpcuser(u, user_quotas.get(u.uid, {})) + hpc_users.append(hpc_user) + + for g in system_state.ldap_groups.values(): + if g.cn.startswith(POSIX_AG_PREFIX): + hpc_group = build_hpcgroup( + g, group_quotas.get(strip_prefix(g.cn, prefix=POSIX_AG_PREFIX), {}) + ) + if hpc_group: + hpc_groups.append(hpc_group) + elif g.cn.startswith(POSIX_PROJECT_PREFIX): + hpc_project = build_hpcproject( + g, group_quotas.get(strip_prefix(g.cn, prefix=POSIX_PROJECT_PREFIX), {}) + ) + if hpc_project: + hpc_projects.append(hpc_project) + + return HpcaccessStateV2( + hpc_users=hpc_users, + hpc_groups=hpc_groups, + hpc_projects=hpc_projects, + ) + + class TargetStateComparison: """Helper class that compares two system states.