diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3b1a40e..d11465d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -28,7 +28,7 @@ jobs: with: prefix-key: "v0-rust" - name: install tooling - run: cargo install oas3-gen + run: cargo install oas3-gen@0.21.1 - name: Build run: cargo build --verbose - name: Check formatting diff --git a/Cargo.lock b/Cargo.lock index 1bf2715..50f2723 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,12 +114,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "any_ascii" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90c6333e01ba7235575b6ab53e5af10f1c327927fd97c36462917e289557ea64" - [[package]] name = "anyhow" version = "1.0.100" @@ -138,12 +132,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - [[package]] name = "async-broadcast" version = "0.7.2" @@ -298,6 +286,329 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-credential-types" +version = "1.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01c9521fa01558f750d183c8c68c81b0155b9d193a4ba7f84c36bd1b6d04a06" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + +[[package]] +name = "aws-lc-rs" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b5ce75405893cd713f9ab8e297d8e438f624dde7d706108285f7e17a25a180f" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "179c3777a8b5e70e90ea426114ffc565b2c1a9f82f6c4a0c5a34aa6ef5e781b6" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "aws-runtime" +version = "1.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce527fb7e53ba9626fc47824f25e256250556c40d8f81d27dd92aa38239d632" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid", +] + +[[package]] +name = "aws-sdk-s3" +version = "1.115.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdaa0053cbcbc384443dd24569bd5d1664f86427b9dc04677bd0ab853954baec" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "fastrand", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "lru", + "percent-encoding", + "regex-lite", + "sha2", + "tracing", + "url", +] + +[[package]] +name = "aws-sigv4" +version = "1.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35452ec3f001e1f2f6db107b6373f1f48f05ec63ba2c5c9fa91f07dad32af11" +dependencies = [ + "aws-credential-types", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "crypto-bigint 0.5.5", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "p256 0.11.1", + "percent-encoding", + "ring", + "sha2", + "subtle", + "time", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "127fcfad33b7dfc531141fda7e1c402ac65f88aca5511a4d31e2e3d2cd01ce9c" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-checksums" +version = "0.63.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95bd108f7b3563598e4dc7b62e1388c9982324a2abd622442167012690184591" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "bytes", + "crc-fast", + "hex", + "http 0.2.12", + "http-body 0.4.6", + "md-5", + "pin-project-lite", + "sha1", + "sha2", + "tracing", +] + +[[package]] +name = "aws-smithy-eventstream" +version = "0.60.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e29a304f8319781a39808847efb39561351b1bb76e933da7aa90232673638658" +dependencies = [ + "aws-smithy-types", + "bytes", + "crc32fast", +] + +[[package]] +name = "aws-smithy-http" +version = "0.62.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445d5d720c99eed0b4aa674ed00d835d9b1427dd73e04adaf2f94c6b2d6f9fca" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-http-client" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "623254723e8dfd535f566ee7b2381645f8981da086b5c4aa26c0c41582bb1d2c" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2 0.3.27", + "h2 0.4.12", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper 1.7.0", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.7", + "hyper-util", + "pin-project-lite", + "rustls 0.21.12", + "rustls 0.23.32", + "rustls-native-certs 0.8.2", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.61.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db31f727935fc63c6eeae8b37b438847639ec330a9161ece694efba257e0c54" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-observability" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1881b1ea6d313f9890710d65c158bdab6fb08c91ea825f74c1c8c357baf4cc" +dependencies = [ + "aws-smithy-runtime-api", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bbe9d018d646b96c7be063dd07987849862b0e6d07c778aad7d93d1be6c1ef0" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7204f9fd94749a7c53b26da1b961b4ac36bf070ef1e0b94bb09f79d4f6c193" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.4.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f535879a207fce0db74b679cfc3e91a3159c8144d717d55f5832aea9eef46e" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab77cdd036b11056d2a30a7af7b775789fb024bf216acc13884c6c97752ae56" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d79fb68e3d7fe5d4833ea34dc87d2e97d26d3086cb3da660bb6b1f76d98680b6" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.76" @@ -313,6 +624,12 @@ dependencies = [ "windows-link 0.2.0", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base16ct" version = "0.2.0" @@ -337,6 +654,16 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + [[package]] name = "base64ct" version = "1.8.0" @@ -439,6 +766,16 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + [[package]] name = "camino" version = "1.2.1" @@ -502,6 +839,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -624,6 +963,15 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "color-eyre" version = "0.6.5" @@ -662,6 +1010,7 @@ name = "coman" version = "0.1.0" dependencies = [ "anyhow", + "aws-sdk-s3", "better-panic", "chrono", "clap", @@ -704,6 +1053,7 @@ dependencies = [ "tracing-error", "tracing-subscriber", "tui-realm-stdlib", + "tui-realm-treeview", "tuirealm", "vergen-gix", ] @@ -842,6 +1192,34 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc-fast" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ddc2d09feefeee8bd78101665bd8645637828fa9317f9f292496dbbd8c65ff3" +dependencies = [ + "crc", + "digest", + "rand 0.9.2", + "regex", + "rustversion", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -927,6 +1305,18 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -1090,6 +1480,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "der" version = "0.7.10" @@ -1272,18 +1672,30 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + [[package]] name = "ecdsa" version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", + "der 0.7.10", "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki 0.7.3", ] [[package]] @@ -1292,8 +1704,8 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", - "signature", + "pkcs8 0.10.2", + "signature 2.2.0", ] [[package]] @@ -1316,23 +1728,43 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest", + "ff 0.12.1", + "generic-array", + "group 0.12.1", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + [[package]] name = "elliptic-curve" version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct", - "crypto-bigint", + "base16ct 0.2.0", + "crypto-bigint 0.5.5", "digest", - "ff", + "ff 0.13.1", "generic-array", - "group", + "group 0.13.0", "hkdf", "pem-rfc7468", - "pkcs8", + "pkcs8 0.10.2", "rand_core 0.6.4", - "sec1", + "sec1 0.7.3", "subtle", "zeroize", ] @@ -1451,6 +1883,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ff" version = "0.13.1" @@ -1499,7 +1941,6 @@ dependencies = [ "better_default", "chrono", "eyre", - "oas3-gen", "oas3-gen-support", "regex", "reqwest", @@ -1558,6 +1999,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.31" @@ -2550,17 +2997,47 @@ dependencies = [ "walkdir", ] +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "group" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.1", "rand_core 0.6.4", "subtle", ] +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.12.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.12" @@ -2572,7 +3049,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.4.0", "indexmap 2.12.0", "slab", "tokio", @@ -2688,15 +3165,25 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", "itoa", ] +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + [[package]] name = "http-auth" version = "0.1.10" @@ -2706,6 +3193,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -2713,7 +3211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.4.0", ] [[package]] @@ -2724,8 +3222,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2735,6 +3233,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "human-panic" version = "2.0.3" @@ -2760,6 +3264,30 @@ dependencies = [ "libm", ] +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.7.0" @@ -2770,9 +3298,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2", - "http", - "http-body", + "h2 0.4.12", + "http 1.4.0", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -2782,19 +3310,36 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http", - "hyper", + "http 1.4.0", + "hyper 1.7.0", "hyper-util", - "rustls", + "rustls 0.23.32", + "rustls-native-certs 0.8.2", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tower-service", "webpki-roots", ] @@ -2807,7 +3352,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.7.0", "hyper-util", "native-tls", "tokio", @@ -2826,14 +3371,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", - "hyper", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.7.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "system-configuration", "tokio", "tower-service", @@ -3038,12 +3583,6 @@ version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" -[[package]] -name = "inflections" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" - [[package]] name = "inout" version = "0.1.4" @@ -3196,6 +3735,16 @@ dependencies = [ "jiff-tzdb", ] +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.81" @@ -3424,6 +3973,16 @@ dependencies = [ "syn 2.0.108", ] +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.6" @@ -3605,16 +4164,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-format" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" -dependencies = [ - "arrayvec", - "itoa", -] - [[package]] name = "num-integer" version = "0.1.46" @@ -3667,12 +4216,12 @@ dependencies = [ [[package]] name = "oas3" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd09780430f4a2a496bd31609a04fae736a091f7e1d28ff11babd6c23cc0a171" +checksum = "16f67c885c7b19aaf652e84102035258ecb4e0425a4f71037e187798e367bd87" dependencies = [ "derive_more", - "http", + "http 1.4.0", "log", "once_cell", "regex", @@ -3682,41 +4231,16 @@ dependencies = [ "url", ] -[[package]] -name = "oas3-gen" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc28a75d37545693acd2a4741ebf73611b8a3c7e3dc390a5ff74231563077759" -dependencies = [ - "any_ascii", - "anyhow", - "clap", - "crossterm 0.29.0", - "http", - "inflections", - "num-format", - "oas3", - "percent-encoding", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "serde", - "serde_json", - "syn 2.0.108", - "tokio", -] - [[package]] name = "oas3-gen-support" -version = "0.9.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f35b27b4d65b4660a2b129b3649120b570f8ad66ab7f98094dda08966ed656b" +checksum = "691e804d8275c782a481a88f391848ef27cec1e427ee0a042b352d2eda8d5342" dependencies = [ "anyhow", "better_default", "chrono", - "http", + "http 1.4.0", "indexmap 2.12.0", "oas3", "percent-encoding", @@ -3724,10 +4248,14 @@ dependencies = [ "proc-macro2", "quote", "regex", + "reqwest", "serde", "serde_json", + "serde_path_to_error", + "serde_plain", "serde_with", "syn 2.0.108", + "thiserror 2.0.17", "uuid", "validator", ] @@ -3741,7 +4269,7 @@ dependencies = [ "base64 0.22.1", "chrono", "getrandom 0.2.16", - "http", + "http 1.4.0", "rand 0.8.5", "reqwest", "serde", @@ -3770,7 +4298,7 @@ dependencies = [ "bytes", "chrono", "futures-util", - "http", + "http 1.4.0", "http-auth", "jwt", "lazy_static", @@ -3831,11 +4359,11 @@ dependencies = [ "dyn-clone", "ed25519-dalek", "hmac", - "http", + "http 1.4.0", "itertools 0.10.5", "log", "oauth2", - "p256", + "p256 0.13.2", "p384", "rand 0.8.5", "rsa", @@ -3911,6 +4439,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "orange-trees" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4ebbf92a33c244681ae21f611f2494f9edf72a3fca85abe430d63480ad496b" + [[package]] name = "ordered-float" version = "2.10.1" @@ -3952,20 +4486,37 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + [[package]] name = "owo-colors" version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2", +] + [[package]] name = "p256" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", "primeorder", "sha2", ] @@ -3976,8 +4527,8 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", "primeorder", "sha2", ] @@ -4168,9 +4719,19 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", - "pkcs8", - "spki", + "der 0.7.10", + "pkcs8 0.10.2", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", ] [[package]] @@ -4179,8 +4740,8 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.10", + "spki 0.7.3", ] [[package]] @@ -4281,7 +4842,7 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve", + "elliptic-curve 0.13.8", ] [[package]] @@ -4364,8 +4925,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls", - "socket2", + "rustls 0.23.32", + "socket2 0.6.0", "thiserror 2.0.17", "tokio", "tracing", @@ -4384,7 +4945,7 @@ dependencies = [ "rand 0.9.2", "ring", "rustc-hash", - "rustls", + "rustls 0.23.32", "rustls-pki-types", "slab", "thiserror 2.0.17", @@ -4402,7 +4963,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.6.0", "tracing", "windows-sys 0.60.2", ] @@ -4566,6 +5127,12 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" + [[package]] name = "regex-syntax" version = "0.8.6" @@ -4583,12 +5150,12 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.12", + "http 1.4.0", + "http-body 1.0.1", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.7.0", + "hyper-rustls 0.27.7", "hyper-tls", "hyper-util", "js-sys", @@ -4599,7 +5166,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls", + "rustls 0.23.32", "rustls-pki-types", "serde", "serde_json", @@ -4607,7 +5174,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.26.4", "tokio-util", "tower", "tower-http", @@ -4620,6 +5187,17 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -4668,10 +5246,10 @@ dependencies = [ "num-integer", "num-traits", "pkcs1", - "pkcs8", + "pkcs8 0.10.2", "rand_core 0.6.4", - "signature", - "spki", + "signature 2.2.0", + "spki 0.7.3", "subtle", "zeroize", ] @@ -4733,20 +5311,66 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ + "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.7", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -4757,12 +5381,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -4828,16 +5463,40 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct 0.1.1", + "der 0.6.1", + "generic-array", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + [[package]] name = "sec1" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", + "base16ct 0.2.0", + "der 0.7.10", "generic-array", - "pkcs8", + "pkcs8 0.10.2", "subtle", "zeroize", ] @@ -5149,6 +5808,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "signature" version = "2.2.0" @@ -5193,6 +5862,16 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.0" @@ -5209,6 +5888,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + [[package]] name = "spki" version = "0.7.3" @@ -5216,7 +5905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", ] [[package]] @@ -5554,7 +6243,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.6.0", "tokio-macros", "tracing", "windows-sys 0.61.1", @@ -5581,13 +6270,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls", + "rustls 0.23.32", "tokio", ] @@ -5721,8 +6420,8 @@ dependencies = [ "bitflags", "bytes", "futures-util", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", "iri-string", "pin-project-lite", "tower", @@ -5832,6 +6531,17 @@ dependencies = [ "unicode-width 0.2.0", ] +[[package]] +name = "tui-realm-treeview" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb75aceab87e6a39595a9765b833054046b9b4ff667927d5ba928fb85d605e3" +dependencies = [ + "orange-trees", + "tuirealm", + "unicode-width 0.2.0", +] + [[package]] name = "tuirealm" version = "3.1.0" @@ -6089,6 +6799,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "vte" version = "0.14.1" @@ -6642,6 +7358,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + [[package]] name = "yaml-rust2" version = "0.8.1" diff --git a/coman/Cargo.toml b/coman/Cargo.toml index 175b081..be14951 100644 --- a/coman/Cargo.toml +++ b/coman/Cargo.toml @@ -69,6 +69,8 @@ oci-distribution = "0.11.0" docker_credential = "1.3.2" chrono = "0.4.42" openssl = { version = "0.10.75", features = ["vendored"] } +tui-realm-treeview = "3.0.0" +aws-sdk-s3 = "1.115.0" [build-dependencies] anyhow = "1.0.90" diff --git a/coman/src/app/ids.rs b/coman/src/app/ids.rs index 07919be..bab7a5b 100644 --- a/coman/src/app/ids.rs +++ b/coman/src/app/ids.rs @@ -8,5 +8,7 @@ pub enum Id { InfoPopup, ErrorPopup, LoginPopup, + DownloadPopup, SystemSelectPopup, + FileView, } diff --git a/coman/src/app/messages.rs b/coman/src/app/messages.rs index 0e098a5..25ab60f 100644 --- a/coman/src/app/messages.rs +++ b/coman/src/app/messages.rs @@ -1,4 +1,6 @@ -use crate::cscs::api_client::System; +use std::path::PathBuf; + +use crate::{app::user_events::UserEvent, cscs::api_client::System}; #[derive(Debug, PartialEq)] pub enum MenuMsg { @@ -6,6 +8,7 @@ pub enum MenuMsg { Closed, CscsLogin, CscsSwitchSystem, + Event(UserEvent), } #[derive(Debug, PartialEq)] @@ -26,6 +29,12 @@ pub enum LoginPopupMsg { LoginDone(String, String), } #[derive(Debug, PartialEq)] +pub enum DownloadPopupMsg { + Opened(PathBuf), + PathSet(PathBuf, PathBuf), + Closed, +} +#[derive(Debug, PartialEq)] pub enum SystemSelectMsg { Opened(Vec), Closed, @@ -43,6 +52,12 @@ pub enum JobMsg { ShowLog(usize), CloseLog, } +#[derive(Debug, Clone, Copy, Default, PartialEq, PartialOrd, Eq, Ord, strum::Display)] +pub enum View { + #[default] + Workloads, + Files, +} #[derive(Debug, PartialEq)] pub enum Msg { AppClose, @@ -50,10 +65,13 @@ pub enum Msg { InfoPopup(InfoPopupMsg), ErrorPopup(ErrorPopupMsg), LoginPopup(LoginPopupMsg), + DownloadPopup(DownloadPopupMsg), SystemSelectPopup(SystemSelectMsg), Error(String), Info(String), Cscs(CscsMsg), Job(JobMsg), + ChangeView(View), + CreateEvent(UserEvent), None, } diff --git a/coman/src/app/model.rs b/coman/src/app/model.rs index 6a9cb3a..4619158 100644 --- a/coman/src/app/model.rs +++ b/coman/src/app/model.rs @@ -3,7 +3,8 @@ use tokio::sync::mpsc; use tuirealm::{ Application, Update, ratatui::{ - layout::{Constraint, Direction, Layout}, + Frame, + layout::{Constraint, Direction, Layout, Rect}, widgets::Clear, }, terminal::{TerminalAdapter, TerminalBridge}, @@ -12,17 +13,23 @@ use tuirealm::{ use crate::{ app::{ ids::Id, - messages::{CscsMsg, ErrorPopupMsg, InfoPopupMsg, JobMsg, LoginPopupMsg, MenuMsg, Msg, SystemSelectMsg}, - user_events::UserEvent, + messages::{ + CscsMsg, DownloadPopupMsg, ErrorPopupMsg, InfoPopupMsg, JobMsg, LoginPopupMsg, MenuMsg, Msg, + SystemSelectMsg, View, + }, + user_events::{CscsEvent, UserEvent}, }, components::{ - error_popup::ErrorPopup, info_popup::InfoPopup, login_popup::LoginPopup, - system_select_popup::SystemSelectPopup, workload_list::WorkloadList, workload_log::WorkloadLog, - workload_menu::WorkloadMenu, + context_menu::ContextMenu, download_popup::DownloadTargetInput, error_popup::ErrorPopup, info_popup::InfoPopup, + login_popup::LoginPopup, system_select_popup::SystemSelectPopup, workload_list::WorkloadList, + workload_log::WorkloadLog, + }, + cscs::{ + handlers::{cscs_login, cscs_system_set}, + ports::TreeAction, }, - cscs::handlers::{cscs_login, cscs_system_set}, trace_dbg, - util::ui::draw_area_in_absolute, + util::ui::{draw_area_in_absolute, draw_area_in_absolute_fixed_height}, }; pub struct Model @@ -35,6 +42,9 @@ where pub quit: bool, /// Tells whether to redraw interface pub redraw: bool, + + /// Determines what view is display + pub current_view: View, /// Used to draw to terminal pub terminal: TerminalBridge, @@ -47,6 +57,12 @@ where /// Triggers watching job logs /// sending None stops watching pub job_log_tx: mpsc::Sender>, + + /// Allows creating user events based on messages + pub user_event_tx: mpsc::Sender, + + /// Allows interacting with the file Api + pub file_tree_tx: mpsc::Sender, } impl Model @@ -59,65 +75,89 @@ where error_tx: mpsc::Sender, select_system_tx: mpsc::Sender<()>, job_log_tx: mpsc::Sender>, + user_event_tx: mpsc::Sender, + file_tree_tx: mpsc::Sender, ) -> Self { Self { app, quit: false, redraw: true, terminal: bridge, + current_view: View::default(), error_tx, select_system_tx, job_log_tx, + user_event_tx, + file_tree_tx, } } pub fn view(&mut self) { + let terminal = &mut self.terminal; + let app = &mut self.app; + let current_view = &self.current_view; assert!( - self.terminal + terminal .draw(|f| { let chunks = Layout::default() .direction(Direction::Vertical) .margin(1) .constraints( [ - Constraint::Min(10), //WorkloadList + Constraint::Min(10), //content Constraint::Max(1), //Toolbar ] .as_ref(), ) .split(f.area()); - if self.app.mounted(&Id::WorkloadList) { - self.app.view(&Id::WorkloadList, f, chunks[0]); - } else if self.app.mounted(&Id::WorkloadLogs) { - self.app.view(&Id::WorkloadLogs, f, chunks[0]); + match current_view { + View::Workloads => Self::view_workloads(app, f, chunks[0]), + View::Files => Self::view_files(app, f, chunks[0]), } - self.app.view(&Id::Toolbar, f, chunks[1]); + app.view(&Id::Toolbar, f, chunks[1]); - if self.app.mounted(&Id::Menu) { + if app.mounted(&Id::Menu) { let popup = draw_area_in_absolute(f.area(), 10); f.render_widget(Clear, popup); - self.app.view(&Id::Menu, f, popup); - } else if self.app.mounted(&Id::ErrorPopup) { + app.view(&Id::Menu, f, popup); + } else if app.mounted(&Id::ErrorPopup) { let popup = draw_area_in_absolute(f.area(), 10); f.render_widget(Clear, popup); - self.app.view(&Id::ErrorPopup, f, popup); - } else if self.app.mounted(&Id::InfoPopup) { + app.view(&Id::ErrorPopup, f, popup); + } else if app.mounted(&Id::InfoPopup) { let popup = draw_area_in_absolute(f.area(), 10); f.render_widget(Clear, popup); - self.app.view(&Id::InfoPopup, f, popup); - } else if self.app.mounted(&Id::LoginPopup) { + app.view(&Id::InfoPopup, f, popup); + } else if app.mounted(&Id::LoginPopup) { let popup = draw_area_in_absolute(f.area(), 10); f.render_widget(Clear, popup); - self.app.view(&Id::LoginPopup, f, popup); - } else if self.app.mounted(&Id::SystemSelectPopup) { + app.view(&Id::LoginPopup, f, popup); + } else if app.mounted(&Id::SystemSelectPopup) { let popup = draw_area_in_absolute(f.area(), 10); f.render_widget(Clear, popup); - self.app.view(&Id::SystemSelectPopup, f, popup); + app.view(&Id::SystemSelectPopup, f, popup); + } else if app.mounted(&Id::DownloadPopup) { + let popup = draw_area_in_absolute_fixed_height(f.area(), 10, 3); + f.render_widget(Clear, popup); + app.view(&Id::DownloadPopup, f, popup); } }) .is_ok() ); } + + fn view_workloads(app: &mut Application, frame: &mut Frame, area: Rect) { + if app.mounted(&Id::WorkloadList) { + app.view(&Id::WorkloadList, frame, area); + } else if app.mounted(&Id::WorkloadLogs) { + app.view(&Id::WorkloadLogs, frame, area); + } + } + fn view_files(app: &mut Application, frame: &mut Frame, area: Rect) { + if app.mounted(&Id::FileView) { + app.view(&Id::FileView, frame, area); + } + } fn handle_login_popup_msg(&mut self, msg: LoginPopupMsg) -> Option { match msg { LoginPopupMsg::Opened => { @@ -202,12 +242,44 @@ where } } } + fn handle_download_popup_msg(&mut self, msg: DownloadPopupMsg) -> Option { + match msg { + DownloadPopupMsg::Opened(remote_path) => { + if self.app.mounted(&Id::DownloadPopup) { + assert!(self.app.umount(&Id::DownloadPopup).is_ok()); + } + assert!( + self.app + .mount( + Id::DownloadPopup, + Box::new(DownloadTargetInput::new(remote_path)), + vec![] + ) + .is_ok() + ); + assert!(self.app.active(&Id::DownloadPopup).is_ok()); + None + } + DownloadPopupMsg::PathSet(remote, local) => { + assert!(self.app.umount(&Id::DownloadPopup).is_ok()); + let file_tx = self.file_tree_tx.clone(); + tokio::spawn(async move { + file_tx.send(TreeAction::Download(remote, local)).await.unwrap(); + }); + None + } + DownloadPopupMsg::Closed => { + assert!(self.app.umount(&Id::DownloadPopup).is_ok()); + None + } + } + } fn handle_menu_msg(&mut self, msg: MenuMsg) -> Option { match msg { MenuMsg::Opened => { assert!( self.app - .mount(Id::Menu, Box::new(WorkloadMenu::default()), vec![]) + .mount(Id::Menu, Box::new(ContextMenu::new(self.current_view)), vec![]) .is_ok() ); assert!(self.app.active(&Id::Menu).is_ok()); @@ -225,6 +297,10 @@ where assert!(self.app.umount(&Id::Menu).is_ok()); Some(Msg::Cscs(CscsMsg::SelectSystem)) } + MenuMsg::Event(event) => { + assert!(self.app.umount(&Id::Menu).is_ok()); + Some(Msg::CreateEvent(event)) + } } } fn handle_job_msg(&mut self, msg: JobMsg) -> Option { @@ -268,6 +344,9 @@ where } } } + fn change_view(&mut self, view: View) { + self.current_view = view; + } } // Let's implement Update for model @@ -279,7 +358,10 @@ where fn update(&mut self, msg: Option) -> Option { if let Some(msg) = msg { // log messages in debug mode - let msg = trace_dbg!(msg); + let msg = match msg { + Msg::None => msg, + _ => trace_dbg!(msg), + }; // Set redraw self.redraw = true; // Match message @@ -293,11 +375,13 @@ where Msg::Menu(menu_msg) => self.handle_menu_msg(menu_msg), Msg::ErrorPopup(popup_msg) => self.handle_error_popup_msg(popup_msg), Msg::InfoPopup(popup_msg) => self.handle_info_popup_msg(popup_msg), + Msg::DownloadPopup(popup_msg) => self.handle_download_popup_msg(popup_msg), Msg::Cscs(CscsMsg::Login(client_id, client_secret)) => { + let event_tx = self.user_event_tx.clone(); let error_tx = self.error_tx.clone(); tokio::spawn(async move { match cscs_login(client_id, client_secret).await { - Ok(_) => {} + Ok(_) => event_tx.send(UserEvent::Cscs(CscsEvent::LoggedIn)).await.unwrap(), Err(e) => error_tx .send(format!( "{:?}", @@ -335,6 +419,21 @@ where Msg::LoginPopup(msg) => self.handle_login_popup_msg(msg), Msg::SystemSelectPopup(msg) => self.handle_system_select_popup_msg(msg), Msg::Job(msg) => self.handle_job_msg(msg), + Msg::ChangeView(view) => { + self.change_view(view); + let event_tx = self.user_event_tx.clone(); + tokio::spawn(async move { + event_tx.send(UserEvent::SwitchedToView(view)).await.unwrap(); + }); + None + } + Msg::CreateEvent(event) => { + let event_tx = self.user_event_tx.clone(); + tokio::spawn(async move { + event_tx.send(event).await.unwrap(); + }); + None + } Msg::None => None, } } else { diff --git a/coman/src/app/user_events.rs b/coman/src/app/user_events.rs index e0ae444..0549526 100644 --- a/coman/src/app/user_events.rs +++ b/coman/src/app/user_events.rs @@ -1,4 +1,7 @@ -use crate::cscs::api_client::{Job, System}; +use crate::{ + app::messages::View, + cscs::api_client::{Job, PathEntry, System}, +}; #[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord)] pub enum CscsEvent { @@ -8,11 +11,19 @@ pub enum CscsEvent { SelectSystemList(Vec), } +#[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord)] +pub enum FileEvent { + List(String, Vec), // Id, Subpaths + DownloadCurrentFile, + DownloadSuccessful, +} #[derive(Debug, Eq, Clone, PartialOrd, Ord)] pub enum UserEvent { Cscs(CscsEvent), + File(FileEvent), Error(String), Info(String), + SwitchedToView(View), } impl PartialEq for UserEvent { diff --git a/coman/src/cli.rs b/coman/src/cli.rs index 8435a6b..ae5809d 100644 --- a/coman/src/cli.rs +++ b/coman/src/cli.rs @@ -29,6 +29,11 @@ pub enum CscsCommands { #[command(subcommand)] command: CscsJobCommands, }, + #[clap(alias("f"))] + File { + #[command(subcommand)] + command: CscsFileCommands, + }, #[clap(alias("s"))] System { #[command(subcommand)] @@ -69,6 +74,27 @@ pub enum CscsJobCommands { job_id: i64, }, } + +#[derive(Subcommand, Debug)] +pub enum CscsFileCommands { + #[clap(alias("ls"))] + List { path: PathBuf }, + #[clap(alias("dl"))] + Download { + #[clap(short, long, help = "account/project to use")] + account: Option, + remote: PathBuf, + local: PathBuf, + }, + #[clap(alias("ul"))] + Upload { + #[clap(short, long, help = "account/project to use")] + account: Option, + local: PathBuf, + remote: PathBuf, + }, +} + #[derive(Subcommand, Debug)] pub enum CscsSystemCommands { #[clap(alias("ls"), about = "List available compute systems")] diff --git a/coman/src/components/context_menu.rs b/coman/src/components/context_menu.rs new file mode 100644 index 0000000..9b4b109 --- /dev/null +++ b/coman/src/components/context_menu.rs @@ -0,0 +1,126 @@ +use tui_realm_stdlib::List; +use tuirealm::{ + AttrValue, Attribute, Component, Event, MockComponent, State, StateValue, + command::{Cmd, CmdResult, Direction, Position}, + event::{Key, KeyEvent}, + props::{Alignment, BorderType, Borders, Color, Table, TableBuilder, TextSpan}, +}; + +use crate::app::{ + messages::{MenuMsg, Msg, View}, + user_events::{FileEvent, UserEvent}, +}; + +#[derive(MockComponent)] +pub struct ContextMenu { + component: List, + current_view: View, +} + +impl ContextMenu { + fn workload_options() -> Table { + TableBuilder::default() + .add_col(TextSpan::from("Login to CSCS").fg(Color::Cyan)) + .add_row() + .add_col(TextSpan::from("Switch System").fg(Color::Cyan)) + .add_row() + .add_col(TextSpan::from("Quit").fg(Color::Cyan)) + .add_row() + .build() + } + fn workload_actions(index: usize) -> Option { + match index { + 0 => Some(Msg::Menu(MenuMsg::CscsLogin)), + 1 => Some(Msg::Menu(MenuMsg::CscsSwitchSystem)), + 2 => Some(Msg::AppClose), + _ => Some(Msg::Menu(MenuMsg::Closed)), + } + } + fn fileview_options() -> Table { + TableBuilder::default() + .add_col(TextSpan::from("Login to CSCS").fg(Color::Cyan)) + .add_row() + .add_col(TextSpan::from("Switch System").fg(Color::Cyan)) + .add_row() + .add_col(TextSpan::from("Download").fg(Color::Cyan)) + .add_row() + .add_col(TextSpan::from("Quit").fg(Color::Cyan)) + .add_row() + .build() + } + fn fileview_actions(index: usize) -> Option { + match index { + 0 => Some(Msg::Menu(MenuMsg::CscsLogin)), + 1 => Some(Msg::Menu(MenuMsg::CscsSwitchSystem)), + 2 => Some(Msg::Menu(MenuMsg::Event(UserEvent::File( + FileEvent::DownloadCurrentFile, + )))), + 3 => Some(Msg::AppClose), + _ => Some(Msg::Menu(MenuMsg::Closed)), + } + } + + pub fn new(view: View) -> Self { + Self { + component: List::default() + .borders(Borders::default().modifiers(BorderType::Thick).color(Color::Yellow)) + .title("Menu", Alignment::Left) + .scroll(true) + .highlighted_color(Color::LightYellow) + .highlighted_str("-") + .rewind(true) + .step(4) + .rows(match view { + View::Workloads => ContextMenu::workload_options(), + View::Files => ContextMenu::fileview_options(), + }) + .selected_line(0), + current_view: view, + } + } +} + +impl Component for ContextMenu { + fn on(&mut self, ev: tuirealm::Event) -> Option { + let _ = match ev { + Event::Keyboard(KeyEvent { code: Key::Down, .. }) => self.perform(Cmd::Move(Direction::Down)), + Event::Keyboard(KeyEvent { + code: Key::PageDown, .. + }) => self.perform(Cmd::Move(Direction::Down)), + Event::Keyboard(KeyEvent { code: Key::Up, .. }) => self.perform(Cmd::Move(Direction::Up)), + Event::Keyboard(KeyEvent { code: Key::PageUp, .. }) => self.perform(Cmd::Move(Direction::Up)), + Event::Keyboard(KeyEvent { code: Key::Home, .. }) => self.perform(Cmd::GoTo(Position::Begin)), + Event::Keyboard(KeyEvent { code: Key::End, .. }) => self.perform(Cmd::GoTo(Position::End)), + Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => { + return Some(Msg::Menu(MenuMsg::Closed)); + } + Event::Keyboard(KeyEvent { + code: Key::Char('x'), .. + }) => { + return Some(Msg::Menu(MenuMsg::Closed)); + } + Event::Keyboard(KeyEvent { code: Key::Enter, .. }) => { + let msg = if let State::One(StateValue::Usize(index)) = self.state() { + match self.current_view { + View::Workloads => ContextMenu::workload_actions(index), + View::Files => ContextMenu::fileview_actions(index), + } + } else { + Some(Msg::Menu(MenuMsg::Closed)) + }; + return msg; + } + Event::User(UserEvent::SwitchedToView(view)) => { + match view { + View::Workloads => self.attr(Attribute::Content, AttrValue::Table(ContextMenu::workload_options())), + View::Files => self.attr(Attribute::Content, AttrValue::Table(ContextMenu::fileview_options())), + }; + self.current_view = view; + CmdResult::None + } + + _ => CmdResult::None, + }; + Some(Msg::None) + } +} diff --git a/coman/src/components/download_popup.rs b/coman/src/components/download_popup.rs new file mode 100644 index 0000000..6641b2d --- /dev/null +++ b/coman/src/components/download_popup.rs @@ -0,0 +1,81 @@ +use std::path::PathBuf; + +use tui_realm_stdlib::Input; +use tuirealm::{ + Component, Event, MockComponent, State, StateValue, + command::{Cmd, CmdResult, Direction, Position}, + event::{Key, KeyEvent, KeyModifiers}, + props::{Alignment, BorderType, Borders, Color, InputType, Style}, +}; + +use crate::app::{ + messages::{DownloadPopupMsg, Msg}, + user_events::UserEvent, +}; + +#[derive(MockComponent)] +pub struct DownloadTargetInput { + component: Input, + remote_path: PathBuf, +} + +impl DownloadTargetInput { + pub fn new(remote_path: PathBuf) -> Self { + Self { + component: Input::default() + .borders(Borders::default().modifiers(BorderType::Thick).color(Color::Green)) + .input_type(InputType::Custom( + |path| { + let path = PathBuf::from(path); + let parent = path.parent(); + match parent { + Some(parent) => parent.exists() && path.to_str().is_some(), + None => false, + } + }, + |_, _| true, + )) + .title("Download Target Path", Alignment::Left) + .invalid_style(Style::default().fg(Color::Red)), + remote_path, + } + } +} + +impl Component for DownloadTargetInput { + fn on(&mut self, ev: tuirealm::Event) -> Option { + let _ = match ev { + Event::Keyboard(KeyEvent { code: Key::Left, .. }) => self.perform(Cmd::Move(Direction::Left)), + Event::Keyboard(KeyEvent { code: Key::Right, .. }) => self.perform(Cmd::Move(Direction::Right)), + Event::Keyboard(KeyEvent { code: Key::Home, .. }) => self.perform(Cmd::GoTo(Position::Begin)), + Event::Keyboard(KeyEvent { code: Key::End, .. }) => self.perform(Cmd::GoTo(Position::End)), + Event::Keyboard(KeyEvent { code: Key::Delete, .. }) => self.perform(Cmd::Cancel), + Event::Keyboard(KeyEvent { + code: Key::Backspace, .. + }) => self.perform(Cmd::Delete), + Event::Keyboard(KeyEvent { + code: Key::Char(ch), + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::Type(ch)), + Event::Keyboard(KeyEvent { + code: Key::Enter, + modifiers: KeyModifiers::NONE, + }) => { + if let State::One(StateValue::String(target)) = self.state() { + let target = PathBuf::from(target); + return Some(Msg::DownloadPopup(DownloadPopupMsg::PathSet( + self.remote_path.clone(), + target, + ))); + } + + CmdResult::None + } + Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => { + return Some(Msg::DownloadPopup(DownloadPopupMsg::Closed)); + } + _ => CmdResult::None, + }; + Some(Msg::None) + } +} diff --git a/coman/src/components/file_tree.rs b/coman/src/components/file_tree.rs new file mode 100644 index 0000000..0046bc8 --- /dev/null +++ b/coman/src/components/file_tree.rs @@ -0,0 +1,160 @@ +use std::{iter, path::PathBuf}; + +use tokio::sync::mpsc; +use tui_realm_treeview::{Node, NodeValue, TREE_CMD_CLOSE, TREE_CMD_OPEN, Tree, TreeView}; +use tuirealm::{ + Component, Event, MockComponent, State, StateValue, + command::{Cmd, CmdResult, Direction, Position}, + event::{Key, KeyEvent, KeyModifiers}, + props::{Alignment, BorderType, Borders, Color, Style}, +}; + +use crate::{ + app::{ + messages::{DownloadPopupMsg, Msg}, + user_events::{FileEvent, UserEvent}, + }, + cscs::{api_client::PathType, ports::TreeAction}, +}; + +#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone)] +pub struct FileNode { + pub name: String, + pub path_type: PathType, +} + +impl FileNode { + pub fn new(name: String, path_type: PathType) -> Self { + Self { name, path_type } + } +} + +impl Default for FileNode { + fn default() -> Self { + Self { + name: "/".to_owned(), + path_type: PathType::Directory, + } + } +} + +impl NodeValue for FileNode { + fn render_parts_iter(&self) -> impl Iterator)> { + iter::once((self.name.as_str(), None)) + } +} + +#[derive(MockComponent)] +pub struct FileTree { + component: TreeView, + file_tree_tx: mpsc::Sender, +} +impl FileTree { + pub fn new(file_tree_tx: mpsc::Sender) -> Self { + let root_node: Node = Node::new("/".to_owned(), FileNode::default()); + let tree = Tree::new(root_node.clone()); + + // Load root node + let tree_tx = file_tree_tx.clone(); + tokio::spawn(async move { tree_tx.send(TreeAction::List(PathBuf::from("/"))).await.unwrap() }); + + Self { + component: TreeView::default() + .foreground(Color::Reset) + .borders( + Borders::default() + .color(Color::LightYellow) + .modifiers(BorderType::Rounded), + ) + .inactive(Style::default().fg(Color::Gray)) + .indent_size(3) + .scroll_step(6) + .title(tree.root().id(), Alignment::Left) + .highlighted_color(Color::LightYellow) + .highlight_symbol("❯") + .with_tree(tree) + .initial_node(root_node.id()), + file_tree_tx, + } + } +} +impl Component for FileTree { + fn on(&mut self, ev: Event) -> Option { + match ev { + Event::Keyboard(KeyEvent { + code: Key::Left, + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::Custom(TREE_CMD_CLOSE)), + Event::Keyboard(KeyEvent { + code: Key::Right, + modifiers: KeyModifiers::NONE, + }) => { + let current_id = self.state().unwrap_one().unwrap_string(); + let node = self.component.tree().root().query(¤t_id).unwrap(); + match node.value().path_type { + PathType::Directory => { + if node.children().is_empty() { + // try loading children if there are none + let tree_tx = self.file_tree_tx.clone(); + tokio::spawn(async move { + tree_tx.send(TreeAction::List(PathBuf::from(current_id))).await.unwrap(); + }); + CmdResult::None + } else { + self.perform(Cmd::Custom(TREE_CMD_OPEN)) + } + } + PathType::File => CmdResult::None, + } + } + Event::Keyboard(KeyEvent { + code: Key::PageDown, + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::Scroll(Direction::Down)), + Event::Keyboard(KeyEvent { + code: Key::PageUp, + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::Scroll(Direction::Up)), + Event::Keyboard(KeyEvent { + code: Key::Down, + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::Move(Direction::Down)), + Event::Keyboard(KeyEvent { + code: Key::Up, + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::Move(Direction::Up)), + Event::Keyboard(KeyEvent { + code: Key::Home, + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::GoTo(Position::Begin)), + Event::Keyboard(KeyEvent { + code: Key::End, + modifiers: KeyModifiers::NONE, + }) => self.perform(Cmd::GoTo(Position::End)), + Event::User(UserEvent::File(FileEvent::List(id, subpaths))) => { + let tree = self.component.tree_mut(); + let parent = tree.root_mut().query_mut(&id).unwrap(); + parent.clear(); + for entry in subpaths { + let id = if entry.name.starts_with("/") { + entry.name.clone() + } else { + format!("{}/{}", id, entry.name.clone()) + }; + parent.add_child(Node::new(id, FileNode::new(entry.name, entry.path_type))); + } + self.perform(Cmd::Custom(TREE_CMD_OPEN)); + CmdResult::None + } + Event::User(UserEvent::File(FileEvent::DownloadCurrentFile)) => { + if let State::One(StateValue::String(id)) = self.state() { + let path = PathBuf::from(id); + return Some(Msg::DownloadPopup(DownloadPopupMsg::Opened(path))); + } + CmdResult::None + } + _ => CmdResult::None, + }; + Some(Msg::None) + } +} diff --git a/coman/src/components/global_listener.rs b/coman/src/components/global_listener.rs index 160d571..84e6de1 100644 --- a/coman/src/components/global_listener.rs +++ b/coman/src/components/global_listener.rs @@ -5,13 +5,14 @@ use tuirealm::{ }; use crate::app::{ - messages::{MenuMsg, Msg, SystemSelectMsg}, - user_events::{CscsEvent, UserEvent}, + messages::{InfoPopupMsg, MenuMsg, Msg, SystemSelectMsg, View}, + user_events::{CscsEvent, FileEvent, UserEvent}, }; #[derive(Default, MockComponent)] pub struct GlobalListener { component: Phantom, + current_view: View, } impl Component for GlobalListener { @@ -27,12 +28,27 @@ impl Component for GlobalListener { Event::Keyboard(KeyEvent { code: Key::Char('x'), .. }) => Some(Msg::Menu(MenuMsg::Opened)), + Event::Keyboard(KeyEvent { + code: Key::Char('f'), .. + }) => { + self.current_view = View::Files; + Some(Msg::ChangeView(View::Files)) + } + Event::Keyboard(KeyEvent { + code: Key::Char('w'), .. + }) => { + self.current_view = View::Workloads; + Some(Msg::ChangeView(View::Workloads)) + } Event::User(UserEvent::Error(msg)) => Some(Msg::Error(msg)), Event::User(UserEvent::Info(msg)) => Some(Msg::Info(msg)), Event::User(UserEvent::Cscs(CscsEvent::LoggedIn)) => Some(Msg::Info("Successfully logged in".to_string())), Event::User(UserEvent::Cscs(CscsEvent::SelectSystemList(systems))) => { Some(Msg::SystemSelectPopup(SystemSelectMsg::Opened(systems))) } + Event::User(UserEvent::File(FileEvent::DownloadSuccessful)) => Some(Msg::InfoPopup(InfoPopupMsg::Opened( + "File successfully downloaded".to_owned(), + ))), _ => None, } } diff --git a/coman/src/components/mod.rs b/coman/src/components/mod.rs index 19078e4..9b8a5b8 100644 --- a/coman/src/components/mod.rs +++ b/coman/src/components/mod.rs @@ -1,4 +1,7 @@ +pub(crate) mod context_menu; +pub(crate) mod download_popup; pub(crate) mod error_popup; +pub(crate) mod file_tree; pub(crate) mod global_listener; pub(crate) mod info_popup; pub(crate) mod login_popup; @@ -6,4 +9,3 @@ pub(crate) mod system_select_popup; pub(crate) mod toolbar; pub(crate) mod workload_list; pub(crate) mod workload_log; -pub(crate) mod workload_menu; diff --git a/coman/src/components/toolbar.rs b/coman/src/components/toolbar.rs index 91a4503..4792c13 100644 --- a/coman/src/components/toolbar.rs +++ b/coman/src/components/toolbar.rs @@ -1,23 +1,44 @@ use tui_realm_stdlib::Label; -use tuirealm::Component; +use tuirealm::{AttrValue, Attribute, Component, Event, MockComponent}; -use crate::app::{messages::Msg, user_events::UserEvent}; +use crate::{ + app::{ + messages::{Msg, View}, + user_events::UserEvent, + }, + trace_dbg, +}; +const WORKLOAD_TOOLTIP: &str = "q: quit, Esc: close/back, l: logs, f: File view, x: menu, ?: help"; +const FILETREE_TOOLTIP: &str = "q: quit, ↑↓: navigate,←→: collapse/expand, x: menu, ?: help"; #[derive(MockComponent)] pub struct Toolbar { component: Label, + current_view: View, } impl Toolbar { pub fn new() -> Self { Self { - component: Label::default().text("q: quit, l: logs, tab/shift+tab: change focus, x: menu, ?: help"), + component: Label::default().text(WORKLOAD_TOOLTIP), + current_view: View::default(), } } } impl Component for Toolbar { - fn on(&mut self, _ev: tuirealm::Event) -> Option { - None + fn on(&mut self, ev: tuirealm::Event) -> Option { + match ev { + Event::User(UserEvent::SwitchedToView(view)) => { + let view = trace_dbg!(view); + self.current_view = view; + match self.current_view { + View::Workloads => self.attr(Attribute::Text, AttrValue::String(WORKLOAD_TOOLTIP.to_owned())), + View::Files => self.attr(Attribute::Text, AttrValue::String(FILETREE_TOOLTIP.to_owned())), + } + None + } + _ => None, + } } } diff --git a/coman/src/components/workload_menu.rs b/coman/src/components/workload_menu.rs deleted file mode 100644 index 8f7d492..0000000 --- a/coman/src/components/workload_menu.rs +++ /dev/null @@ -1,82 +0,0 @@ -use tui_realm_stdlib::List; -use tuirealm::{ - Component, Event, MockComponent, State, StateValue, - command::{Cmd, CmdResult, Direction, Position}, - event::{Key, KeyEvent}, - props::{Alignment, BorderType, Borders, Color, TableBuilder, TextSpan}, -}; - -use crate::app::{ - messages::{MenuMsg, Msg}, - user_events::UserEvent, -}; - -#[derive(MockComponent)] -pub struct WorkloadMenu { - component: List, -} - -impl Default for WorkloadMenu { - fn default() -> Self { - Self { - component: List::default() - .borders(Borders::default().modifiers(BorderType::Thick).color(Color::Yellow)) - .title("Menu", Alignment::Left) - .scroll(true) - .highlighted_color(Color::LightYellow) - .highlighted_str("-") - .rewind(true) - .step(4) - .rows( - TableBuilder::default() - .add_col(TextSpan::from("Login to CSCS").fg(Color::Cyan)) - .add_row() - .add_col(TextSpan::from("Switch System").fg(Color::Cyan)) - .add_row() - .add_col(TextSpan::from("Quit").fg(Color::Cyan)) - .add_row() - .build(), - ) - .selected_line(0), - } - } -} - -impl Component for WorkloadMenu { - fn on(&mut self, ev: tuirealm::Event) -> Option { - let _ = match ev { - Event::Keyboard(KeyEvent { code: Key::Down, .. }) => self.perform(Cmd::Move(Direction::Down)), - Event::Keyboard(KeyEvent { - code: Key::PageDown, .. - }) => self.perform(Cmd::Move(Direction::Down)), - Event::Keyboard(KeyEvent { code: Key::Up, .. }) => self.perform(Cmd::Move(Direction::Up)), - Event::Keyboard(KeyEvent { code: Key::PageUp, .. }) => self.perform(Cmd::Move(Direction::Up)), - Event::Keyboard(KeyEvent { code: Key::Home, .. }) => self.perform(Cmd::GoTo(Position::Begin)), - Event::Keyboard(KeyEvent { code: Key::End, .. }) => self.perform(Cmd::GoTo(Position::End)), - Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => { - return Some(Msg::Menu(MenuMsg::Closed)); - } - Event::Keyboard(KeyEvent { - code: Key::Char('x'), .. - }) => { - return Some(Msg::Menu(MenuMsg::Closed)); - } - Event::Keyboard(KeyEvent { code: Key::Enter, .. }) => { - let msg = if let State::One(StateValue::Usize(index)) = self.state() { - match index { - 0 => Some(Msg::Menu(MenuMsg::CscsLogin)), - 1 => Some(Msg::Menu(MenuMsg::CscsSwitchSystem)), - 2 => Some(Msg::AppClose), - _ => Some(Msg::Menu(MenuMsg::Closed)), - } - } else { - Some(Msg::Menu(MenuMsg::Closed)) - }; - return msg; - } - - _ => CmdResult::None, - }; - Some(Msg::None) - } -} diff --git a/coman/src/config.rs b/coman/src/config.rs index 381199f..34df4cd 100644 --- a/coman/src/config.rs +++ b/coman/src/config.rs @@ -28,6 +28,8 @@ pub struct CscsConfig { #[serde(default)] pub current_system: String, #[serde(default)] + pub account: String, + #[serde(default)] pub sbatch_script_template: String, #[serde(default)] pub workdir: Option, @@ -101,6 +103,8 @@ impl Config { let config_dir = get_config_dir(); let path = config_dir.join(CONFIG_FILE_NAME.clone()); let content = toml::to_string_pretty(self)?; + let parent = path.parent().unwrap(); + std::fs::create_dir_all(parent)?; std::fs::write(path, content)?; Ok(()) } diff --git a/coman/src/cscs/api_client.rs b/coman/src/cscs/api_client.rs index 9690d16..6e9aaa0 100644 --- a/coman/src/cscs/api_client.rs +++ b/coman/src/cscs/api_client.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, path::PathBuf}; use chrono::prelude::*; use color_eyre::eyre::{Context, Result}; +use eyre::eyre; use firecrest_client::{ client::FirecrestClient, compute_api::{ @@ -9,14 +10,18 @@ use firecrest_client::{ post_compute_system_job, }, filesystem_api::{ - get_filesystem_ops_tail, post_filesystem_ops_mkdir, post_filesystem_ops_upload, put_filesystem_ops_chmod, + get_filesystem_ops_download, get_filesystem_ops_ls, get_filesystem_ops_stat, get_filesystem_ops_tail, + post_filesystem_ops_mkdir, post_filesystem_ops_upload, post_filesystem_transfer_download, + post_filesystem_transfer_upload, put_filesystem_ops_chmod, }, status_api::{get_status_systems, get_status_userinfo}, types::{ - FileSystem as CSCSFileSystem, FileSystemDataType, HealthCheckType, HpcclusterOutput, JobMetadataModel, - JobModelOutput, SchedulerServiceHealth, UserInfoResponse, + DownloadFileResponseTransferDirectives, File as CSCSFile, FileStat as CSCSFileStat, + FileSystem as CSCSFileSystem, FileSystemDataType, HPCCluster, HealthCheckType, JobMetadataModel, JobModel, + S3TransferResponse, SchedulerServiceHealth, UserInfoResponse, }, }; +use reqwest::Url; use strum::Display; use crate::trace_dbg; @@ -58,6 +63,19 @@ impl From for FileSystemType { } } } +impl From for FileSystemType { + fn from(value: String) -> Self { + match value.as_str() { + "users" => Self::Users, + "store" => Self::Store, + "archive" => Self::Archive, + "apps" => Self::Apps, + "scratch" => Self::Scratch, + "project" => Self::Project, + _ => panic!("unknown file system type: {}", value), + } + } +} #[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord, tabled::Tabled)] pub struct FileSystem { pub data_type: FileSystemType, @@ -74,6 +92,63 @@ impl From for FileSystem { } } +#[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord, Display)] +pub enum PathType { + Directory, + File, +} + +#[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord, tabled::Tabled)] +pub struct PathEntry { + #[tabled(order = 3)] + pub name: String, + #[tabled(order = 1)] + pub path_type: PathType, + #[tabled(display("display_option"), order = 0)] + pub permissions: Option, + #[tabled(display("display_option"), order = 2)] + pub size: Option, +} + +fn display_option(value: &Option) -> String +where + V: ToString, +{ + match value { + Some(s) => s.to_string(), + None => "".to_owned(), + } +} + +impl From for PathEntry { + fn from(value: CSCSFile) -> Self { + let size = match value.size.parse::() { + Ok(size) => size, + Err(err) => panic!("Couldn't parse file size {}: {:?}", value.size, err), + }; + Self { + name: value.name, + path_type: match value.r#type.as_str() { + "d" => PathType::Directory, + "-" => PathType::File, + _ => panic!("Unknown file type: {}", value.r#type), + }, + permissions: Some(value.permissions), + size: Some(size), + } + } +} + +#[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord)] +pub struct FileStat { + pub size: i64, +} +impl From for FileStat { + fn from(value: CSCSFileStat) -> Self { + Self { size: value.size } + } +} + #[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord, Display)] pub enum JobStatus { Pending, @@ -81,6 +156,7 @@ pub enum JobStatus { Finished, Cancelled, Failed, + Timeout, } impl From for JobStatus { fn from(value: String) -> Self { @@ -90,6 +166,7 @@ impl From for JobStatus { "COMPLETED" => JobStatus::Finished, "CANCELLED" => JobStatus::Cancelled, "PENDING" => JobStatus::Pending, + "TIMEOUT" => JobStatus::Timeout, other => panic!("got job status: {}", other), } } @@ -105,8 +182,8 @@ pub struct Job { #[tabled(display("display_option_datetime"))] pub end_date: Option>, } -impl From for Job { - fn from(value: JobModelOutput) -> Self { +impl From for Job { + fn from(value: JobModel) -> Self { Self { id: value.job_id as usize, name: value.name, @@ -146,8 +223,8 @@ fn display_option_datetime(value: &Option>) -> String { None => "".to_owned(), } } -impl From<(JobModelOutput, JobMetadataModel)> for JobDetail { - fn from(value: (JobModelOutput, JobMetadataModel)) -> Self { +impl From<(JobModel, JobMetadataModel)> for JobDetail { + fn from(value: (JobModel, JobMetadataModel)) -> Self { Self { id: value.0.job_id as usize, name: value.0.name, @@ -192,6 +269,18 @@ impl From for ServiceType { } } } +impl From for ServiceType { + fn from(value: String) -> Self { + match value.as_str() { + "scheduler" => ServiceType::Scheduler, + "filesystem" => ServiceType::Filesystem, + "ssh" => ServiceType::Ssh, + "s3" => ServiceType::S3, + "exception" => ServiceType::Exception, + _ => panic!("unknown service type: {}", value), + } + } +} #[derive(Debug, Eq, Clone, PartialEq, PartialOrd, Ord, tabled::Tabled)] pub struct ServicesHealth { @@ -222,8 +311,8 @@ pub struct System { #[tabled(display = "display_health")] pub services_health: Option>, } -impl From for System { - fn from(value: HpcclusterOutput) -> Self { +impl From for System { + fn from(value: HPCCluster) -> Self { Self { name: value.name, file_systems: value @@ -246,6 +335,31 @@ fn display_health(h: &Option>) -> String { .unwrap_or("".to_string()) } +#[derive(Debug, Clone)] +pub struct S3Upload { + pub parts_upload_urls: Vec, + pub complete_upload_url: Url, + pub part_size: u64, + pub num_parts: u64, +} + +impl S3Upload { + fn convert(value: S3TransferResponse, size: u64) -> Result { + let complete_url = value.complete_upload_url.ok_or(eyre!("no upload completion url set"))?; + let part_urls = value.parts_upload_urls.ok_or(eyre!("no part upload urls set"))?; + let part_size = value.max_part_size.ok_or(eyre!("couldn't parse size"))? as u64; + Ok(Self { + parts_upload_urls: part_urls + .iter() + .map(|u| Url::parse(u).wrap_err("couldn't parse url")) + .collect::>>()?, + part_size, + complete_upload_url: Url::parse(&complete_url)?, + num_parts: (size.div_ceil(part_size)), + }) + } +} + pub struct CscsApi { client: FirecrestClient, } @@ -348,6 +462,50 @@ impl CscsApi { .wrap_err("couldn't upload file")?; Ok(()) } + pub async fn transfer_upload( + &self, + system_name: &str, + account: &str, + path: PathBuf, + size: i64, + ) -> Result<(i64, S3Upload)> { + if account.is_empty() { + return Err(eyre!( + "An account is required, set it in the config file or with the --account flag" + )); + } + let job = post_filesystem_transfer_upload(&self.client, system_name, account, path, size) + .await + .wrap_err("couldn't upload file")?; + if let DownloadFileResponseTransferDirectives::S3(directives) = job.transfer_directives { + Ok((job.transfer_job.job_id, S3Upload::convert(directives, size as u64)?)) + } else { + trace_dbg!(job); + Err(eyre!("didn't get S3 transfer directive")) + } + } + pub async fn download(&self, system_name: &str, path: PathBuf) -> Result { + let content = get_filesystem_ops_download(&self.client, system_name, path) + .await + .wrap_err("couldn't download file")?; + Ok(content) + } + pub async fn transfer_download(&self, system_name: &str, account: &str, path: PathBuf) -> Result<(i64, Url)> { + if account.is_empty() { + return Err(eyre!( + "An account is required, set it in the config file or with the --account flag" + )); + } + let job = post_filesystem_transfer_download(&self.client, system_name, account, path) + .await + .wrap_err("couldn't transfer file")?; + if let DownloadFileResponseTransferDirectives::S3(directives) = job.transfer_directives { + let download_url = Url::parse(&directives.download_url.unwrap())?; + Ok((job.transfer_job.job_id, download_url)) + } else { + Err(eyre!("didn't get S3 transfer directive")) + } + } pub async fn tail(&self, system_name: &str, path: PathBuf, lines: usize) -> Result { let result = get_filesystem_ops_tail(&self.client, system_name, path, lines) .await @@ -357,6 +515,22 @@ impl CscsApi { None => Ok("".to_string()), } } + pub async fn list_path(&self, system_name: &str, path: PathBuf) -> Result> { + let result = get_filesystem_ops_ls(&self.client, system_name, path) + .await + .wrap_err("couldn't list path")?; + let result = trace_dbg!(result); + match result.output { + Some(entries) => Ok(entries.into_iter().map(|e| e.into()).collect()), + None => Ok(vec![]), + } + } + pub async fn stat_path(&self, system_name: &str, path: PathBuf) -> Result> { + let result = get_filesystem_ops_stat(&self.client, system_name, path) + .await + .wrap_err("couldn't stat file")?; + Ok(result.output.map(|f| f.into())) + } pub async fn get_userinfo(&self, system_name: &str) -> Result { let result = get_status_userinfo(&self.client, system_name) .await diff --git a/coman/src/cscs/cli.rs b/coman/src/cscs/cli.rs index e145199..442e515 100644 --- a/coman/src/cscs/cli.rs +++ b/coman/src/cscs/cli.rs @@ -1,12 +1,27 @@ -use std::path::PathBuf; +use std::{ + io::{SeekFrom, Write}, + path::PathBuf, + time::{Duration, Instant}, +}; use color_eyre::{Result, eyre::Context}; +use eyre::eyre; +use futures::StreamExt; use inquire::{Password, Text}; +use itertools::Itertools; +use reqwest::Url; +use tokio::{ + fs::File, + io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, BufReader}, +}; use crate::{ - cscs::handlers::{ - cscs_job_cancel, cscs_job_details, cscs_job_list, cscs_job_log, cscs_login, cscs_start_job, cscs_system_list, - cscs_system_set, + cscs::{ + api_client::JobStatus, + handlers::{ + cscs_file_download, cscs_file_list, cscs_file_upload, cscs_job_cancel, cscs_job_details, cscs_job_list, + cscs_job_log, cscs_login, cscs_start_job, cscs_system_list, cscs_system_set, + }, }, util::types::DockerImageUrl, }; @@ -103,3 +118,129 @@ pub(crate) async fn cli_cscs_system_list() -> Result<()> { pub(crate) async fn cli_cscs_set_system(system_name: String, global: bool) -> Result<()> { cscs_system_set(system_name, global).await } + +pub(crate) async fn cli_cscs_file_list(path: PathBuf) -> Result<()> { + match cscs_file_list(path).await { + Ok(path_entries) => { + let mut table = tabled::Table::new(path_entries); + table.with(tabled::settings::Style::empty()); + println!("{}", table); + Ok(()) + } + Err(e) => Err(e), + } +} + +pub(crate) async fn cli_cscs_file_download(remote: PathBuf, local: PathBuf, account: Option) -> Result<()> { + match cscs_file_download(remote, local.clone(), account).await { + Ok(None) => { + println!("File successfully downloaded"); + Ok(()) + } + Ok(Some(job_data)) => { + // file is large, so we created a transfer job to s3 that we need to wait on + // then we can download from s3 + println!("started s3 transfer job {}", job_data.0); + let mut transfer_done = false; + while !transfer_done { + if let Some(job) = cscs_job_details(job_data.0).await? { + match job.status { + JobStatus::Pending | JobStatus::Running => {} + JobStatus::Finished => transfer_done = true, + JobStatus::Cancelled | JobStatus::Failed => return Err(eyre!("transfer job failed")), + JobStatus::Timeout => return Err(eyre!("transfer job timed out")), + } + } + tokio::time::sleep(Duration::from_secs(2)).await; + } + + // download from s3 + println!("Downloading file from s3, this might take a while"); + + let mut output = File::create(local).await?; + let mut stream = reqwest::get(job_data.1).await?.bytes_stream(); + let mut progress = 0; + let mut start_time = Instant::now(); + while let Some(chunk_result) = stream.next().await { + let chunk = chunk_result?; + output.write_all(&chunk).await?; + progress += chunk.len(); + + if start_time.elapsed() >= Duration::from_secs(1) { + print!("\rDownloaded {}/{}Mb", progress / 1024 / 1024, job_data.2 / 1024 / 1024); + std::io::stdout().flush()?; + start_time = Instant::now(); + } + } + output.flush().await?; + println!(); //force newline + println!("Download complete"); + + Ok(()) + } + Err(e) => Err(e), + } +} + +pub(crate) async fn cli_cscs_file_upload(local: PathBuf, remote: PathBuf, account: Option) -> Result<()> { + match cscs_file_upload(local.clone(), remote, account).await { + Ok(None) => { + println!("File successfully uploaded"); + Ok(()) + } + Ok(Some(transfer_data)) => { + println!("starting file transfer, this might take a while"); + let mut etags: Vec = Vec::new(); + let client = reqwest::Client::new(); + let num_parts = transfer_data.1.num_parts; + for (chunk_id, transfer_url) in transfer_data.1.parts_upload_urls.into_iter().enumerate() { + println!( + "Uploading part {}/{} ({}Mb)", + chunk_id + 1, + num_parts, + transfer_data.1.part_size / 1024 / 1024 + ); + let etag = upload_chunk( + local.clone(), + (chunk_id as u64) * transfer_data.1.part_size, + transfer_data.1.part_size, + transfer_url, + ) + .await?; + etags.push(etag); + } + + let body = etags + .into_iter() + .enumerate() + .map(|(i, etag)| (i + 1, etag)) + .map(|(i, etag)| format!("{}{}", i, etag)) + .join(""); + let body = format!("{}", body); + let req = client.post(transfer_data.1.complete_upload_url).body(body).build()?; + let resp = client.execute(req).await?; + match resp.error_for_status() { + Ok(_) => { + println!("done"); + Ok(()) + } + Err(e) => Err(e).wrap_err("failed to complete upload"), + } + } + Err(e) => Err(e), + } +} + +async fn upload_chunk(path: PathBuf, offset: u64, size: u64, url: Url) -> Result { + let client = reqwest::Client::new(); + + let source_file = File::open(path).await?; + let mut buf = vec![]; + let mut reader = BufReader::new(source_file); + reader.seek(SeekFrom::Start(offset)).await?; + let mut chunk = reader.take(size); + chunk.read_to_end(&mut buf).await?; + let req = client.put(url).body(buf).build()?; + let resp = client.execute(req).await?; + Ok(resp.headers()["etag"].to_str()?.to_owned()) +} diff --git a/coman/src/cscs/handlers.rs b/coman/src/cscs/handlers.rs index d1bc354..fbe9534 100644 --- a/coman/src/cscs/handlers.rs +++ b/coman/src/cscs/handlers.rs @@ -1,11 +1,12 @@ -use std::path::PathBuf; +use std::{os::unix::fs::MetadataExt, path::PathBuf}; use color_eyre::{Result, eyre::eyre}; +use reqwest::Url; use crate::{ config::Config, cscs::{ - api_client::{CscsApi, FileSystemType, Job, JobDetail, System}, + api_client::{CscsApi, FileStat, FileSystemType, Job, JobDetail, PathEntry, S3Upload, System, UserInfo}, oauth2::{ CLIENT_ID_SECRET_NAME, CLIENT_SECRET_SECRET_NAME, client_credentials_login, finish_cscs_device_login, start_cscs_device_login, @@ -16,6 +17,9 @@ use crate::{ types::DockerImageUrl, }, }; + +const CSCS_MAX_DIRECT_SIZE: usize = 5242880; + async fn get_access_token() -> Result { let client_id = match get_secret(CLIENT_ID_SECRET_NAME).await { Ok(Some(client_id)) => client_id, @@ -239,3 +243,107 @@ pub async fn cscs_start_job( Err(e) => Err(e), } } + +pub async fn cscs_file_list(path: PathBuf) -> Result> { + match get_access_token().await { + Ok(access_token) => { + let api_client = CscsApi::new(access_token.0).unwrap(); + let config = Config::new().unwrap(); + api_client.list_path(&config.cscs.current_system, path).await + } + Err(e) => Err(e), + } +} + +pub async fn cscs_file_download( + remote: PathBuf, + local: PathBuf, + account: Option, +) -> Result> { + match get_access_token().await { + Ok(access_token) => { + let api_client = CscsApi::new(access_token.0).unwrap(); + let config = Config::new().unwrap(); + let paths = api_client + .list_path(&config.cscs.current_system, remote.clone()) + .await?; + let path = paths.first().ok_or(eyre!("remote path doesn't exist"))?; + if let crate::cscs::api_client::PathType::Directory = path.path_type { + return Err(eyre!("remote path must be a file, not directory")); + } + let size = path.size.ok_or(eyre!("couldn't determin download file size"))?; + if size < CSCS_MAX_DIRECT_SIZE { + // download directly + let contents = api_client.download(&config.cscs.current_system, remote).await?; + std::fs::write(local, contents)?; + Ok(None) + } else { + // download via s3 + let job_data = api_client + .transfer_download( + &config.cscs.current_system, + &account.unwrap_or(config.cscs.account), + remote, + ) + .await?; + Ok(Some((job_data.0, job_data.1, size))) + } + } + Err(e) => Err(e), + } +} +pub async fn cscs_file_upload( + local: PathBuf, + remote: PathBuf, + account: Option, +) -> Result> { + match get_access_token().await { + Ok(access_token) => { + let api_client = CscsApi::new(access_token.0).unwrap(); + let config = Config::new().unwrap(); + + let file_meta = std::fs::metadata(local.clone())?; + if (file_meta.size() as usize) < CSCS_MAX_DIRECT_SIZE { + // upload directly + let contents = std::fs::read(local)?; + api_client.upload(&config.cscs.current_system, remote, contents).await?; + Ok(None) + } else { + // upload via s3 + let transfer_data = api_client + .transfer_upload( + &config.cscs.current_system, + &account.unwrap_or(config.cscs.account), + remote, + file_meta.size() as i64, + ) + .await?; + + Ok(Some(transfer_data)) + } + } + Err(e) => Err(e), + } +} + +pub async fn cscs_stat_path(path: PathBuf) -> Result> { + match get_access_token().await { + Ok(access_token) => { + let api_client = CscsApi::new(access_token.0).unwrap(); + let config = Config::new().unwrap(); + api_client.stat_path(&config.cscs.current_system, path).await + } + Err(e) => Err(e), + } +} + +pub async fn cscs_user_info() -> Result { + match get_access_token().await { + Ok(access_token) => { + let api_client = CscsApi::new(access_token.0).unwrap(); + let config = Config::new().unwrap(); + api_client.get_userinfo(&config.cscs.current_system).await + } + Err(e) => Err(e), + } +} diff --git a/coman/src/cscs/ports.rs b/coman/src/cscs/ports.rs index e6474e8..61c2405 100644 --- a/coman/src/cscs/ports.rs +++ b/coman/src/cscs/ports.rs @@ -1,22 +1,33 @@ -use color_eyre::{Section, eyre::Context}; -use eyre::Report; +use std::{path::PathBuf, time::Duration}; + +use color_eyre::{ + Section, + eyre::{Context, Report, Result, eyre}, +}; +use futures::StreamExt; use openidconnect::core::CoreDeviceAuthorizationResponse; -use tokio::sync::mpsc; +use tokio::{fs::File, io::AsyncWriteExt, sync::mpsc}; use tuirealm::{ Event, listener::{ListenerResult, PollAsync}, }; use crate::{ - app::user_events::{CscsEvent, UserEvent}, + app::user_events::{CscsEvent, FileEvent, UserEvent}, + config::Config, cscs::{ - handlers::{cscs_job_list, cscs_job_log, cscs_system_list}, + api_client::{JobStatus, PathEntry, PathType}, + handlers::{ + cscs_file_download, cscs_file_list, cscs_job_details, cscs_job_list, cscs_job_log, cscs_stat_path, + cscs_system_list, cscs_user_info, + }, oauth2::{ACCESS_TOKEN_SECRET_NAME, REFRESH_TOKEN_SECRET_NAME, finish_cscs_device_login}, }, trace_dbg, util::keyring::store_secret, }; +/// This port does the polling of the token for finishing the device code oauth2 flow #[allow(dead_code)] pub(crate) struct AsyncDeviceFlowPort { receiver: mpsc::Receiver<(CoreDeviceAuthorizationResponse, String)>, @@ -90,6 +101,8 @@ impl PollAsync for AsyncDeviceFlowPort { } } } + +/// This port periodically fetches jobs from CSCS pub(crate) struct AsyncFetchWorkloadsPort {} impl AsyncFetchWorkloadsPort { @@ -111,6 +124,7 @@ impl PollAsync for AsyncFetchWorkloadsPort { } } +/// This port handles getting available compute systems from CSCS pub(crate) struct AsyncSelectSystemPort { receiver: mpsc::Receiver<()>, } @@ -140,6 +154,7 @@ impl PollAsync for AsyncSelectSystemPort { } } +/// This port handles polling the logs of a CSCS job pub(crate) struct AsyncJobLogPort { receiver: mpsc::Receiver>, current_job: Option, @@ -181,3 +196,156 @@ impl PollAsync for AsyncJobLogPort { } } } + +pub enum TreeAction { + List(PathBuf), + Download(PathBuf, PathBuf), +} + +/// This port handles asynchronous file operations on CSCS +pub(crate) struct AsyncFileTreePort { + receiver: mpsc::Receiver, +} + +impl AsyncFileTreePort { + pub fn new(receiver: mpsc::Receiver) -> Self { + Self { receiver } + } +} +async fn list_files(id: PathBuf) -> Result>> { + let id_str = id + .clone() + .into_os_string() + .into_string() + .map_err(|_| eyre!("couldn't convert id to string".to_owned()))?; + if id_str == "/" { + // load file system roots + let config = Config::new().expect("couldn't load config"); + let user_info = cscs_user_info().await?; + let systems = cscs_system_list().await?; + let system = systems + .iter() + .find(|s| s.name == config.cscs.current_system) + .unwrap_or_else(|| panic!("couldn't get info for system {}", config.cscs.current_system)); + // listing big directories fails in the api and we might not actually be allowed to + // access the roots of the storage. + // So we try to append the user name to the paths and use that, if it works + let mut subpaths = vec![]; + for fs in system.file_systems.clone() { + let entry = match cscs_stat_path(PathBuf::from(fs.path.clone()).join(user_info.name.clone())).await { + Ok(Some(_)) => PathEntry { + name: format!("{}/{}", fs.path.clone(), user_info.name), + path_type: PathType::Directory, + permissions: None, + size: None, + }, + _ => PathEntry { + name: fs.path.clone(), + path_type: PathType::Directory, + permissions: None, + size: None, + }, + }; + subpaths.push(entry); + } + Ok(Some(Event::User(UserEvent::File(FileEvent::List(id_str, subpaths))))) + } else { + let subpaths = cscs_file_list(id).await?; + Ok(Some(Event::User(UserEvent::File(FileEvent::List(id_str, subpaths))))) + } +} +async fn download_file(remote: PathBuf, local: PathBuf) -> Result>> { + match cscs_file_download(remote, local.clone(), None).await { + Ok(None) => Ok(Some(Event::User(UserEvent::File(FileEvent::DownloadSuccessful)))), + Ok(Some(job_data)) => { + // file is large, so we created a transfer job to s3 that we need to wait on + // then we can download from s3 + // TODO: add status updates once we have some sort of status line update functionality + let mut transfer_done = false; + while !transfer_done { + if let Some(job) = cscs_job_details(job_data.0).await? { + match job.status { + JobStatus::Pending | JobStatus::Running => {} + JobStatus::Finished => transfer_done = true, + JobStatus::Cancelled | JobStatus::Failed => { + return Ok(Some(Event::User(UserEvent::Error( + "file download job failed".to_string(), + )))); + } + JobStatus::Timeout => { + return Ok(Some(Event::User(UserEvent::Error( + "file download job timed out".to_string(), + )))); + } + } + } + tokio::time::sleep(Duration::from_secs(2)).await; + } + + // download from s3 + + let mut output = File::create(local).await?; + let mut stream = reqwest::get(job_data.1).await?.bytes_stream(); + while let Some(chunk_result) = stream.next().await { + let chunk = chunk_result?; + output.write_all(&chunk).await?; + } + output.flush().await?; + Ok(Some(Event::User(UserEvent::File(FileEvent::DownloadSuccessful)))) + } + Err(e) => Ok(Some(Event::User(UserEvent::Error(format!( + "{:?}", + Err::<(), Report>(e).wrap_err("couldn't download path") + ))))), + } +} +#[tuirealm::async_trait] +impl PollAsync for AsyncFileTreePort { + async fn poll(&mut self) -> ListenerResult>> { + if self.receiver.is_closed() { + return Ok(None); + } + if let Some(action) = self.receiver.recv().await { + match action { + TreeAction::List(id) => match list_files(id).await { + Ok(event) => Ok(event), + Err(e) => Ok(Some(Event::User(UserEvent::Error(format!( + "{:?}", + Err::<(), Report>(e).wrap_err("couldn't list subpaths") + ))))), + }, + TreeAction::Download(remote, local) => match download_file(remote, local).await { + Ok(event) => Ok(event), + Err(e) => Ok(Some(Event::User(UserEvent::Error(format!( + "{:?}", + Err::<(), Report>(e).wrap_err("couldn't download file") + ))))), + }, + } + } else { + return Ok(Some(Event::None)); + } + } +} + +/// This is a convenience class to create new user events from the model +pub(crate) struct AsyncUserEventPort { + receiver: mpsc::Receiver, +} + +impl AsyncUserEventPort { + pub fn new(receiver: mpsc::Receiver) -> Self { + Self { receiver } + } +} +#[tuirealm::async_trait] +impl PollAsync for AsyncUserEventPort { + async fn poll(&mut self) -> ListenerResult>> { + if let Some(event) = self.receiver.recv().await { + let event = trace_dbg!(event); + Ok(Some(Event::User(event))) + } else { + Ok(Some(Event::None)) + } + } +} diff --git a/coman/src/main.rs b/coman/src/main.rs index 8570872..5361876 100644 --- a/coman/src/main.rs +++ b/coman/src/main.rs @@ -13,19 +13,22 @@ use tuirealm::{ use crate::{ app::{ ids::Id, - messages::Msg, + messages::{Msg, View}, model::Model, - user_events::{CscsEvent, UserEvent}, + user_events::{CscsEvent, FileEvent, UserEvent}, }, cli::{Cli, version}, - components::{global_listener::GlobalListener, toolbar::Toolbar, workload_list::WorkloadList}, + components::{file_tree::FileTree, global_listener::GlobalListener, toolbar::Toolbar, workload_list::WorkloadList}, config::Config, cscs::{ cli::{ - cli_cscs_job_cancel, cli_cscs_job_detail, cli_cscs_job_list, cli_cscs_job_log, cli_cscs_job_start, - cli_cscs_login, cli_cscs_set_system, cli_cscs_system_list, + cli_cscs_file_download, cli_cscs_file_list, cli_cscs_file_upload, cli_cscs_job_cancel, cli_cscs_job_detail, + cli_cscs_job_list, cli_cscs_job_log, cli_cscs_job_start, cli_cscs_login, cli_cscs_set_system, + cli_cscs_system_list, + }, + ports::{ + AsyncFetchWorkloadsPort, AsyncFileTreePort, AsyncJobLogPort, AsyncSelectSystemPort, AsyncUserEventPort, }, - ports::{AsyncFetchWorkloadsPort, AsyncJobLogPort, AsyncSelectSystemPort}, }, errors::AsyncErrorPort, }; @@ -65,6 +68,15 @@ async fn main() -> Result<()> { } => cli_cscs_job_start(script_file, image, command, workdir, env).await?, cli::CscsJobCommands::Cancel { job_id } => cli_cscs_job_cancel(job_id).await?, }, + cli::CscsCommands::File { command } => match command { + cli::CscsFileCommands::List { path } => cli_cscs_file_list(path).await?, + cli::CscsFileCommands::Download { remote, local, account } => { + cli_cscs_file_download(remote, local, account).await? + } + cli::CscsFileCommands::Upload { local, remote, account } => { + cli_cscs_file_upload(local, remote, account).await? + } + }, cli::CscsCommands::System { command } => match command { cli::CscsSystemCommands::List => cli_cscs_system_list().await?, cli::CscsSystemCommands::Set { system_name, global } => { @@ -89,7 +101,14 @@ fn run_tui() -> Result<()> { let (select_system_tx, select_system_rx) = mpsc::channel(100); let (job_log_tx, job_log_rx) = mpsc::channel(100); + let (file_tree_tx, file_tree_rx) = mpsc::channel(100); + let (user_event_tx, user_event_rx) = mpsc::channel(100); let (error_tx, error_rx) = mpsc::channel(100); + + // Set up ports that produce events + // Since the TUI code is synchronous, we set up async ports for async actions that + // listen on a tokio queue for triggers, do async actions and then produce regular events + // that the components can handle let event_listener = EventListenerCfg::default() .with_handle(handle) .async_crossterm_input_listener(Duration::default(), 3) @@ -100,24 +119,43 @@ fn run_tui() -> Result<()> { Duration::default(), 1, ) - .add_async_port(Box::new(AsyncJobLogPort::new(job_log_rx)), Duration::from_secs(3), 1); + .add_async_port(Box::new(AsyncJobLogPort::new(job_log_rx)), Duration::from_secs(3), 1) + .add_async_port(Box::new(AsyncFileTreePort::new(file_tree_rx)), Duration::default(), 1) + .add_async_port(Box::new(AsyncUserEventPort::new(user_event_rx)), Duration::default(), 1); let mut app: Application = Application::init(event_listener); - // subscribe component to clause - app.mount(Id::Toolbar, Box::new(Toolbar::new()), vec![])?; + // Mount components and set up which component get which message + app.mount( + Id::Toolbar, + Box::new(Toolbar::new()), + vec![Sub::new( + SubEventClause::Discriminant(UserEvent::SwitchedToView(View::default())), + SubClause::Always, + )], + )?; app.mount( Id::WorkloadList, Box::new(WorkloadList::default()), vec![Sub::new( SubEventClause::Any, - SubClause::Not(Box::new(SubClause::OrMany(vec![ - SubClause::IsMounted(Id::Menu), - SubClause::IsMounted(Id::ErrorPopup), - SubClause::IsMounted(Id::LoginPopup), - ]))), + SubClause::AndMany(vec![SubClause::IsMounted(Id::WorkloadList), popup_exclusion_clause()]), )], )?; + app.mount( + Id::FileView, + Box::new(FileTree::new(file_tree_tx.clone())), + vec![ + Sub::new( + SubEventClause::Discriminant(UserEvent::File(FileEvent::List("".to_owned(), vec![]))), + SubClause::Always, + ), + Sub::new( + SubEventClause::Any, + SubClause::AndMany(vec![SubClause::IsMounted(Id::FileView), popup_exclusion_clause()]), + ), + ], + )?; app.mount( Id::GlobalListener, Box::new(GlobalListener::default()), @@ -144,6 +182,10 @@ fn run_tui() -> Result<()> { SubEventClause::Discriminant(UserEvent::Error("".to_string())), SubClause::Always, ), + Sub::new( + SubEventClause::Discriminant(UserEvent::File(FileEvent::DownloadSuccessful)), + SubClause::Always, + ), Sub::new( SubEventClause::User(UserEvent::Cscs(CscsEvent::LoggedIn)), SubClause::Always, @@ -153,18 +195,36 @@ fn run_tui() -> Result<()> { code: Key::Char('x'), modifiers: KeyModifiers::NONE, }), - SubClause::Not(Box::new(SubClause::OrMany(vec![ - SubClause::IsMounted(Id::Menu), - SubClause::IsMounted(Id::ErrorPopup), - SubClause::IsMounted(Id::LoginPopup), - ]))), + popup_exclusion_clause(), + ), + Sub::new( + SubEventClause::Keyboard(KeyEvent { + code: Key::Char('f'), + modifiers: KeyModifiers::NONE, + }), + popup_exclusion_clause(), + ), + Sub::new( + SubEventClause::Keyboard(KeyEvent { + code: Key::Char('w'), + modifiers: KeyModifiers::NONE, + }), + popup_exclusion_clause(), ), ], )?; app.active(&Id::WorkloadList).expect("failed to active"); - let mut model = Model::new(app, bridge, error_tx, select_system_tx, job_log_tx); + let mut model = Model::new( + app, + bridge, + error_tx, + select_system_tx, + job_log_tx, + user_event_tx, + file_tree_tx, + ); // Main loop // NOTE: loop until quit; quit is set in update if AppClose is received from counter while !model.quit { @@ -196,3 +256,12 @@ fn run_tui() -> Result<()> { Ok(()) } + +fn popup_exclusion_clause() -> SubClause { + SubClause::Not(Box::new(SubClause::OrMany(vec![ + SubClause::IsMounted(Id::Menu), + SubClause::IsMounted(Id::ErrorPopup), + SubClause::IsMounted(Id::LoginPopup), + SubClause::IsMounted(Id::DownloadPopup), + ]))) +} diff --git a/coman/src/util/ui.rs b/coman/src/util/ui.rs index d79da1d..d281604 100644 --- a/coman/src/util/ui.rs +++ b/coman/src/util/ui.rs @@ -14,3 +14,12 @@ pub fn draw_area_in_absolute(parent: Rect, padding: u16) -> Rect { ]) .split(new_area[1])[1] } +pub fn draw_area_in_absolute_fixed_height(parent: Rect, padding: u16, height: u16) -> Rect { + let new_area = Layout::vertical([Constraint::Min(1), Constraint::Length(height), Constraint::Min(1)]).split(parent); + Layout::horizontal([ + Constraint::Length(padding), + Constraint::Min(1), + Constraint::Length(padding), + ]) + .split(new_area[1])[1] +} diff --git a/firecrest_client/Cargo.toml b/firecrest_client/Cargo.toml index 82b331f..67f8fe6 100644 --- a/firecrest_client/Cargo.toml +++ b/firecrest_client/Cargo.toml @@ -9,7 +9,7 @@ build = "build.rs" [dependencies] chrono = "0.4.42" eyre = "0.6.12" -oas3-gen-support = "0.9.0" +oas3-gen-support = "0.21.1" regex = "1.12.2" reqwest = { version = "0.12.24", features = ["multipart"] } serde = { version = "1.0.228", features = ["derive"] } @@ -18,10 +18,10 @@ serde_with = { version = "3.15", features = ["chrono"] } thiserror = "2.0.17" validator = { version = "0.20.0", features = ["derive"] } better_default = { version = "1.0" } +anyhow = "1.0.90" [build-dependencies] serde_json = "1.0.145" serde_yaml = "0.9.34" -oas3-gen = "0.9.0" anyhow = "1.0.90" tempfile = "3.23.0" diff --git a/firecrest_client/build.rs b/firecrest_client/build.rs index da6d949..26dbad1 100644 --- a/firecrest_client/build.rs +++ b/firecrest_client/build.rs @@ -14,12 +14,13 @@ fn main() -> Result<()> { let o = std::fs::File::create(outpath)?; serde_json::to_writer_pretty(o, &json_value)?; std::process::Command::new("oas3-gen") + .arg("generate") .arg("-i") .arg(outpath.to_str().unwrap()) .arg("-o") .arg("./src/types.rs") .spawn() - .expect("oas3-gen failed to run, if it's missing please install with 'cargo install oas3-gen'") + .expect("oas3-gen failed to run, if it's missing please install with 'cargo install oas3-gen@0.21.1'") .wait()?; // we need to add an into clause because the defaults in the openapi spec are weird let content = std::fs::read_to_string("./src/types.rs")?; diff --git a/firecrest_client/src/filesystem_api.rs b/firecrest_client/src/filesystem_api.rs index 85cb394..01c566c 100644 --- a/firecrest_client/src/filesystem_api.rs +++ b/firecrest_client/src/filesystem_api.rs @@ -4,21 +4,57 @@ use eyre::{Result, eyre}; use crate::{ client::FirecrestClient, - types::{GetFileTailResponse, PostMakeDirRequest, PostMkdirResponse, PutFileChmodRequest, PutFileChmodResponse}, + types::{ + DownloadFileResponse, DownloadFileResponseTransferDirectives, GetDirectoryLsResponse, GetFileStatResponse, + GetFileTailResponse, PostFileDownloadRequest, PostFileDownloadRequestTransferDirectives, PostFileUploadRequest, + PostMakeDirRequest, PostMkdirResponse, PutFileChmodRequest, PutFileChmodResponse, S3TransferRequest, + S3TransferResponse, UploadFileResponse, + }, }; +pub async fn get_filesystem_ops_ls( + client: &FirecrestClient, + system_name: &str, + path: PathBuf, +) -> Result { + let path = path.as_os_str().to_str().ok_or(eyre!("couldn't cast path to string"))?; + let response = client + .get( + format!("filesystem/{system_name}/ops/ls").as_str(), + Some(vec![("path", path)]), + ) + .await?; + let model: GetDirectoryLsResponse = serde_json::from_str(response.as_str())?; + Ok(model) +} +pub async fn get_filesystem_ops_stat( + client: &FirecrestClient, + system_name: &str, + path: PathBuf, +) -> Result { + let path = path.as_os_str().to_str().ok_or(eyre!("couldn't cast path to string"))?; + let response = client + .get( + format!("filesystem/{system_name}/ops/stat").as_str(), + Some(vec![("path", path)]), + ) + .await?; + let model: GetFileStatResponse = serde_json::from_str(response.as_str())?; + Ok(model) +} + pub async fn post_filesystem_ops_mkdir( client: &FirecrestClient, system_name: &str, path: PathBuf, ) -> Result { + let path = path + .into_os_string() + .into_string() + .map_err(|_| eyre!("couldn't convert path"))?; let body = PostMakeDirRequest { parent: Some(true), - source_path: Some( - path.into_os_string() - .into_string() - .map_err(|_| eyre!("couldn't convert path"))?, - ), + source_path: Some(path), }; let body_json = serde_json::to_string(&body)?; let response = client @@ -99,3 +135,95 @@ pub async fn post_filesystem_ops_upload( .await?; Ok(()) } + +pub async fn post_filesystem_transfer_upload( + client: &FirecrestClient, + system_name: &str, + account: &str, + path: PathBuf, + size: i64, +) -> Result { + let file_path = path.as_os_str().to_str().ok_or(eyre!("couldn't cast path to string"))?; + let body = PostFileUploadRequest { + source_path: Some(file_path.to_owned()), + transfer_directives: PostFileDownloadRequestTransferDirectives::S3(S3TransferRequest { + file_size: Some(size), + ..Default::default() + }), + account: Some(account.to_owned()), + }; + let body_json = serde_json::to_string(&body)?; + let response = client + .post( + format!("filesystem/{system_name}/transfer/upload").as_str(), + body_json, + None, + None, + ) + .await?; + let json_data: serde_json::Value = serde_json::from_str(response.as_str())?; + + let mut model: UploadFileResponse = serde_json::from_str(response.as_str())?; + // deserializing of contained enum does not work properly as the fields are wrong, we do it here manually + let transfer_json = json_data["transferDirectives"].clone(); + let transfer_dir = DownloadFileResponseTransferDirectives::S3(S3TransferResponse { + complete_upload_url: transfer_json["complete_upload_url"].as_str().map(|s| s.to_owned()), + download_url: transfer_json["download_url"].as_str().map(|s| s.to_owned()), + max_part_size: transfer_json["max_part_size"].as_i64(), + parts_upload_urls: transfer_json["parts_upload_urls"] + .as_array() + .map(|v| v.iter().flat_map(|u| u.as_str().map(|s| s.to_owned())).collect()), + transfer_method: "s3".to_owned(), + }); + model.transfer_directives = transfer_dir; + + Ok(model) +} + +pub async fn get_filesystem_ops_download(client: &FirecrestClient, system_name: &str, path: PathBuf) -> Result { + let file_path = path.as_os_str().to_str().ok_or(eyre!("couldn't cast path to string"))?; + let response = client + .get( + format!("filesystem/{system_name}/ops/download").as_str(), + Some(vec![("path", file_path)]), + ) + .await?; + Ok(response.as_str().to_string()) +} + +pub async fn post_filesystem_transfer_download( + client: &FirecrestClient, + system_name: &str, + account: &str, + path: PathBuf, +) -> Result { + let file_path = path.as_os_str().to_str().ok_or(eyre!("couldn't cast path to string"))?; + let body = PostFileDownloadRequest { + source_path: Some(file_path.to_owned()), + transfer_directives: PostFileDownloadRequestTransferDirectives::S3(S3TransferRequest::default()), + account: Some(account.to_owned()), + }; + let body_json = serde_json::to_string(&body)?; + let response = client + .post( + format!("filesystem/{system_name}/transfer/download").as_str(), + body_json, + None, + None, + ) + .await?; + let mut model: DownloadFileResponse = serde_json::from_str(response.as_str())?; + let json_data: serde_json::Value = serde_json::from_str(response.as_str())?; + let transfer_json = json_data["transferDirectives"].clone(); + let transfer_dir = DownloadFileResponseTransferDirectives::S3(S3TransferResponse { + complete_upload_url: transfer_json["complete_upload_url"].as_str().map(|s| s.to_owned()), + download_url: transfer_json["download_url"].as_str().map(|s| s.to_owned()), + max_part_size: transfer_json["max_part_size"].as_i64(), + parts_upload_urls: transfer_json["parts_upload_urls"] + .as_array() + .map(|v| v.iter().flat_map(|u| u.as_str().map(|s| s.to_owned())).collect()), + transfer_method: "s3".to_owned(), + }); + model.transfer_directives = transfer_dir; + Ok(model) +} diff --git a/firecrest_client/src/lib.rs b/firecrest_client/src/lib.rs index cbc74b5..6209427 100644 --- a/firecrest_client/src/lib.rs +++ b/firecrest_client/src/lib.rs @@ -4,4 +4,3 @@ mod error; pub mod filesystem_api; pub mod status_api; pub mod types; -mod util; diff --git a/firecrest_client/src/types.rs b/firecrest_client/src/types.rs index 762e94b..3542b97 100644 --- a/firecrest_client/src/types.rs +++ b/firecrest_client/src/types.rs @@ -1,20 +1,24 @@ // @generated by oas3-gen #![allow(clippy::all)] #![allow(dead_code)] +#![allow(clippy::doc_markdown)] +#![allow(clippy::large_enum_variant)] +#![allow(clippy::missing_panics_doc)] +#![allow(clippy::result_large_err)] +//! //! AUTO-GENERATED CODE - DO NOT EDIT! //! //! FirecREST -//! Source: /tmp/.tmpj8EA0E.json -//! Version: 2.4.0 -//! Generated by `oas3-gen v0.9.0` +//! Source: /tmp/.tmpSZH8Tb.json +//! Version: 2.4.1 +//! Generated by `oas3-gen v0.21.1` //! //! No description provided -#![allow(clippy::large_enum_variant)] use serde::{Deserialize, Serialize}; static REGEX_ATTACH_COMPUTE_SYSTEM_NAME_JOBS_JOB_ID_ATTACH_PUT_REQUEST_JOB_ID: std::sync::LazyLock = std::sync::LazyLock::new(|| regex::Regex::new("^[a-zA-Z0-9]+$").expect("invalid regex")); -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, oas3_gen_support::Default)] pub enum ApResponseErrorType { #[serde(rename = "error")] #[default] @@ -22,56 +26,73 @@ pub enum ApResponseErrorType { #[serde(rename = "validation")] Validation, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct ApiResponseError { pub data: Option, #[serde(rename = "errorType")] - pub error_type: Option, - #[validate(length(min = 1))] + pub error_type: Option, pub message: String, pub user: Option, } +impl std::fmt::Display for ApiResponseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.message) + } +} +impl std::error::Error for ApiResponseError {} ///Attach a procces to a job by `{job_id}` -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct AttachComputeSystemNameJobsJobIdAttachPutRequest { ///Job id - ///## Schema - /// - Location: Path + /// - Location: `Path` #[validate( - length(min = 1), + length(min = 1u64), regex(path = "REGEX_ATTACH_COMPUTE_SYSTEM_NAME_JOBS_JOB_ID_ATTACH_PUT_REQUEST_JOB_ID") )] pub job_id: String, - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: AttachComputeSystemNameJobsJobIdAttachPutRequestBody, } impl AttachComputeSystemNameJobsJobIdAttachPutRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/compute/{}/jobs/{}/attach", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()), - oas3_gen_support::percent_encode_path_segment(&self.job_id.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "compute/{}/jobs/{}/attach", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?), + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.job_id)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let _ = req.bytes().await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::NoContent); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::Unknown) } } pub type AttachComputeSystemNameJobsJobIdAttachPutRequestBody = PostJobAttachRequest; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] pub struct BodyPostUploadFilesystemSystemNameOpsUploadPost { ///File to be uploaded as `multipart/form-data` pub file: Vec, } ///Configuration for automatic object lifecycle in storage buckets. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(default)] pub struct BucketLifecycleConfiguration { ///Number of days after which objects will expire automatically. @@ -79,28 +100,59 @@ pub struct BucketLifecycleConfiguration { pub days: Option, } ///Create compress file or directory operation (`tar`) (for files larger than 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct CompressFilesystemSystemNameTransferCompressPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: CompressFilesystemSystemNameTransferCompressPostRequestBody, } impl CompressFilesystemSystemNameTransferCompressPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/transfer/compress", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/transfer/compress", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(CompressFilesystemSystemNameTransferCompressPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(CompressFilesystemSystemNameTransferCompressPostResponse::ClientError( + data, + )); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(CompressFilesystemSystemNameTransferCompressPostResponse::ServerError( + data, + )); + } + let _ = req.bytes().await?; + Ok(CompressFilesystemSystemNameTransferCompressPostResponse::Unknown) } } pub type CompressFilesystemSystemNameTransferCompressPostRequestBody = CompressRequest; +///Response types for compress_filesystem__system_name__transfer_compress_post +#[derive(Clone, Debug)] +pub enum CompressFilesystemSystemNameTransferCompressPostResponse { + ///201: Compress file or directory operation created successfully + Created(CompressResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] #[serde(default)] @@ -108,7 +160,7 @@ pub struct CompressRequest { ///Name of the account in the scheduler pub account: Option, ///Defines the type of compression to be used. By default gzip is used. - #[default(Some("gzip".to_string().into()))] + #[default(Some(Default::default()))] pub compression: Option, ///If set to `true`, it follows symbolic links and archive the files they point to instead of the links /// themselves. @@ -121,15 +173,15 @@ pub struct CompressRequest { pub source_path: Option, ///Target path of the compress operation #[serde(rename = "targetPath")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub target_path: String, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct CompressResponse { #[serde(rename = "transferJob")] pub transfer_job: FirecrestFilesystemTransferModelsTransferJob, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, oas3_gen_support::Default)] pub enum CompressionType { #[serde(rename = "none")] #[default] @@ -141,7 +193,7 @@ pub enum CompressionType { #[serde(rename = "xz")] Xz, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, oas3_gen_support::Default)] pub enum ContentUnit { #[serde(rename = "lines")] #[default] @@ -162,133 +214,162 @@ pub struct CopyRequest { pub source_path: Option, ///Target path of the copy operation #[serde(rename = "targetPath")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub target_path: String, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct CopyResponse { #[serde(rename = "transferJob")] pub transfer_job: FirecrestFilesystemTransferModelsTransferJob, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] -pub struct DataOperationInput { - ///Data transfer service configuration - pub data_transfer: Option, - ///Maximum file size (in bytes) allowed for direct upload and download. Larger files will go through the staging - /// area. - #[default(Some(5242880i64))] - pub max_ops_file_size: Option, -} -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(default)] -pub struct DataOperationOutput { +pub struct DataOperation { ///Data transfer service configuration - pub data_transfer: Option, + pub data_transfer: Option, ///Maximum file size (in bytes) allowed for direct upload and download. Larger files will go through the staging /// area. #[default(Some(5242880i64))] pub max_ops_file_size: Option, } ///Cancel a job -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct DeleteJobCancelComputeSystemNameJobsJobIdDeleteRequest { ///Job id - ///## Schema - /// - Location: Path + /// - Location: `Path` #[validate( - length(min = 1), + length(min = 1u64), regex(path = "REGEX_ATTACH_COMPUTE_SYSTEM_NAME_JOBS_JOB_ID_ATTACH_PUT_REQUEST_JOB_ID") )] pub job_id: String, - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, } impl DeleteJobCancelComputeSystemNameJobsJobIdDeleteRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/compute/{}/jobs/{}", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()), - oas3_gen_support::percent_encode_path_segment(&self.job_id.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "compute/{}/jobs/{}", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?), + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.job_id)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let _ = req.bytes().await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::NoContent); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::Unknown) } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct DeleteResponse { #[serde(rename = "transferJob")] pub transfer_job: FirecrestFilesystemTransferModelsTransferJob, } ///Delete file or directory operation (`rm`) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct DeleteRmFilesystemSystemNameOpsRmDeleteRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///The path to delete - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, } impl DeleteRmFilesystemSystemNameOpsRmDeleteRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/rm", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/rm", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let _ = req.bytes().await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::NoContent); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::Unknown) } } +///Response types for delete_rm_filesystem__system_name__ops_rm_delete +#[derive(Clone, Debug)] +pub enum DeleteRmFilesystemSystemNameOpsRmDeleteResponse { + ///204: File or directory deleted successfully + NoContent, + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Create remove file or directory operation (`rm`) (for files larger than 5242880 Bytes) -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct DeleteRmFilesystemSystemNameTransferRmDeleteRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///The path to delete - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, - ///## Schema - /// - Location: Query + /// - Location: `Query` pub account: Option, } impl DeleteRmFilesystemSystemNameTransferRmDeleteRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/transfer/rm", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/transfer/rm", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); if let Some(value) = &self.account { @@ -296,55 +377,130 @@ impl DeleteRmFilesystemSystemNameTransferRmDeleteRequest { write!( &mut path, "{prefix}account={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameTransferRmDeleteResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameTransferRmDeleteResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameTransferRmDeleteResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(DeleteRmFilesystemSystemNameTransferRmDeleteResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for delete_rm_filesystem__system_name__transfer_rm_delete +#[derive(Clone, Debug)] +pub enum DeleteRmFilesystemSystemNameTransferRmDeleteResponse { + ///200: Remove file or directory operation created successfully + Ok(DeleteResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct DownloadFileResponse { - ///Provide method specific transfer directives + ///Data transfer parameters specific to the transfer method #[serde(rename = "transferDirectives")] - pub transfer_directives: Option, + pub transfer_directives: DownloadFileResponseTransferDirectives, #[serde(rename = "transferJob")] pub transfer_job: FirecrestFilesystemTransferModelsTransferJob, } -///Provide method specific transfer directives -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] -#[serde(tag = "transferMethod")] +///Data transfer parameters specific to the transfer method +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +#[serde(untagged)] pub enum DownloadFileResponseTransferDirectives { - #[serde(rename = "s3")] #[default] - S3DataTransferDirective(S3DataTransferDirective), - #[serde(rename = "wormhole")] - WormholeDataTransferDirective(WormholeDataTransferDirective), + Wormhole(WormholeTransferResponse), + S3(S3TransferResponse), + Streamer(StreamerTransferResponse), +} +impl DownloadFileResponseTransferDirectives { + ///Creates a `Wormhole` variant with default values. + pub fn wormhole() -> Self { + Self::Wormhole(WormholeTransferResponse::default()) + } + ///Creates a `S3` variant with default values. + pub fn s3() -> Self { + Self::S3(S3TransferResponse::default()) + } + ///Creates a `Streamer` variant with default values. + pub fn streamer() -> Self { + Self::Streamer(StreamerTransferResponse::default()) + } } ///Create extract file operation (`tar`) (for files larger than 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct ExtractFilesystemSystemNameTransferExtractPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: ExtractFilesystemSystemNameTransferExtractPostRequestBody, } impl ExtractFilesystemSystemNameTransferExtractPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/transfer/extract", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/transfer/extract", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(ExtractFilesystemSystemNameTransferExtractPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(ExtractFilesystemSystemNameTransferExtractPostResponse::ClientError( + data, + )); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(ExtractFilesystemSystemNameTransferExtractPostResponse::ServerError( + data, + )); + } + let _ = req.bytes().await?; + Ok(ExtractFilesystemSystemNameTransferExtractPostResponse::Unknown) } } pub type ExtractFilesystemSystemNameTransferExtractPostRequestBody = ExtractRequest; +///Response types for extract_filesystem__system_name__transfer_extract_post +#[derive(Clone, Debug)] +pub enum ExtractFilesystemSystemNameTransferExtractPostResponse { + ///201: Extract file or directory operation created successfully + Created(ExtractResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] #[serde(default)] @@ -352,63 +508,52 @@ pub struct ExtractRequest { ///Name of the account in the scheduler pub account: Option, ///Defines the type of compression to be used. By default gzip is used. - #[default(Some("gzip".to_string().into()))] + #[default(Some(Default::default()))] pub compression: Option, #[serde(rename = "sourcePath")] pub source_path: Option, ///Path to the directory where to extract the compressed file #[serde(rename = "targetPath")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub target_path: String, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct ExtractResponse { #[serde(rename = "transferJob")] pub transfer_job: FirecrestFilesystemTransferModelsTransferJob, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct File { - #[validate(length(min = 1))] pub group: String, #[serde(rename = "lastModified")] - #[validate(length(min = 1))] pub last_modified: String, #[serde(rename = "linkTarget")] pub link_target: Option, - #[validate(length(min = 1))] pub name: String, - #[validate(length(min = 1))] pub permissions: String, - #[validate(length(min = 1))] pub size: String, #[serde(rename = "type")] - #[validate(length(min = 1))] pub r#type: String, - #[validate(length(min = 1))] pub user: String, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(default)] pub struct FileChecksum { #[default(Some("SHA-256".to_string()))] pub algorithm: Option, - #[validate(length(min = 1))] pub checksum: String, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct FileContent { - #[validate(length(min = 1))] pub content: String, #[serde(rename = "contentType")] - pub content_type: ContentUnit, + pub content_type: String, #[serde(rename = "endPosition")] pub end_position: i64, #[serde(rename = "startPosition")] pub start_position: i64, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct FileStat { pub atime: i64, pub ctime: i64, @@ -422,22 +567,21 @@ pub struct FileStat { pub uid: i64, } ///Defines a cluster file system and its type. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +#[serde(default)] pub struct FileSystem { ///Data types for cluster file systems. #[serde(rename = "dataType")] - pub data_type: FileSystemDataType, + pub data_type: String, ///Mark this as the default working directory. #[serde(rename = "defaultWorkDir")] #[default(Some(false))] pub default_work_dir: Option, ///Mount path for the file system. - #[validate(length(min = 1))] pub path: String, } ///Data types for cluster file systems. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, oas3_gen_support::Default)] pub enum FileSystemDataType { #[serde(rename = "users")] #[default] @@ -456,6 +600,7 @@ pub enum FileSystemDataType { ///Health check for a mounted file system. #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[serde(default)] pub struct FilesystemServiceHealth { ///True if the service is healthy. #[default(Some(false))] @@ -471,192 +616,270 @@ pub struct FilesystemServiceHealth { pub path: Option, ///Types of services that can be health-checked. #[serde(rename = "serviceType")] - pub service_type: HealthCheckType, + pub service_type: String, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct FirecrestFilesystemTransferModelsTransferJob { #[serde(rename = "jobId")] pub job_id: i64, - pub logs: LibDatatransfersDatatransferBaseTransferJobLogs, - #[validate(length(min = 1))] + pub logs: FirecrestFilesystemTransferModelsTransferJobLogs, pub system: String, #[serde(rename = "workingDirectory")] - #[validate(length(min = 1))] pub working_directory: String, } +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +pub struct FirecrestFilesystemTransferModelsTransferJobLogs { + #[serde(rename = "errorLog")] + pub error_log: String, + #[serde(rename = "outputLog")] + pub output_log: String, +} ///Output the checksum of a file (using SHA-256 algotithm) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetChecksumFilesystemSystemNameOpsChecksumGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///Target system - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, } impl GetChecksumFilesystemSystemNameOpsChecksumGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/checksum", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/checksum", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetChecksumFilesystemSystemNameOpsChecksumGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetChecksumFilesystemSystemNameOpsChecksumGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetChecksumFilesystemSystemNameOpsChecksumGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetChecksumFilesystemSystemNameOpsChecksumGetResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_checksum_filesystem__system_name__ops_checksum_get +#[derive(Clone, Debug)] +pub enum GetChecksumFilesystemSystemNameOpsChecksumGetResponse { + ///200: Checksum returned successfully + Ok(GetFileChecksumResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetDirectoryLsResponse { pub output: Option>, } ///Download a small file (max 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetDownloadFilesystemSystemNameOpsDownloadGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///A file to download - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, } impl GetDownloadFilesystemSystemNameOpsDownloadGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/download", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/download", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let _ = req.bytes().await?; + return Ok(GetDownloadFilesystemSystemNameOpsDownloadGetResponse::Ok); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetDownloadFilesystemSystemNameOpsDownloadGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetDownloadFilesystemSystemNameOpsDownloadGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetDownloadFilesystemSystemNameOpsDownloadGetResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_download_filesystem__system_name__ops_download_get +#[derive(Clone, Debug)] +pub enum GetDownloadFilesystemSystemNameOpsDownloadGetResponse { + ///200: File downloaded successfully + Ok, + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetFileChecksumResponse { pub output: Option, } ///Output the type of a file or directory -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetFileFilesystemSystemNameOpsFileGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///A file or folder path - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, } impl GetFileFilesystemSystemNameOpsFileGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/file", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/file", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetFileFilesystemSystemNameOpsFileGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetFileFilesystemSystemNameOpsFileGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetFileFilesystemSystemNameOpsFileGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetFileFilesystemSystemNameOpsFileGetResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_file_filesystem__system_name__ops_file_get +#[derive(Clone, Debug)] +pub enum GetFileFilesystemSystemNameOpsFileGetResponse { + ///200: Type returned successfully + Ok(GetFileTypeResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetFileHeadResponse { pub output: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetFileStatResponse { pub output: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetFileTailResponse { pub output: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetFileTypeResponse { pub output: Option, } ///Output the first part of file/s (`head`) -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetHeadFilesystemSystemNameOpsHeadGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///File path - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, ///The output will be the first NUM bytes of each file. - ///## Schema - /// - Location: Query + /// - Location: `Query` pub bytes: Option, ///The output will be the first NUM lines of each file. - ///## Schema - /// - Location: Query + /// - Location: `Query` pub lines: Option, ///The output will be the whole file, without the last NUM bytes/lines of each file. NUM should be specified in - /// the respective argument through `bytes` or `lines`. ## Schema - /// - Location: Query - #[serde(rename = "skipTrailing")] + /// the respective argument through `bytes` or `lines`. + /// - Location: `Query` #[default(Some(false))] pub skip_trailing: Option, } impl GetHeadFilesystemSystemNameOpsHeadGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/head", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/head", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); if let Some(value) = &self.bytes { @@ -664,7 +887,7 @@ impl GetHeadFilesystemSystemNameOpsHeadGetRequest { write!( &mut path, "{prefix}bytes={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -673,7 +896,7 @@ impl GetHeadFilesystemSystemNameOpsHeadGetRequest { write!( &mut path, "{prefix}lines={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -682,100 +905,169 @@ impl GetHeadFilesystemSystemNameOpsHeadGetRequest { write!( &mut path, "{prefix}skipTrailing={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetHeadFilesystemSystemNameOpsHeadGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetHeadFilesystemSystemNameOpsHeadGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetHeadFilesystemSystemNameOpsHeadGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetHeadFilesystemSystemNameOpsHeadGetResponse::Unknown) } } +///Response types for get_head_filesystem__system_name__ops_head_get +#[derive(Clone, Debug)] +pub enum GetHeadFilesystemSystemNameOpsHeadGetResponse { + ///200: Head operation finished successfully + Ok(GetFileHeadResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Get status of a job by `{job_id}` -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetJobComputeSystemNameJobsJobIdGetRequest { ///Job id - ///## Schema - /// - Location: Path + /// - Location: `Path` #[validate( - length(min = 1), + length(min = 1u64), regex(path = "REGEX_ATTACH_COMPUTE_SYSTEM_NAME_JOBS_JOB_ID_ATTACH_PUT_REQUEST_JOB_ID") )] pub job_id: String, - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, } impl GetJobComputeSystemNameJobsJobIdGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/compute/{}/jobs/{}", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()), - oas3_gen_support::percent_encode_path_segment(&self.job_id.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "compute/{}/jobs/{}", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?), + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.job_id)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response(req: reqwest::Response) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobsComputeSystemNameJobsGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobsComputeSystemNameJobsGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobsComputeSystemNameJobsGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetJobsComputeSystemNameJobsGetResponse::Unknown) } } ///Get metadata of a job by `{job_id}` -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetJobMetadataComputeSystemNameJobsJobIdMetadataGetRequest { ///Job id - ///## Schema - /// - Location: Path + /// - Location: `Path` #[validate( - length(min = 1), + length(min = 1u64), regex(path = "REGEX_ATTACH_COMPUTE_SYSTEM_NAME_JOBS_JOB_ID_ATTACH_PUT_REQUEST_JOB_ID") )] pub job_id: String, - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, } impl GetJobMetadataComputeSystemNameJobsJobIdMetadataGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/compute/{}/jobs/{}/metadata", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()), - oas3_gen_support::percent_encode_path_segment(&self.job_id.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "compute/{}/jobs/{}/metadata", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?), + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.job_id)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobMetadataComputeSystemNameJobsJobIdMetadataGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobMetadataComputeSystemNameJobsJobIdMetadataGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobMetadataComputeSystemNameJobsJobIdMetadataGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetJobMetadataComputeSystemNameJobsJobIdMetadataGetResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_job_metadata_compute__system_name__jobs__job_id__metadata_get +#[derive(Clone, Debug)] +pub enum GetJobMetadataComputeSystemNameJobsJobIdMetadataGetResponse { + ///200: Jobs metadata returned successfully + Ok(GetJobMetadataResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetJobMetadataResponse { pub jobs: Option>, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetJobResponse { - pub jobs: Option>, + pub jobs: Option>, } ///Get status of all jobs -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetJobsComputeSystemNameJobsGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///If set to `true` returns all jobs visible by the current user, otherwise only the current user owned jobs - ///## Schema - /// - Location: Query + /// - Location: `Query` #[default(Some(false))] pub allusers: Option, } impl GetJobsComputeSystemNameJobsGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/compute/{}/jobs", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "compute/{}/jobs", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; if let Some(value) = &self.allusers { @@ -783,73 +1075,130 @@ impl GetJobsComputeSystemNameJobsGetRequest { write!( &mut path, "{prefix}allusers={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response(req: reqwest::Response) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobsComputeSystemNameJobsGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobsComputeSystemNameJobsGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetJobsComputeSystemNameJobsGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetJobsComputeSystemNameJobsGetResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_jobs_compute__system_name__jobs_get +#[derive(Clone, Debug)] +pub enum GetJobsComputeSystemNameJobsGetResponse { + ///200: Jobs status returned successfully + Ok(GetJobResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetLiveness { #[serde(rename = "healthcheckRuns")] pub healthcheck_runs: Option, #[serde(rename = "lastUpdate")] pub last_update: Option, } +///Get liveness status of FirecREST +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] +pub struct GetLivenessStatusLivenessGetRequest {} +impl GetLivenessStatusLivenessGetRequest { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok("status/liveness/".to_string()) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response(req: reqwest::Response) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetLivenessStatusLivenessGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetLivenessStatusLivenessGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetLivenessStatusLivenessGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetLivenessStatusLivenessGetResponse::Unknown) + } +} +///Response types for get_liveness_status_liveness__get +#[derive(Clone, Debug)] +pub enum GetLivenessStatusLivenessGetResponse { + ///200: Liveness status returned successfully + Ok(GetLiveness), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///List the contents of the given directory (`ls`) -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetLsFilesystemSystemNameOpsLsGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///The path to list - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, ///Show hidden files - ///## Schema - /// - Location: Query - #[serde(rename = "showHidden")] + /// - Location: `Query` #[default(Some(false))] pub show_hidden: Option, ///List numeric user and group IDs - ///## Schema - /// - Location: Query - #[serde(rename = "numericUid")] + /// - Location: `Query` #[default(Some(false))] pub numeric_uid: Option, ///Recursively list files and folders - ///## Schema - /// - Location: Query + /// - Location: `Query` #[default(Some(false))] pub recursive: Option, ///Show information for the file the link references. - ///## Schema - /// - Location: Query + /// - Location: `Query` #[default(Some(false))] pub dereference: Option, } impl GetLsFilesystemSystemNameOpsLsGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/ls", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/ls", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); if let Some(value) = &self.show_hidden { @@ -857,7 +1206,7 @@ impl GetLsFilesystemSystemNameOpsLsGetRequest { write!( &mut path, "{prefix}showHidden={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -866,7 +1215,7 @@ impl GetLsFilesystemSystemNameOpsLsGetRequest { write!( &mut path, "{prefix}numericUid={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -875,7 +1224,7 @@ impl GetLsFilesystemSystemNameOpsLsGetRequest { write!( &mut path, "{prefix}recursive={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -884,60 +1233,84 @@ impl GetLsFilesystemSystemNameOpsLsGetRequest { write!( &mut path, "{prefix}dereference={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response(req: reqwest::Response) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetLsFilesystemSystemNameOpsLsGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetLsFilesystemSystemNameOpsLsGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetLsFilesystemSystemNameOpsLsGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetLsFilesystemSystemNameOpsLsGetResponse::Unknown) } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_ls_filesystem__system_name__ops_ls_get +#[derive(Clone, Debug)] +pub enum GetLsFilesystemSystemNameOpsLsGetResponse { + ///200: Directory listed successfully + Ok(GetDirectoryLsResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetNodesResponse { pub nodes: Vec, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetPartitionsResponse { pub partitions: Vec, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetReservationsResponse { pub reservations: Vec, } ///Output the `stat` of a file -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetStatFilesystemSystemNameOpsStatGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///A file or folder path - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, ///Follow symbolic links - ///## Schema - /// - Location: Query + /// - Location: `Query` #[default(Some(false))] pub dereference: Option, } impl GetStatFilesystemSystemNameOpsStatGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/stat", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/stat", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); if let Some(value) = &self.dereference { @@ -945,118 +1318,274 @@ impl GetStatFilesystemSystemNameOpsStatGetRequest { write!( &mut path, "{prefix}dereference={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetStatFilesystemSystemNameOpsStatGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetStatFilesystemSystemNameOpsStatGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetStatFilesystemSystemNameOpsStatGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetStatFilesystemSystemNameOpsStatGetResponse::Unknown) } } +///Response types for get_stat_filesystem__system_name__ops_stat_get +#[derive(Clone, Debug)] +pub enum GetStatFilesystemSystemNameOpsStatGetResponse { + ///200: Stat returned successfully + Ok(GetFileStatResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Get the list of nodes of a `{system_name}` -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetSystemNodesStatusSystemNameNodesGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, } impl GetSystemNodesStatusSystemNameNodesGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/status/{}/nodes", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "status/{}/nodes", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemNodesStatusSystemNameNodesGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemNodesStatusSystemNameNodesGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemNodesStatusSystemNameNodesGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetSystemNodesStatusSystemNameNodesGetResponse::Unknown) } } +///Response types for get_system_nodes_status__system_name__nodes_get +#[derive(Clone, Debug)] +pub enum GetSystemNodesStatusSystemNameNodesGetResponse { + ///200: Nodes list returned successfully + Ok(GetNodesResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Get the list of partitions of a `{system_name}` -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetSystemPartitionsStatusSystemNamePartitionsGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, } impl GetSystemPartitionsStatusSystemNamePartitionsGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/status/{}/partitions", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "status/{}/partitions", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemPartitionsStatusSystemNamePartitionsGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemPartitionsStatusSystemNamePartitionsGetResponse::ClientError( + data, + )); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemPartitionsStatusSystemNamePartitionsGetResponse::ServerError( + data, + )); + } + let _ = req.bytes().await?; + Ok(GetSystemPartitionsStatusSystemNamePartitionsGetResponse::Unknown) } } +///Response types for get_system_partitions_status__system_name__partitions_get +#[derive(Clone, Debug)] +pub enum GetSystemPartitionsStatusSystemNamePartitionsGetResponse { + ///200: Partitions list returned successfully + Ok(GetPartitionsResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Get the list of reservations of a `{system_name}` -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetSystemReservationsStatusSystemNameReservationsGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, } impl GetSystemReservationsStatusSystemNameReservationsGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/status/{}/reservations", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "status/{}/reservations", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemReservationsStatusSystemNameReservationsGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemReservationsStatusSystemNameReservationsGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemReservationsStatusSystemNameReservationsGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetSystemReservationsStatusSystemNameReservationsGetResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_system_reservations_status__system_name__reservations_get +#[derive(Clone, Debug)] +pub enum GetSystemReservationsStatusSystemNameReservationsGetResponse { + ///200: Reservations list returned successfully + Ok(GetReservationsResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetSystemsResponse { #[serde(rename = "dataOperation")] - pub data_operation: Option, - pub systems: Vec, + pub data_operation: Option, + pub systems: Vec, +} +///Get the list of systems and health status +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] +pub struct GetSystemsStatusSystemsGetRequest {} +impl GetSystemsStatusSystemsGetRequest { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok("status/systems".to_string()) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response(req: reqwest::Response) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemsStatusSystemsGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemsStatusSystemsGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetSystemsStatusSystemsGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetSystemsStatusSystemsGetResponse::Unknown) + } +} +///Response types for get_systems_status_systems_get +#[derive(Clone, Debug)] +pub enum GetSystemsStatusSystemsGetResponse { + ///200: System list returned successfully + Ok(GetSystemsResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, } ///Output the last part of a file (`tail`) -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetTailFilesystemSystemNameOpsTailGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///File path - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, ///The output will be the last NUM bytes of each file. - ///## Schema - /// - Location: Query + /// - Location: `Query` pub bytes: Option, ///The output will be the last NUM lines of each file. - ///## Schema - /// - Location: Query + /// - Location: `Query` pub lines: Option, ///The output will be the whole file, without the first NUM bytes/lines of each file. NUM should be specified in - /// the respective argument through `bytes` or `lines`. ## Schema - /// - Location: Query - #[serde(rename = "skipHeading")] + /// the respective argument through `bytes` or `lines`. + /// - Location: `Query` #[default(Some(false))] pub skip_heading: Option, } impl GetTailFilesystemSystemNameOpsTailGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/tail", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/tail", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); if let Some(value) = &self.bytes { @@ -1064,7 +1593,7 @@ impl GetTailFilesystemSystemNameOpsTailGetRequest { write!( &mut path, "{prefix}bytes={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -1073,7 +1602,7 @@ impl GetTailFilesystemSystemNameOpsTailGetRequest { write!( &mut path, "{prefix}lines={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -1082,76 +1611,130 @@ impl GetTailFilesystemSystemNameOpsTailGetRequest { write!( &mut path, "{prefix}skipHeading={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetTailFilesystemSystemNameOpsTailGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetTailFilesystemSystemNameOpsTailGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetTailFilesystemSystemNameOpsTailGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetTailFilesystemSystemNameOpsTailGetResponse::Unknown) } } +///Response types for get_tail_filesystem__system_name__ops_tail_get +#[derive(Clone, Debug)] +pub enum GetTailFilesystemSystemNameOpsTailGetResponse { + ///200: `tail` operation finished successfully + Ok(GetFileTailResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Get current user information on a `{system_name}` -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetUserinfoStatusSystemNameUserinfoGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, } impl GetUserinfoStatusSystemNameUserinfoGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/status/{}/userinfo", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "status/{}/userinfo", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetUserinfoStatusSystemNameUserinfoGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetUserinfoStatusSystemNameUserinfoGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetUserinfoStatusSystemNameUserinfoGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetUserinfoStatusSystemNameUserinfoGetResponse::Unknown) } } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for get_userinfo_status__system_name__userinfo_get +#[derive(Clone, Debug)] +pub enum GetUserinfoStatusSystemNameUserinfoGetResponse { + ///200: User information returned successfully + Ok(UserInfoResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct GetViewFileResponse { pub output: Option, } ///View file content (up to max 5242880 bytes) -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct GetViewFilesystemSystemNameOpsViewGetRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///File path - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, ///Value, in bytes, of the size of data to be retrieved from the file. - ///## Schema - /// - Location: Query + /// - Location: `Query` #[default(Some(5242880i64))] pub size: Option, ///Value in bytes of the offset. - ///## Schema - /// - Location: Query + /// - Location: `Query` #[default(Some(0i64))] pub offset: Option, } impl GetViewFilesystemSystemNameOpsViewGetRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/view", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/view", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); if let Some(value) = &self.size { @@ -1159,7 +1742,7 @@ impl GetViewFilesystemSystemNameOpsViewGetRequest { write!( &mut path, "{prefix}size={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } @@ -1168,16 +1751,72 @@ impl GetViewFilesystemSystemNameOpsViewGetRequest { write!( &mut path, "{prefix}offset={}", - oas3_gen_support::percent_encode_query_component(&value.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(value)?) ) .unwrap(); } - path + Ok(path) } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetViewFilesystemSystemNameOpsViewGetResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetViewFilesystemSystemNameOpsViewGetResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(GetViewFilesystemSystemNameOpsViewGetResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(GetViewFilesystemSystemNameOpsViewGetResponse::Unknown) + } +} +///Response types for get_view_filesystem__system_name__ops_view_get +#[derive(Clone, Debug)] +pub enum GetViewFilesystemSystemNameOpsViewGetResponse { + ///200: View operation finished successfully + Ok(GetViewFileResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +///Definition of an HPC cluster, including SSH access, scheduling, and +///filesystem layout. More info in +///[the systems' section](../arch/systems//README.md). +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +pub struct HPCCluster { + ///Custom scheduler flags passed to data transfer jobs (e.g. `-pxfer` for a dedicated partition). + #[serde(rename = "datatransferJobsDirectives")] + pub datatransfer_jobs_directives: Option>, + ///List of mounted file systems on the cluster, such as scratch or home directories. + #[serde(rename = "fileSystems")] + pub file_systems: Option>, + ///Unique name for the cluster. This field is case insensitive. + pub name: String, + ///Probing configuration for monitoring the cluster. + pub probing: Option, + ///Cluster job scheduler configuration. + pub scheduler: Scheduler, + ///Optional health information for different services in the cluster. + #[serde(rename = "servicesHealth")] + pub services_health: Option>, + ///SSH connection pool configuration for remote execution. + pub ssh: SSHClientPool, } ///Generic health check error placeholder. #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[serde(default)] pub struct HealthCheckException { ///True if the service is healthy. #[default(Some(false))] @@ -1191,10 +1830,10 @@ pub struct HealthCheckException { pub message: Option, ///Types of services that can be health-checked. #[serde(rename = "serviceType")] - pub service_type: HealthCheckType, + pub service_type: String, } ///Types of services that can be health-checked. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, oas3_gen_support::Default)] pub enum HealthCheckType { #[serde(rename = "scheduler")] #[default] @@ -1208,61 +1847,8 @@ pub enum HealthCheckType { #[serde(rename = "exception")] Exception, } -///Definition of an HPC cluster, including SSH access, scheduling, and -///filesystem layout. More info in -///[the systems' section](../arch/systems//README.md). #[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct HpcclusterInput { - ///Custom scheduler flags passed to data transfer jobs (e.g. `-pxfer` for a dedicated partition). - #[serde(rename = "datatransferJobsDirectives")] - pub datatransfer_jobs_directives: Option>, - ///List of mounted file systems on the cluster, such as scratch or home directories. - #[serde(rename = "fileSystems")] - pub file_systems: Option>, - ///Unique name for the cluster. This field is case insensitive. - #[validate(length(min = 1))] - pub name: String, - ///Cluster monitoring attributes. - pub probing: Probing, - ///Cluster job scheduler configuration. - pub scheduler: Scheduler, - ///Internal service account credentials. - #[serde(rename = "serviceAccount")] - pub service_account: ServiceAccount, - ///Optional health information for different services in the cluster. - #[serde(rename = "servicesHealth")] - pub services_health: Option>, - ///SSH connection pool configuration for remote execution. - pub ssh: SshclientPool, -} -///Definition of an HPC cluster, including SSH access, scheduling, and -///filesystem layout. More info in -///[the systems' section](../arch/systems//README.md). -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct HpcclusterOutput { - ///Custom scheduler flags passed to data transfer jobs (e.g. `-pxfer` for a dedicated partition). - #[serde(rename = "datatransferJobsDirectives")] - pub datatransfer_jobs_directives: Option>, - ///List of mounted file systems on the cluster, such as scratch or home directories. - #[serde(rename = "fileSystems")] - pub file_systems: Option>, - ///Unique name for the cluster. This field is case insensitive. - #[validate(length(min = 1))] - pub name: String, - ///Cluster monitoring attributes. - pub probing: Probing, - ///Cluster job scheduler configuration. - pub scheduler: Scheduler, - ///Optional health information for different services in the cluster. - #[serde(rename = "servicesHealth")] - pub services_health: Option>, - ///SSH connection pool configuration for remote execution. - pub ssh: SshclientPool, -} -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] #[serde(default)] pub struct JobDescriptionModel { ///Charge job resources to specified account @@ -1290,22 +1876,20 @@ pub struct JobDescriptionModel { pub standard_output: Option, ///Job working directory #[serde(rename = "workingDirectory")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub working_directory: String, } ///Dictionary of environment variables to set in the job context -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Serialize, oas3_gen_support::Default)] #[serde(untagged)] pub enum JobDescriptionModelEnv { #[default] Object(serde_json::Value), Array(Vec), } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct JobMetadataModel { #[serde(rename = "jobId")] - #[validate(length(min = 1))] pub job_id: String, pub script: Option, #[serde(rename = "standardError")] @@ -1315,52 +1899,19 @@ pub struct JobMetadataModel { #[serde(rename = "standardOutput")] pub standard_output: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct JobModelInput { - pub account: Option, - #[serde(rename = "allocationNodes")] - pub allocation_nodes: i64, - #[validate(length(min = 1))] - pub cluster: String, - pub group: Option, - #[serde(rename = "jobId")] - pub job_id: i64, - #[serde(rename = "killRequestUser")] - pub kill_request_user: Option, - #[validate(length(min = 1))] - pub name: String, - #[validate(length(min = 1))] - pub nodes: String, - #[validate(length(min = 1))] - pub partition: String, - pub priority: Option, - pub status: JobStatus, - pub tasks: Option>, - pub time: JobTime, - pub user: Option, - #[serde(rename = "workingDirectory")] - #[validate(length(min = 1))] - pub working_directory: String, -} -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct JobModelOutput { +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +pub struct JobModel { pub account: Option, #[serde(rename = "allocationNodes")] pub allocation_nodes: i64, - #[validate(length(min = 1))] pub cluster: String, pub group: Option, #[serde(rename = "jobId")] pub job_id: i64, #[serde(rename = "killRequestUser")] pub kill_request_user: Option, - #[validate(length(min = 1))] pub name: String, - #[validate(length(min = 1))] pub nodes: String, - #[validate(length(min = 1))] pub partition: String, pub priority: Option, pub status: JobStatus, @@ -1368,32 +1919,26 @@ pub struct JobModelOutput { pub time: JobTime, pub user: Option, #[serde(rename = "workingDirectory")] - #[validate(length(min = 1))] pub working_directory: String, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct JobStatus { #[serde(rename = "exitCode")] pub exit_code: Option, #[serde(rename = "interruptSignal")] pub interrupt_signal: Option, - #[validate(length(min = 1))] pub state: String, #[serde(rename = "stateReason")] pub state_reason: Option, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct JobTask { - #[validate(length(min = 1))] pub id: String, - #[validate(length(min = 1))] pub name: String, pub status: JobStatus, pub time: JobTime, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct JobTime { pub elapsed: Option, pub end: Option, @@ -1401,38 +1946,56 @@ pub struct JobTime { pub start: Option, pub suspended: Option, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct LibDatatransfersDatatransferBaseTransferJobLogs { - #[serde(rename = "errorLog")] - #[validate(length(min = 1))] - pub error_log: String, - #[serde(rename = "outputLog")] - #[validate(length(min = 1))] - pub output_log: String, -} ///Create move file or directory operation (`mv`) (for files larger than 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct MoveMvFilesystemSystemNameTransferMvPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: MoveMvFilesystemSystemNameTransferMvPostRequestBody, } impl MoveMvFilesystemSystemNameTransferMvPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/transfer/mv", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/transfer/mv", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(MoveMvFilesystemSystemNameTransferMvPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(MoveMvFilesystemSystemNameTransferMvPostResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(MoveMvFilesystemSystemNameTransferMvPostResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(MoveMvFilesystemSystemNameTransferMvPostResponse::Unknown) } } pub type MoveMvFilesystemSystemNameTransferMvPostRequestBody = MoveRequest; +///Response types for move_mv_filesystem__system_name__transfer_mv_post +#[derive(Clone, Debug)] +pub enum MoveMvFilesystemSystemNameTransferMvPostResponse { + ///201: Move file or directory operation created successfully + Created(MoveResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] pub struct MoveRequest { @@ -1442,17 +2005,16 @@ pub struct MoveRequest { pub source_path: Option, ///Target path of the move operation #[serde(rename = "targetPath")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub target_path: String, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct MoveResponse { #[serde(rename = "transferJob")] pub transfer_job: FirecrestFilesystemTransferModelsTransferJob, } ///Configuration for multipart upload behavior. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(default)] pub struct MultipartUpload { ///Maximum size (in bytes) for multipart data transfers. Default is 2 GB. @@ -1468,8 +2030,7 @@ pub struct MultipartUpload { #[default(Some(false))] pub use_split: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct NodeModel { pub address: Option, #[serde(rename = "allocCpus")] @@ -1486,7 +2047,6 @@ pub struct NodeModel { pub hostname: Option, #[serde(rename = "idleCpus")] pub idle_cpus: Option, - #[validate(length(min = 1))] pub name: String, pub partitions: Option>, pub sockets: Option, @@ -1494,64 +2054,75 @@ pub struct NodeModel { pub threads: Option, pub weight: Option, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(untagged)] pub enum NodeModelFeatures { #[default] String(String), Array(Vec), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(untagged)] pub enum NodeModelState { #[default] String(String), Array(Vec), } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct PartitionModel { pub cpus: Option, - #[validate(length(min = 1))] pub name: String, pub partition: PartitionModelPartition, #[serde(rename = "totalNodes")] pub total_nodes: Option, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(untagged)] pub enum PartitionModelPartition { #[default] String(String), Array(Vec), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct PosixIdentified { - #[validate(length(min = 1))] pub id: String, - #[validate(length(min = 1))] pub name: String, } ///Compress files and directories using `tar` command -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostCompressFilesystemSystemNameOpsCompressPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostCompressFilesystemSystemNameOpsCompressPostRequestBody, } impl PostCompressFilesystemSystemNameOpsCompressPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/ops/compress", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/ops/compress", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let _ = req.bytes().await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::NoContent); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::Unknown) } } pub type PostCompressFilesystemSystemNameOpsCompressPostRequestBody = PostCompressRequest; @@ -1560,7 +2131,7 @@ pub type PostCompressFilesystemSystemNameOpsCompressPostRequestBody = PostCompre #[serde(default)] pub struct PostCompressRequest { ///Defines the type of compression to be used. By default gzip is used. - #[default(Some("gzip".to_string().into()))] + #[default(Some(Default::default()))] pub compression: Option, ///If set to `true`, it follows symbolic links and archive the files they point to instead of the links /// themselves. @@ -1573,75 +2144,146 @@ pub struct PostCompressRequest { pub source_path: Option, ///Path to the compressed file #[serde(rename = "targetPath")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub target_path: String, } ///Create copy file or directory operation (`cp`) (for files larger than 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostCpFilesystemSystemNameTransferCpPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostCpFilesystemSystemNameTransferCpPostRequestBody, } impl PostCpFilesystemSystemNameTransferCpPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/transfer/cp", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/transfer/cp", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostCpFilesystemSystemNameTransferCpPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostCpFilesystemSystemNameTransferCpPostResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostCpFilesystemSystemNameTransferCpPostResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(PostCpFilesystemSystemNameTransferCpPostResponse::Unknown) } } pub type PostCpFilesystemSystemNameTransferCpPostRequestBody = CopyRequest; +///Response types for post_cp_filesystem__system_name__transfer_cp_post +#[derive(Clone, Debug)] +pub enum PostCpFilesystemSystemNameTransferCpPostResponse { + ///201: Copy file or directory operation created successfully + Created(CopyResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Create asynchronous download operation (for files larger than 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostDownloadFilesystemSystemNameTransferDownloadPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostDownloadFilesystemSystemNameTransferDownloadPostRequestBody, } impl PostDownloadFilesystemSystemNameTransferDownloadPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/transfer/download", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/transfer/download", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostDownloadFilesystemSystemNameTransferDownloadPostResponse::Created( + data, + )); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostDownloadFilesystemSystemNameTransferDownloadPostResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostDownloadFilesystemSystemNameTransferDownloadPostResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(PostDownloadFilesystemSystemNameTransferDownloadPostResponse::Unknown) } } pub type PostDownloadFilesystemSystemNameTransferDownloadPostRequestBody = PostFileDownloadRequest; +///Response types for post_download_filesystem__system_name__transfer_download_post +#[derive(Clone, Debug)] +pub enum PostDownloadFilesystemSystemNameTransferDownloadPostResponse { + ///201: Download operation created successfully + Created(DownloadFileResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Extract `tar` `gzip` archives -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostExtractFilesystemSystemNameOpsExtractPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostExtractFilesystemSystemNameOpsExtractPostRequestBody, } impl PostExtractFilesystemSystemNameOpsExtractPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/ops/extract", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/ops/extract", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let _ = req.bytes().await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::NoContent); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::Unknown) } } pub type PostExtractFilesystemSystemNameOpsExtractPostRequestBody = PostExtractRequest; @@ -1650,13 +2292,13 @@ pub type PostExtractFilesystemSystemNameOpsExtractPostRequestBody = PostExtractR #[serde(default)] pub struct PostExtractRequest { ///Defines the type of compression to be used. By default gzip is used. - #[default(Some("gzip".to_string().into()))] + #[default(Some(Default::default()))] pub compression: Option, #[serde(rename = "sourcePath")] pub source_path: Option, ///Path to the directory where to extract the compressed file #[serde(rename = "targetPath")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub target_path: String, } #[oas3_gen_support::skip_serializing_none] @@ -1666,19 +2308,44 @@ pub struct PostFileDownloadRequest { pub account: Option, #[serde(rename = "sourcePath")] pub source_path: Option, + ///Data transfer parameters specific to the transfer method + #[serde(rename = "transferDirectives")] + pub transfer_directives: PostFileDownloadRequestTransferDirectives, +} +///Data transfer parameters specific to the transfer method +#[derive(Debug, Clone, PartialEq, Serialize, oas3_gen_support::Default)] +#[serde(untagged)] +pub enum PostFileDownloadRequestTransferDirectives { + #[default] + Wormhole(WormholeTransferRequest), + S3(S3TransferRequest), + Streamer(StreamerTransferRequest), +} +impl PostFileDownloadRequestTransferDirectives { + ///Creates a `Wormhole` variant with default values. + pub fn wormhole() -> Self { + Self::Wormhole(WormholeTransferRequest::default()) + } + ///Creates a `S3` variant with default values. + pub fn s3() -> Self { + Self::S3(S3TransferRequest::default()) + } + ///Creates a `Streamer` variant with default values. + pub fn streamer() -> Self { + Self::Streamer(StreamerTransferRequest::default()) + } } #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] pub struct PostFileSymlinkRequest { ///Path to the new symlink #[serde(rename = "linkPath")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub link_path: String, #[serde(rename = "sourcePath")] pub source_path: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct PostFileSymlinkResponse { pub output: Option, } @@ -1691,15 +2358,7 @@ pub struct PostFileUploadRequest { pub source_path: Option, ///Data transfer parameters specific to the transfer method #[serde(rename = "transferDirectives")] - pub transfer_directives: PostFileUploadRequestTransferDirectives, -} -///Data transfer parameters specific to the transfer method -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] -#[serde(untagged)] -pub enum PostFileUploadRequestTransferDirectives { - #[default] - WormholeDataTransferDirective(WormholeDataTransferDirective), - S3DataTransferDirective(S3DataTransferDirective), + pub transfer_directives: PostFileDownloadRequestTransferDirectives, } #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] @@ -1707,35 +2366,61 @@ pub struct PostJobAttachRequest { ///Command to attach to the job pub command: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct PostJobSubmissionResponse { #[serde(rename = "jobId")] pub job_id: Option, } ///Submit a new job -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostJobSubmitComputeSystemNameJobsPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostJobSubmitComputeSystemNameJobsPostRequestBody, } impl PostJobSubmitComputeSystemNameJobsPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/compute/{}/jobs", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "compute/{}/jobs", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostJobSubmitComputeSystemNameJobsPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostJobSubmitComputeSystemNameJobsPostResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostJobSubmitComputeSystemNameJobsPostResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(PostJobSubmitComputeSystemNameJobsPostResponse::Unknown) } } pub type PostJobSubmitComputeSystemNameJobsPostRequestBody = PostJobSubmitRequest; +///Response types for post_job_submit_compute__system_name__jobs_post +#[derive(Clone, Debug)] +pub enum PostJobSubmitComputeSystemNameJobsPostResponse { + ///201: Job submitted correctly + Created(PostJobSubmissionResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} #[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] pub struct PostJobSubmitRequest { pub job: JobDescriptionModel, @@ -1751,117 +2436,215 @@ pub struct PostMakeDirRequest { pub source_path: Option, } ///Create directory operation (`mkdir`) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostMkdirFilesystemSystemNameOpsMkdirPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostMkdirFilesystemSystemNameOpsMkdirPostRequestBody, } impl PostMkdirFilesystemSystemNameOpsMkdirPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/ops/mkdir", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/ops/mkdir", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostMkdirFilesystemSystemNameOpsMkdirPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostMkdirFilesystemSystemNameOpsMkdirPostResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostMkdirFilesystemSystemNameOpsMkdirPostResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(PostMkdirFilesystemSystemNameOpsMkdirPostResponse::Unknown) } } pub type PostMkdirFilesystemSystemNameOpsMkdirPostRequestBody = PostMakeDirRequest; -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +///Response types for post_mkdir_filesystem__system_name__ops_mkdir_post +#[derive(Clone, Debug)] +pub enum PostMkdirFilesystemSystemNameOpsMkdirPostResponse { + ///201: Directory created successfully + Created(PostMkdirResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct PostMkdirResponse { pub output: Option, } ///Create symlink operation (`ln`) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostSymlinkFilesystemSystemNameOpsSymlinkPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostSymlinkFilesystemSystemNameOpsSymlinkPostRequestBody, } impl PostSymlinkFilesystemSystemNameOpsSymlinkPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/ops/symlink", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/ops/symlink", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostSymlinkFilesystemSystemNameOpsSymlinkPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostSymlinkFilesystemSystemNameOpsSymlinkPostResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostSymlinkFilesystemSystemNameOpsSymlinkPostResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(PostSymlinkFilesystemSystemNameOpsSymlinkPostResponse::Unknown) } } pub type PostSymlinkFilesystemSystemNameOpsSymlinkPostRequestBody = PostFileSymlinkRequest; +///Response types for post_symlink_filesystem__system_name__ops_symlink_post +#[derive(Clone, Debug)] +pub enum PostSymlinkFilesystemSystemNameOpsSymlinkPostResponse { + ///201: Symlink created successfully + Created(PostFileSymlinkResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Upload a small file (max 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostUploadFilesystemSystemNameOpsUploadPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, ///Specify path where file should be uploaded. - ///## Schema - /// - Location: Query - #[validate(length(min = 1))] + /// - Location: `Query` + #[validate(length(min = 1u64))] pub path: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `multipart/form-data` pub body: PostUploadFilesystemSystemNameOpsUploadPostRequestBody, } impl PostUploadFilesystemSystemNameOpsUploadPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { use std::fmt::Write as _; let mut path = format!( - "/filesystem/{}/ops/upload", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) + "filesystem/{}/ops/upload", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) ); let mut prefix = '\0'; prefix = if prefix == '\0' { '?' } else { '&' }; write!( &mut path, "{prefix}path={}", - oas3_gen_support::percent_encode_query_component(&self.path.to_string()) + oas3_gen_support::percent_encode_query_component(&oas3_gen_support::serialize_query_param(&self.path)?) ) .unwrap(); - path + Ok(path) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let _ = req.bytes().await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::NoContent); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(DeleteRmFilesystemSystemNameOpsRmDeleteResponse::Unknown) } } pub type PostUploadFilesystemSystemNameOpsUploadPostRequestBody = BodyPostUploadFilesystemSystemNameOpsUploadPost; ///Create asynchronous upload operation (for files larger than 5242880 Bytes) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PostUploadFilesystemSystemNameTransferUploadPostRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PostUploadFilesystemSystemNameTransferUploadPostRequestBody, } impl PostUploadFilesystemSystemNameTransferUploadPostRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/transfer/upload", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/transfer/upload", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostUploadFilesystemSystemNameTransferUploadPostResponse::Created(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostUploadFilesystemSystemNameTransferUploadPostResponse::ClientError( + data, + )); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PostUploadFilesystemSystemNameTransferUploadPostResponse::ServerError( + data, + )); + } + let _ = req.bytes().await?; + Ok(PostUploadFilesystemSystemNameTransferUploadPostResponse::Unknown) } } pub type PostUploadFilesystemSystemNameTransferUploadPostRequestBody = PostFileUploadRequest; +///Response types for post_upload_filesystem__system_name__transfer_upload_post +#[derive(Clone, Debug)] +pub enum PostUploadFilesystemSystemNameTransferUploadPostResponse { + ///201: Upload operation created successfully + Created(UploadFileResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Cluster monitoring attributes. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] pub struct Probing { @@ -1871,62 +2654,115 @@ pub struct Probing { pub timeout: i64, } ///Change the permission mode of a file(`chmod`) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PutChmodFilesystemSystemNameOpsChmodPutRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PutChmodFilesystemSystemNameOpsChmodPutRequestBody, } impl PutChmodFilesystemSystemNameOpsChmodPutRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/ops/chmod", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/ops/chmod", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PutChmodFilesystemSystemNameOpsChmodPutResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PutChmodFilesystemSystemNameOpsChmodPutResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PutChmodFilesystemSystemNameOpsChmodPutResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(PutChmodFilesystemSystemNameOpsChmodPutResponse::Unknown) } } pub type PutChmodFilesystemSystemNameOpsChmodPutRequestBody = PutFileChmodRequest; +///Response types for put_chmod_filesystem__system_name__ops_chmod_put +#[derive(Clone, Debug)] +pub enum PutChmodFilesystemSystemNameOpsChmodPutResponse { + ///200: File permissions changed successfully + Ok(PutFileChmodResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} ///Change the ownership of a given file (`chown`) -#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, validator::Validate, oas3_gen_support::Default)] pub struct PutChownFilesystemSystemNameOpsChownPutRequest { - ///## Schema - /// - Location: Path - #[validate(length(min = 1))] + /// - Location: `Path` + #[validate(length(min = 1u64))] pub system_name: String, - ///## Schema - /// - Required: `yes` - /// - Content-Type: `application/json` pub body: PutChownFilesystemSystemNameOpsChownPutRequestBody, } impl PutChownFilesystemSystemNameOpsChownPutRequest { - ///Render the request path with percent-encoded parameters. - #[must_use] - pub fn render_path(&self) -> String { - format!( - "/filesystem/{}/ops/chown", - oas3_gen_support::percent_encode_path_segment(&self.system_name.to_string()) - ) + ///Render the request path with parameters. + pub fn render_path(&self) -> anyhow::Result { + Ok(format!( + "filesystem/{}/ops/chown", + oas3_gen_support::percent_encode_path_segment(&oas3_gen_support::serialize_query_param(&self.system_name)?) + )) + } + ///Parse the HTTP response into the response enum. + pub async fn parse_response( + req: reqwest::Response, + ) -> anyhow::Result { + let status = req.status(); + if status.is_success() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PutChownFilesystemSystemNameOpsChownPutResponse::Ok(data)); + } + if status.is_client_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PutChownFilesystemSystemNameOpsChownPutResponse::ClientError(data)); + } + if status.is_server_error() { + let data = oas3_gen_support::Diagnostics::::json_with_diagnostics(req).await?; + return Ok(PutChownFilesystemSystemNameOpsChownPutResponse::ServerError(data)); + } + let _ = req.bytes().await?; + Ok(PutChownFilesystemSystemNameOpsChownPutResponse::Unknown) } } pub type PutChownFilesystemSystemNameOpsChownPutRequestBody = PutFileChownRequest; +///Response types for put_chown_filesystem__system_name__ops_chown_put +#[derive(Clone, Debug)] +pub enum PutChownFilesystemSystemNameOpsChownPutResponse { + ///200: File ownership changed successfully + Ok(PutFileChownResponse), + ///4XX: Client Error + ClientError(ApiResponseError), + ///5XX: Server Error + ServerError(ApiResponseError), + ///default: Unknown response + Unknown, +} #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] pub struct PutFileChmodRequest { ///Mode in octal permission format - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] pub mode: String, #[serde(rename = "sourcePath")] pub source_path: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct PutFileChmodResponse { pub output: Option, } @@ -1943,53 +2779,27 @@ pub struct PutFileChownRequest { #[serde(rename = "sourcePath")] pub source_path: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct PutFileChownResponse { pub output: Option, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct ReservationModel { #[serde(rename = "endTime")] pub end_time: i64, pub features: Option, - #[validate(length(min = 1))] pub name: String, #[serde(rename = "nodeList")] - #[validate(length(min = 1))] pub node_list: String, #[serde(rename = "startTime")] pub start_time: i64, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] -pub struct S3DataTransferDirective { - #[serde(rename = "completeUploadUrl")] - pub complete_upload_url: Option, - #[serde(rename = "downloadUrl")] - pub download_url: Option, - ///Size of the file to upload in bytes - #[serde(rename = "fileSize")] - pub file_size: Option, - #[serde(rename = "maxPartSize")] - pub max_part_size: Option, - #[serde(rename = "partsUploadUrls")] - pub parts_upload_urls: Option>, - #[serde(rename = "transferMethod")] - #[validate(length(min = 1))] - #[default("s3".to_string())] - pub transfer_method: String, -} ///Object storage configuration, including credentials, endpoints, and upload behavior. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(default)] -pub struct S3DataTransferInput { +pub struct S3DataTransfer { ///Access key ID for S3-compatible storage. #[serde(rename = "accessKeyId")] - #[validate(length(min = 1))] pub access_key_id: String, ///Configuration for automatic object lifecycle in storage buckets. #[serde(rename = "bucketLifecycleConfiguration")] @@ -1997,75 +2807,22 @@ pub struct S3DataTransferInput { ///Configuration for multipart upload behavior. pub multipart: Option, ///Name identifier for the storage. - #[validate(length(min = 1))] pub name: String, ///Private/internal endpoint URL for the storage. #[serde(rename = "privateUrl")] - #[validate(length(min = 1))] pub private_url: String, ///Configuration for probing storage availability. pub probing: Option, ///Public/external URL for the storage. #[serde(rename = "publicUrl")] - #[validate(length(min = 1))] pub public_url: String, ///Region of the storage bucket. - #[validate(length(min = 1))] pub region: String, ///Secret access key for storage. You can give directly the content or the file path using /// `'secret_file:/path/to/file'`. #[serde(rename = "secretAccessKey")] - #[validate(length(min = 1))] pub secret_access_key: String, #[serde(rename = "serviceType")] - #[validate(length(min = 1))] - #[default("s3".to_string())] - pub service_type: String, - ///Optional health information for different services in the cluster. - #[serde(rename = "servicesHealth")] - pub services_health: Option>, - ///Optional tenant identifier for multi-tenant setups. - pub tenant: Option, - ///Time-to-live (in seconds) for generated URLs. - pub ttl: i64, -} -///Object storage configuration, including credentials, endpoints, and upload behavior. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] -pub struct S3DataTransferOutput { - ///Access key ID for S3-compatible storage. - #[serde(rename = "accessKeyId")] - #[validate(length(min = 1))] - pub access_key_id: String, - ///Configuration for automatic object lifecycle in storage buckets. - #[serde(rename = "bucketLifecycleConfiguration")] - pub bucket_lifecycle_configuration: Option, - ///Configuration for multipart upload behavior. - pub multipart: Option, - ///Name identifier for the storage. - #[validate(length(min = 1))] - pub name: String, - ///Private/internal endpoint URL for the storage. - #[serde(rename = "privateUrl")] - #[validate(length(min = 1))] - pub private_url: String, - ///Configuration for probing storage availability. - pub probing: Option, - ///Public/external URL for the storage. - #[serde(rename = "publicUrl")] - #[validate(length(min = 1))] - pub public_url: String, - ///Region of the storage bucket. - #[validate(length(min = 1))] - pub region: String, - ///Secret access key for storage. You can give directly the content or the file path using - /// `'secret_file:/path/to/file'`. - #[serde(rename = "secretAccessKey")] - #[validate(length(min = 1))] - pub secret_access_key: String, - #[serde(rename = "serviceType")] - #[validate(length(min = 1))] #[default("s3".to_string())] pub service_type: String, ///Optional health information for different services in the cluster. @@ -2079,6 +2836,7 @@ pub struct S3DataTransferOutput { ///Health status of S3-compatible storage. #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[serde(default)] pub struct S3ServiceHealth { ///True if the service is healthy. #[default(Some(false))] @@ -2092,74 +2850,40 @@ pub struct S3ServiceHealth { pub message: Option, ///Types of services that can be health-checked. #[serde(rename = "serviceType")] - pub service_type: HealthCheckType, -} -///Cluster job scheduler configuration. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct Scheduler { - ///REST API endpoint for scheduler. - #[serde(rename = "apiUrl")] - pub api_url: Option, - ///Scheduler API version. - #[serde(rename = "apiVersion")] - pub api_version: Option, - ///Timeout in seconds for scheduler communication with the API. - #[default(Some(10i64))] - pub timeout: Option, - ///Supported job scheduler types. - #[serde(rename = "type")] - pub r#type: SchedulerType, - ///Scheduler version. - #[validate(length(min = 1))] - pub version: String, + pub service_type: String, } -///Health check result for the job scheduler. #[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct SchedulerServiceHealth { - ///True if the service is healthy. - #[default(Some(false))] - pub healthy: Option, - ///Timestamp of the last health check. - #[serde(rename = "lastChecked")] - pub last_checked: Option>, - ///Service response latency in seconds. - pub latency: Option, - ///Optional status message. - pub message: Option, - ///Types of services that can be health-checked. - #[serde(rename = "serviceType")] - pub service_type: HealthCheckType, -} -///Supported job scheduler types. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] -pub enum SchedulerType { - #[serde(rename = "slurm")] - #[default] - Slurm, - #[serde(rename = "pbs")] - Pbs, +#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[serde(default)] +pub struct S3TransferRequest { + ///Size of the file to upload in bytes + #[serde(rename = "fileSize")] + pub file_size: Option, + #[serde(rename = "transferMethod")] + #[validate(length(min = 1u64))] + #[default("s3".to_string())] + pub transfer_method: String, } -///Internal service account credentials. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct ServiceAccount { - ///Service account client ID. - #[serde(rename = "clientId")] - #[validate(length(min = 1))] - pub client_id: String, - ///Service account secret token. You can give directly the content or the file path using - /// `'secret_file:/path/to/file'`. - #[validate(length(min = 1))] - pub secret: String, +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +#[serde(default)] +pub struct S3TransferResponse { + #[serde(rename = "completeUploadUrl")] + pub complete_upload_url: Option, + #[serde(rename = "downloadUrl")] + pub download_url: Option, + #[serde(rename = "maxPartSize")] + pub max_part_size: Option, + #[serde(rename = "partsUploadUrls")] + pub parts_upload_urls: Option>, + #[serde(rename = "transferMethod")] + #[default("s3".to_string())] + pub transfer_method: String, } ///SSH connection pool configuration for remote execution. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(default)] -pub struct SshclientPool { +pub struct SSHClientPool { ///SSH target hostname. - #[validate(length(min = 1))] pub host: String, ///Maximum number of concurrent SSH clients. #[serde(rename = "maxClients")] @@ -2174,12 +2898,13 @@ pub struct SshclientPool { #[serde(rename = "proxyPort")] pub proxy_port: Option, ///Various SSH settings. - pub timeout: Option, + pub timeout: Option, } ///Health status of SSH service. #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -pub struct SshserviceHealth { +#[serde(default)] +pub struct SSHServiceHealth { ///True if the service is healthy. #[default(Some(false))] pub healthy: Option, @@ -2192,13 +2917,12 @@ pub struct SshserviceHealth { pub message: Option, ///Types of services that can be health-checked. #[serde(rename = "serviceType")] - pub service_type: HealthCheckType, + pub service_type: String, } ///Various SSH settings. -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] #[serde(default)] -pub struct Sshtimeouts { +pub struct SSHTimeouts { ///Timeout (seconds) for executing commands over SSH. #[serde(rename = "commandExecution")] #[default(Some(5i64))] @@ -2218,26 +2942,112 @@ pub struct Sshtimeouts { #[default(Some(5i64))] pub login: Option, } +///Cluster job scheduler configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +#[serde(default)] +pub struct Scheduler { + ///REST API endpoint for scheduler. + #[serde(rename = "apiUrl")] + pub api_url: Option, + ///Scheduler API version. + #[serde(rename = "apiVersion")] + pub api_version: Option, + ///Timeout in seconds for scheduler communication with the API. + #[default(Some(10i64))] + pub timeout: Option, + ///Supported job scheduler types. + #[serde(rename = "type")] + pub r#type: String, + ///Scheduler version. + pub version: String, +} +///Health check result for the job scheduler. +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +#[serde(default)] +pub struct SchedulerServiceHealth { + ///True if the service is healthy. + #[default(Some(false))] + pub healthy: Option, + ///Timestamp of the last health check. + #[serde(rename = "lastChecked")] + pub last_checked: Option>, + ///Service response latency in seconds. + pub latency: Option, + ///Optional status message. + pub message: Option, + ///Types of services that can be health-checked. + #[serde(rename = "serviceType")] + pub service_type: String, +} +///Supported job scheduler types. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, oas3_gen_support::Default)] +pub enum SchedulerType { + #[serde(rename = "slurm")] + #[default] + Slurm, + #[serde(rename = "pbs")] + Pbs, +} #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[serde(default)] +pub struct StreamerDataTransfer { + ///The interface to use for listening incoming connections + pub host: Option, + ///Limit how much data can be received (in bytes) + #[serde(rename = "inboundTransferLimit")] + #[default(Some(5368709120i64))] + pub inbound_transfer_limit: Option, + ///Port range for establishing connections. + #[serde(rename = "portRange")] + #[validate(length(min = 2u64, max = 2u64))] + #[default(Some(Default::default()))] + pub port_range: Option>, + ///Configuration for probing storage availability. + pub probing: Option, + ///List of public IP addresses where server can be reached. + #[serde(rename = "publicIps")] + pub public_ips: Option>, + ///Optional local PyPI index URL for installing dependencies. + #[serde(rename = "pypiIndexUrl")] + pub pypi_index_url: Option, + #[serde(rename = "serviceType")] + #[validate(length(min = 1u64))] + #[default("streamer".to_string())] + pub service_type: String, + ///Optional health information for different services in the cluster. + #[serde(rename = "servicesHealth")] + pub services_health: Option>, + ///How long to wait for a connection before exiting (in seconds) + #[serde(rename = "waitTimeout")] + #[default(Some(86400i64))] + pub wait_timeout: Option, +} +#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] +#[serde(default)] +pub struct StreamerTransferRequest { + #[serde(rename = "transferMethod")] + #[validate(length(min = 1u64))] + #[default("streamer".to_string())] + pub transfer_method: String, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +#[serde(default)] +pub struct StreamerTransferResponse { + pub coordinates: Option, + #[serde(rename = "transferMethod")] + #[default("streamer".to_string())] + pub transfer_method: String, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct UploadFileResponse { - ///Provide method specific transfer directives + ///Data transfer parameters specific to the transfer method #[serde(rename = "transferDirectives")] - pub transfer_directives: Option, + pub transfer_directives: DownloadFileResponseTransferDirectives, #[serde(rename = "transferJob")] pub transfer_job: FirecrestFilesystemTransferModelsTransferJob, } -///Provide method specific transfer directives -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, oas3_gen_support::Default)] -#[serde(tag = "transferMethod")] -pub enum UploadFileResponseTransferDirectives { - #[serde(rename = "s3")] - #[default] - S3DataTransferDirective(S3DataTransferDirective), - #[serde(rename = "wormhole")] - WormholeDataTransferDirective(WormholeDataTransferDirective), -} -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] pub struct UserInfoResponse { pub group: PosixIdentified, pub groups: Vec, @@ -2246,41 +3056,34 @@ pub struct UserInfoResponse { #[oas3_gen_support::skip_serializing_none] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] #[serde(default)] -pub struct WormholeDataTransferDirective { - #[serde(rename = "transferMethod")] - #[validate(length(min = 1))] - #[default("wormhole".to_string())] - pub transfer_method: String, - #[serde(rename = "wormholeCode")] - pub wormhole_code: Option, -} -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] -#[serde(default)] -pub struct WormholeDataTransferInput { +pub struct WormholeDataTransfer { ///Configuration for probing storage availability. pub probing: Option, + ///Optional local PyPI index URL for installing dependencies. + #[serde(rename = "pypiIndexUrl")] + pub pypi_index_url: Option, #[serde(rename = "serviceType")] - #[validate(length(min = 1))] + #[validate(length(min = 1u64))] #[default("wormhole".to_string())] pub service_type: String, ///Optional health information for different services in the cluster. #[serde(rename = "servicesHealth")] pub services_health: Option>, } -#[oas3_gen_support::skip_serializing_none] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, validator::Validate, oas3_gen_support::Default)] +#[derive(Debug, Clone, PartialEq, Serialize, validator::Validate, oas3_gen_support::Default)] #[serde(default)] -pub struct WormholeDataTransferOutput { - ///Configuration for probing storage availability. - pub probing: Option, - #[serde(rename = "serviceType")] - #[validate(length(min = 1))] +pub struct WormholeTransferRequest { + #[serde(rename = "transferMethod")] + #[validate(length(min = 1u64))] #[default("wormhole".to_string())] - pub service_type: String, - ///Optional health information for different services in the cluster. - #[serde(rename = "servicesHealth")] - pub services_health: Option>, + pub transfer_method: String, +} +#[derive(Debug, Clone, PartialEq, Deserialize, oas3_gen_support::Default)] +#[serde(default)] +pub struct WormholeTransferResponse { + #[serde(rename = "transferMethod")] + #[default("wormhole".to_string())] + pub transfer_method: String, + #[serde(rename = "wormholeCode")] + pub wormhole_code: Option, } - -fn main() {} diff --git a/firecrest_client/src/util.rs b/firecrest_client/src/util.rs deleted file mode 100644 index c59b78f..0000000 --- a/firecrest_client/src/util.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::types::CompressionType; - -// this is missing from autogenerated code, so we implement it ourselves -impl From for CompressionType { - fn from(value: String) -> Self { - serde_json::from_str(&value).expect("couldn't conver enum value") - } -} diff --git a/openapi_spec/firecrest_3.1.yaml b/openapi_spec/firecrest_3.1.yaml index fe66253..aaed152 100644 --- a/openapi_spec/firecrest_3.1.yaml +++ b/openapi_spec/firecrest_3.1.yaml @@ -170,42 +170,20 @@ components: - transferJob title: CopyResponse type: object - DataOperation-Input: + DataOperation: properties: data_transfer: anyOf: - discriminator: mapping: - s3: "#/components/schemas/S3DataTransfer-Input" - wormhole: "#/components/schemas/WormholeDataTransfer-Input" + s3: "#/components/schemas/S3DataTransfer" + streamer: "#/components/schemas/StreamerDataTransfer" + wormhole: "#/components/schemas/WormholeDataTransfer" propertyName: serviceType oneOf: - - $ref: "#/components/schemas/S3DataTransfer-Input" - - $ref: "#/components/schemas/WormholeDataTransfer-Input" - - type: "null" - description: Data transfer service configuration - title: Data Transfer - max_ops_file_size: - default: 5242880 - description: - Maximum file size (in bytes) allowed for direct upload and - download. Larger files will go through the staging area. - title: Max Ops File Size - type: integer - title: DataOperation - type: object - DataOperation-Output: - properties: - data_transfer: - anyOf: - - discriminator: - mapping: - s3: "#/components/schemas/S3DataTransfer-Output" - wormhole: "#/components/schemas/WormholeDataTransfer-Output" - propertyName: serviceType - oneOf: - - $ref: "#/components/schemas/S3DataTransfer-Output" - - $ref: "#/components/schemas/WormholeDataTransfer-Output" + - $ref: "#/components/schemas/S3DataTransfer" + - $ref: "#/components/schemas/WormholeDataTransfer" + - $ref: "#/components/schemas/StreamerDataTransfer" - type: "null" description: Data transfer service configuration title: Data Transfer @@ -229,20 +207,17 @@ components: DownloadFileResponse: properties: transferDirectives: - description: Provide method specific transfer directives - discriminator: - mapping: - s3: "#/components/schemas/S3DataTransferDirective" - wormhole: "#/components/schemas/WormholeDataTransferDirective" - propertyName: transferMethod - oneOf: - - $ref: "#/components/schemas/S3DataTransferDirective" - - $ref: "#/components/schemas/WormholeDataTransferDirective" + anyOf: + - $ref: "#/components/schemas/WormholeTransferResponse" + - $ref: "#/components/schemas/S3TransferResponse" + - $ref: "#/components/schemas/StreamerTransferResponse" + description: Data transfer parameters specific to the transfer method title: Transferdirectives transferJob: $ref: "#/components/schemas/firecrest__filesystem__transfer__models__TransferJob" required: - transferJob + - transferDirectives title: DownloadFileResponse type: object ExtractRequest: @@ -560,7 +535,7 @@ components: jobs: anyOf: - items: - $ref: "#/components/schemas/JobModel-Output" + $ref: "#/components/schemas/JobModel" type: array - type: "null" title: Jobs @@ -616,11 +591,11 @@ components: properties: dataOperation: anyOf: - - $ref: "#/components/schemas/DataOperation-Output" + - $ref: "#/components/schemas/DataOperation" - type: "null" systems: items: - $ref: "#/components/schemas/HPCCluster-Output" + $ref: "#/components/schemas/HPCCluster" title: Systems type: array required: @@ -638,7 +613,7 @@ components: - output title: GetViewFileResponse type: object - HPCCluster-Input: + HPCCluster: description: "Definition of an HPC cluster, including SSH access, scheduling, and @@ -668,68 +643,9 @@ components: title: Name type: string probing: - $ref: "#/components/schemas/Probing" - description: Probing configuration for monitoring the cluster. - scheduler: - $ref: "#/components/schemas/Scheduler" - description: Job scheduler configuration. - serviceAccount: - $ref: "#/components/schemas/ServiceAccount" - description: Service credentials for internal APIs. - servicesHealth: anyOf: - - items: - anyOf: - - $ref: "#/components/schemas/SchedulerServiceHealth" - - $ref: "#/components/schemas/FilesystemServiceHealth" - - $ref: "#/components/schemas/SSHServiceHealth" - - $ref: "#/components/schemas/HealthCheckException" - type: array + - $ref: "#/components/schemas/Probing" - type: "null" - description: Optional health information for different services in the cluster. - title: Serviceshealth - ssh: - $ref: "#/components/schemas/SSHClientPool" - description: SSH configuration for accessing the cluster nodes. - required: - - name - - ssh - - scheduler - - serviceAccount - - probing - title: HPCCluster - type: object - HPCCluster-Output: - description: - "Definition of an HPC cluster, including SSH access, scheduling, - and - - filesystem layout. More info in - - [the systems' section](../arch/systems//README.md)." - properties: - datatransferJobsDirectives: - description: - Custom scheduler flags passed to data transfer jobs (e.g. `-pxfer` - for a dedicated partition). - items: - type: string - title: Datatransferjobsdirectives - type: array - fileSystems: - description: - List of mounted file systems on the cluster, such as scratch - or home directories. - items: - $ref: "#/components/schemas/FileSystem" - title: Filesystems - type: array - name: - description: Unique name for the cluster. This field is case insensitive. - title: Name - type: string - probing: - $ref: "#/components/schemas/Probing" description: Probing configuration for monitoring the cluster. scheduler: $ref: "#/components/schemas/Scheduler" @@ -753,7 +669,6 @@ components: - name - ssh - scheduler - - probing title: HPCCluster type: object HealthCheckException: @@ -898,79 +813,7 @@ components: - jobId title: JobMetadataModel type: object - JobModel-Input: - properties: - account: - anyOf: - - type: string - - type: "null" - title: Account - allocationNodes: - title: Allocationnodes - type: integer - cluster: - title: Cluster - type: string - group: - anyOf: - - type: string - - type: "null" - title: Group - jobId: - title: Jobid - type: integer - killRequestUser: - anyOf: - - type: string - - type: "null" - title: Killrequestuser - name: - title: Name - type: string - nodes: - title: Nodes - type: string - partition: - title: Partition - type: string - priority: - anyOf: - - type: integer - - type: "null" - title: Priority - status: - $ref: "#/components/schemas/JobStatus" - tasks: - anyOf: - - items: - $ref: "#/components/schemas/JobTask" - type: array - - type: "null" - title: Tasks - time: - $ref: "#/components/schemas/JobTime" - user: - anyOf: - - type: string - - type: "null" - title: User - workingDirectory: - title: Workingdirectory - type: string - required: - - jobId - - name - - status - - time - - allocationNodes - - cluster - - nodes - - partition - - user - - workingDirectory - title: JobModel - type: object - JobModel-Output: + JobModel: properties: account: anyOf: @@ -1401,8 +1244,16 @@ components: - type: "null" example: /home/user/dir title: Sourcepath + transferDirectives: + anyOf: + - $ref: "#/components/schemas/WormholeTransferRequest" + - $ref: "#/components/schemas/S3TransferRequest" + - $ref: "#/components/schemas/StreamerTransferRequest" + description: Data transfer parameters specific to the transfer method + title: Transferdirectives required: - sourcePath + - transferDirectives title: PostFileDownloadRequest type: object PostFileSymlinkRequest: @@ -1457,8 +1308,9 @@ components: title: Sourcepath transferDirectives: anyOf: - - $ref: "#/components/schemas/WormholeDataTransferDirective" - - $ref: "#/components/schemas/S3DataTransferDirective" + - $ref: "#/components/schemas/WormholeTransferRequest" + - $ref: "#/components/schemas/S3TransferRequest" + - $ref: "#/components/schemas/StreamerTransferRequest" description: Data transfer parameters specific to the transfer method title: Transferdirectives required: @@ -1674,7 +1526,7 @@ components: - startTime title: ReservationModel type: object - S3DataTransfer-Input: + S3DataTransfer: description: Object storage configuration, including credentials, endpoints, and upload behavior. @@ -1759,92 +1611,59 @@ components: - ttl title: S3DataTransfer type: object - S3DataTransfer-Output: - description: - Object storage configuration, including credentials, endpoints, - and upload behavior. + S3ServiceHealth: + description: Health status of S3-compatible storage. properties: - accessKeyId: - description: Access key ID for S3-compatible storage. - format: password - title: Accesskeyid - type: string - writeOnly: true - bucketLifecycleConfiguration: - $ref: "#/components/schemas/BucketLifecycleConfiguration" - description: - Lifecycle policy settings for auto-deleting files after a given - number of days. - multipart: - $ref: "#/components/schemas/MultipartUpload" - description: Settings for multipart upload, including chunk size and concurrency. - name: - description: Name identifier for the storage. - title: Name - type: string - privateUrl: - description: Private/internal endpoint URL for the storage. - format: password - title: Privateurl - type: string - writeOnly: true - probing: + healthy: anyOf: - - $ref: "#/components/schemas/Probing" + - type: boolean - type: "null" - description: Configuration for probing storage availability. - publicUrl: - description: Public/external URL for the storage. - title: Publicurl - type: string - region: - description: Region of the storage bucket. - title: Region - type: string - secretAccessKey: - description: - Secret access key for storage. You can give directly the content - or the file path using `'secret_file:/path/to/file'`. - format: password - title: Secretaccesskey - type: string - writeOnly: true - serviceType: - const: s3 - title: Servicetype - type: string - servicesHealth: + default: false + description: True if the service is healthy. + title: Healthy + lastChecked: anyOf: - - items: - anyOf: - - $ref: "#/components/schemas/S3ServiceHealth" - - $ref: "#/components/schemas/HealthCheckException" - type: array + - format: date-time + type: string - type: "null" - description: Optional health information for different services in the cluster. - title: Serviceshealth - tenant: + description: Timestamp of the last health check. + title: Lastchecked + latency: + anyOf: + - type: number + - type: "null" + description: Service response latency in seconds. + title: Latency + message: anyOf: - type: string - type: "null" - description: Optional tenant identifier for multi-tenant setups. - title: Tenant - ttl: - description: Time-to-live (in seconds) for generated URLs. - title: Ttl - type: integer + description: Optional status message. + title: Message + serviceType: + $ref: "#/components/schemas/HealthCheckType" + description: Type of the service being checked. required: - serviceType - - name - - privateUrl - - publicUrl - - accessKeyId - - secretAccessKey - - region - - ttl - title: S3DataTransfer + title: S3ServiceHealth type: object - S3DataTransferDirective: + S3TransferRequest: + properties: + fileSize: + anyOf: + - type: integer + - type: "null" + description: Size of the file to upload in bytes + title: Filesize + transferMethod: + const: s3 + title: Transfermethod + type: string + required: + - transferMethod + title: S3TransferRequest + type: object + S3TransferResponse: properties: completeUploadUrl: anyOf: @@ -1856,12 +1675,6 @@ components: - type: string - type: "null" title: Downloadurl - fileSize: - anyOf: - - type: integer - - type: "null" - description: Size of the file to upload in bytes - title: Filesize maxPartSize: anyOf: - type: integer @@ -1880,43 +1693,7 @@ components: type: string required: - transferMethod - title: S3DataTransferDirective - type: object - S3ServiceHealth: - description: Health status of S3-compatible storage. - properties: - healthy: - anyOf: - - type: boolean - - type: "null" - default: false - description: True if the service is healthy. - title: Healthy - lastChecked: - anyOf: - - format: date-time - type: string - - type: "null" - description: Timestamp of the last health check. - title: Lastchecked - latency: - anyOf: - - type: number - - type: "null" - description: Service response latency in seconds. - title: Latency - message: - anyOf: - - type: string - - type: "null" - description: Optional status message. - title: Message - serviceType: - $ref: "#/components/schemas/HealthCheckType" - description: Type of the service being checked. - required: - - serviceType - title: S3ServiceHealth + title: S3TransferResponse type: object SSHClientPool: description: SSH connection pool configuration for remote execution. @@ -2117,23 +1894,116 @@ components: - secret title: ServiceAccount type: object + StreamerDataTransfer: + properties: + host: + anyOf: + - type: string + - type: "null" + description: The interface to use for listening incoming connections + title: Host + inboundTransferLimit: + anyOf: + - type: integer + - type: "null" + default: 5368709120 + description: Limit how much data can be received (in bytes) + title: Inboundtransferlimit + portRange: + default: + - 5665 + - 5675 + description: Port range for establishing connections. + maxItems: 2 + minItems: 2 + prefixItems: + - type: integer + - type: integer + title: Portrange + type: array + probing: + anyOf: + - $ref: "#/components/schemas/Probing" + - type: "null" + description: Configuration for probing storage availability. + publicIps: + anyOf: + - items: + type: string + type: array + - type: "null" + description: List of public IP addresses where server can be reached. + title: Publicips + pypiIndexUrl: + anyOf: + - type: string + - type: "null" + description: Optional local PyPI index URL for installing dependencies. + title: Pypiindexurl + serviceType: + const: streamer + title: Servicetype + type: string + servicesHealth: + anyOf: + - items: + anyOf: + - $ref: "#/components/schemas/S3ServiceHealth" + - $ref: "#/components/schemas/HealthCheckException" + type: array + - type: "null" + description: Optional health information for different services in the cluster. + title: Serviceshealth + waitTimeout: + anyOf: + - type: integer + - type: "null" + default: 86400 + description: How long to wait for a connection before exiting (in seconds) + title: Waittimeout + required: + - serviceType + title: StreamerDataTransfer + type: object + StreamerTransferRequest: + properties: + transferMethod: + const: streamer + title: Transfermethod + type: string + required: + - transferMethod + title: StreamerTransferRequest + type: object + StreamerTransferResponse: + properties: + coordinates: + anyOf: + - type: string + - type: "null" + title: Coordinates + transferMethod: + const: streamer + title: Transfermethod + type: string + required: + - transferMethod + title: StreamerTransferResponse + type: object UploadFileResponse: properties: transferDirectives: - description: Provide method specific transfer directives - discriminator: - mapping: - s3: "#/components/schemas/S3DataTransferDirective" - wormhole: "#/components/schemas/WormholeDataTransferDirective" - propertyName: transferMethod - oneOf: - - $ref: "#/components/schemas/S3DataTransferDirective" - - $ref: "#/components/schemas/WormholeDataTransferDirective" + anyOf: + - $ref: "#/components/schemas/WormholeTransferResponse" + - $ref: "#/components/schemas/S3TransferResponse" + - $ref: "#/components/schemas/StreamerTransferResponse" + description: Data transfer parameters specific to the transfer method title: Transferdirectives transferJob: $ref: "#/components/schemas/firecrest__filesystem__transfer__models__TransferJob" required: - transferJob + - transferDirectives title: UploadFileResponse type: object UserInfoResponse: @@ -2153,13 +2023,19 @@ components: - groups title: UserInfoResponse type: object - WormholeDataTransfer-Input: + WormholeDataTransfer: properties: probing: anyOf: - $ref: "#/components/schemas/Probing" - type: "null" description: Configuration for probing storage availability. + pypiIndexUrl: + anyOf: + - type: string + - type: "null" + description: Optional local PyPI index URL for installing dependencies. + title: Pypiindexurl serviceType: const: wormhole title: Servicetype @@ -2178,32 +2054,17 @@ components: - serviceType title: WormholeDataTransfer type: object - WormholeDataTransfer-Output: + WormholeTransferRequest: properties: - probing: - anyOf: - - $ref: "#/components/schemas/Probing" - - type: "null" - description: Configuration for probing storage availability. - serviceType: + transferMethod: const: wormhole - title: Servicetype + title: Transfermethod type: string - servicesHealth: - anyOf: - - items: - anyOf: - - $ref: "#/components/schemas/S3ServiceHealth" - - $ref: "#/components/schemas/HealthCheckException" - type: array - - type: "null" - description: Optional health information for different services in the cluster. - title: Serviceshealth required: - - serviceType - title: WormholeDataTransfer + - transferMethod + title: WormholeTransferRequest type: object - WormholeDataTransferDirective: + WormholeTransferResponse: properties: transferMethod: const: wormhole @@ -2216,7 +2077,7 @@ components: title: Wormholecode required: - transferMethod - title: WormholeDataTransferDirective + title: WormholeTransferResponse type: object firecrest__filesystem__transfer__models__TransferJob: properties: @@ -2224,7 +2085,7 @@ components: title: Jobid type: integer logs: - $ref: "#/components/schemas/lib__datatransfers__datatransfer_base__TransferJobLogs" + $ref: "#/components/schemas/firecrest__filesystem__transfer__models__TransferJobLogs" system: title: System type: string @@ -2238,7 +2099,7 @@ components: - logs title: TransferJob type: object - lib__datatransfers__datatransfer_base__TransferJobLogs: + firecrest__filesystem__transfer__models__TransferJobLogs: properties: errorLog: title: Errorlog @@ -2263,7 +2124,7 @@ components: type: http info: title: FirecREST - version: 2.4.0 + version: 2.4.1 openapi: 3.1.0 paths: /compute/{system_name}/jobs: