From d8c762e9df6a6fe5c3c49dea3f83f15fbcd4e0bd Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Wed, 22 Jan 2025 10:21:08 -0500 Subject: [PATCH] feat(harmony_macros): add `yaml` macro to validate YAML input - Introduced a new `yaml` macro in `harmony_macros` that validates if the provided YAML string is valid by attempting to deserialize it using `serde_yaml`. - Added dependencies on `serde`, `serde_yaml` for handling YAML deserialization. - Included dev dependencies with features enabled for deriving types from `serde`. --- harmony-rs/Cargo.lock | 652 +++++++++++++++++++++++++-- harmony-rs/demo/kube-rs/Cargo.toml | 3 + harmony-rs/demo/kube-rs/src/main.rs | 192 +++++++- harmony-rs/harmony_macros/Cargo.toml | 5 + harmony-rs/harmony_macros/src/lib.rs | 42 +- 5 files changed, 861 insertions(+), 33 deletions(-) diff --git a/harmony-rs/Cargo.lock b/harmony-rs/Cargo.lock index 4c7797e..bbb6037 100644 --- a/harmony-rs/Cargo.lock +++ b/harmony-rs/Cargo.lock @@ -188,6 +188,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -323,6 +329,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-targets 0.52.6", ] @@ -385,6 +392,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -579,6 +596,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -722,6 +745,19 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fqm" +version = "0.1.0" +dependencies = [ + "cidr", + "env_logger", + "harmony", + "harmony_macros", + "harmony_types", + "log", + "tokio", +] + [[package]] name = "funty" version = "2.0.0" @@ -877,7 +913,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -916,6 +952,8 @@ version = "1.0.0" dependencies = [ "harmony_types", "quote", + "serde", + "serde_yaml", "syn", ] @@ -929,6 +967,30 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http 1.2.0", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http 1.2.0", +] + [[package]] name = "heck" version = "0.5.0" @@ -985,6 +1047,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -992,7 +1065,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1025,8 +1121,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1038,6 +1134,77 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-http-proxy" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d06dbdfbacf34d996c6fb540a71a684a7aae9056c71951163af8a8a4c07b9a4" +dependencies = [ + "bytes", + "futures-util", + "headers", + "http 1.2.0", + "hyper 1.5.2", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "rustls-native-certs 0.7.3", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http 1.2.0", + "hyper 1.5.2", + "hyper-util", + "log", + "rustls", + "rustls-native-certs 0.8.1", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.5.2", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1045,12 +1212,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.5.2", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -1260,6 +1446,97 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonpath-rust" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror 2.0.11", +] + +[[package]] +name = "k8s-openapi" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c75b990324f09bef15e791606b7b7a296d02fc88a344f6eba9390970a870ad5" +dependencies = [ + "base64 0.22.1", + "chrono", + "serde", + "serde-value", + "serde_json", +] + +[[package]] +name = "kube" +version = "0.98.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32053dc495efad4d188c7b33cc7c02ef4a6e43038115348348876efd39a53cba" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", +] + +[[package]] +name = "kube-client" +version = "0.98.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d34ad38cdfbd1fa87195d42569f57bb1dda6ba5f260ee32fef9570b7937a0c9" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "either", + "futures", + "home", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.2", + "hyper-http-proxy", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem", + "rustls", + "rustls-pemfile 2.2.0", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror 2.0.11", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.98.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97aa830b288a178a90e784d1b0f1539f2d200d2188c7b4a3146d9dc983d596f3" +dependencies = [ + "chrono", + "form_urlencoded", + "http 1.2.0", + "k8s-openapi", + "serde", + "serde-value", + "serde_json", + "thiserror 2.0.11", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1382,7 +1659,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -1535,7 +1812,7 @@ dependencies = [ "russh-sftp", "serde", "serde_json", - "thiserror", + "thiserror 1.0.63", "tokio", "tokio-stream", "tokio-util", @@ -1551,7 +1828,7 @@ dependencies = [ "pretty_assertions", "rand", "serde", - "thiserror", + "thiserror 1.0.63", "tokio", "uuid", "xml-rs", @@ -1559,6 +1836,15 @@ dependencies = [ "yaserde_derive", ] +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "p256" version = "0.13.2" @@ -1653,6 +1939,16 @@ dependencies = [ "hmac", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1668,6 +1964,51 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +dependencies = [ + "memchr", + "thiserror 2.0.11", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1873,15 +2214,15 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", "hyper-tls", "ipnet", "js-sys", @@ -1891,11 +2232,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", @@ -1917,6 +2258,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rsa" version = "0.9.6" @@ -1977,7 +2333,7 @@ dependencies = [ "ssh-encoding", "ssh-key", "subtle", - "thiserror", + "thiserror 1.0.63", "tokio", ] @@ -2035,7 +2391,7 @@ dependencies = [ "spki", "ssh-encoding", "ssh-key", - "thiserror", + "thiserror 1.0.63", "tokio", "tokio-stream", "typenum", @@ -2055,7 +2411,7 @@ dependencies = [ "flurry", "log", "serde", - "thiserror", + "thiserror 1.0.63", "tokio", "tokio-util", ] @@ -2072,7 +2428,7 @@ dependencies = [ "hmac", "rand", "sha2", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -2103,13 +2459,79 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -2167,6 +2589,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -2174,7 +2605,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -2182,9 +2626,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -2204,18 +2648,28 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] -name = "serde_derive" -version = "1.0.209" +name = "serde-value" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -2258,6 +2712,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2426,6 +2893,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "synstructure" version = "0.13.1" @@ -2444,7 +2917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -2477,13 +2950,39 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "test-kube-rs" +version = "0.1.0" +dependencies = [ + "cidr", + "env_logger", + "harmony", + "harmony_macros", + "http 1.2.0", + "k8s-openapi", + "kube", + "log", + "serde_yaml", + "tokio", + "url", +] + [[package]] name = "thiserror" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.63", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", ] [[package]] @@ -2497,6 +2996,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -2554,6 +3064,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.17" @@ -2578,6 +3098,47 @@ dependencies = [ "tokio", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +dependencies = [ + "base64 0.22.1", + "bitflags 2.6.0", + "bytes", + "http 1.2.0", + "http-body 1.0.1", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -2590,10 +3151,23 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -2615,6 +3189,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -2631,6 +3211,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.4" @@ -3037,6 +3629,7 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yaserde" version = "0.12.0" +source = "git+https://github.com/jggc/yaserde.git#c94ca32b6505f9c9a668702a1b1f1f88c6374301" dependencies = [ "log", "xml-rs", @@ -3045,6 +3638,7 @@ dependencies = [ [[package]] name = "yaserde_derive" version = "0.12.0" +source = "git+https://github.com/jggc/yaserde.git#c94ca32b6505f9c9a668702a1b1f1f88c6374301" dependencies = [ "heck", "log", diff --git a/harmony-rs/demo/kube-rs/Cargo.toml b/harmony-rs/demo/kube-rs/Cargo.toml index 4c53369..f53b80b 100644 --- a/harmony-rs/demo/kube-rs/Cargo.toml +++ b/harmony-rs/demo/kube-rs/Cargo.toml @@ -14,3 +14,6 @@ log = { workspace = true } env_logger = { workspace = true } url = { workspace = true } kube = "0.98.0" +k8s-openapi = { version = "0.24.0", features = [ "v1_30" ] } +http = "1.2.0" +serde_yaml = "0.9.34" diff --git a/harmony-rs/demo/kube-rs/src/main.rs b/harmony-rs/demo/kube-rs/src/main.rs index ac19f78..a8cc948 100644 --- a/harmony-rs/demo/kube-rs/src/main.rs +++ b/harmony-rs/demo/kube-rs/src/main.rs @@ -1,8 +1,194 @@ -use kube::Client; +use std::collections::BTreeMap; + +use harmony_macros::yaml; +use k8s_openapi::{ + api::{ + apps::v1::{Deployment, DeploymentSpec}, + core::v1::{Container, Node, Pod, PodSpec, PodTemplateSpec}, + }, + apimachinery::pkg::apis::meta::v1::LabelSelector, +}; +use kube::{ + Api, Client, Config, ResourceExt, + api::{ListParams, ObjectMeta, PostParams}, +}; #[tokio::main] async fn main() { - let client = Client::try_default().await.expect("Should instanciate client from defaults"); - println!("apiserver_version {:?}", client.apiserver_version()); + let client = Client::try_default() + .await + .expect("Should instanciate client from defaults"); + println!("apiserver_version {:?}", client.apiserver_version().await); + println!("default namespace {:?}", client.default_namespace()); + // println!( + // "apiserver_groups {:?}", + // client + // .list_api_groups() + // .await + // .unwrap() + // .groups + // .iter() + // .map(|g| g.name.clone()) + // .collect::>() + // ); + + // let pods: Api = Api::default_namespaced(client.clone()); + // for p in pods.list(&ListParams::default()).await.unwrap() { + // println!("found pod {}", p.name_any()) + // } + + // let nodes : Api = Api::all(client.clone()); + // for n in nodes.list(&ListParams::default()).await.unwrap() { + // println!("found node {} status {:?}", n.name_any(), n.status.unwrap()) + // } + + let nginxdeployment = nginx_deployment_2(); + let nginxdeployment = nginx_deployment_serde(); + assert_eq!(nginx_deployment_2(), nginx_macro()); + assert_eq!(nginx_deployment_serde(), nginx_macro()); + let nginxdeployment = nginx_macro(); + let deployment: Api = Api::default_namespaced(client.clone()); + match deployment + .create(&PostParams::default(), &nginxdeployment) + .await + { + Ok(_d) => println!("Deployment success"), + Err(e) => { + println!("Error creating deployment {}", e); + if let kube::Error::Api(error_response) = &e { + if error_response.code == http::StatusCode::CONFLICT.as_u16() { + println!("Already exists"); + return; + } + } + panic!("{}", e) + } + }; + println!( + "{:?}", + deployment + .get_status(&nginxdeployment.name_unchecked()) + .await + .unwrap() + ); println!("Hello world"); } + +fn nginx_macro() -> Deployment { + yaml!( + r#" +metadata: + name: "nginx-test" +spec: + selector: + matchLabels: + app: nginx-test + template: + metadata: + labels: + app: nginx-test + spec: + containers: + - image: nginx + name: nginx"# + ) + .unwrap() +} + +fn nginx_deployment_serde() -> Deployment { + let deployment: Deployment = serde_yaml::from_str( + r#" +metadata: + name: "nginx-test" +spec: + selector: + matchLabels: + app: nginx-test + template: + metadata: + labels: + app: nginx-test + spec: + containers: + - image: nginx + name: nginx"#, + ) + .unwrap(); + return deployment; +} +fn nginx_deployment_2() -> Deployment { + let mut pod_template = PodTemplateSpec::default(); + pod_template.metadata = Some(ObjectMeta { + labels: Some(BTreeMap::from([( + "app".to_string(), + "nginx-test".to_string(), + )])), + ..Default::default() + }); + pod_template.spec = Some(PodSpec { + containers: vec![Container { + name: "nginx".to_string(), + image: Some("nginx".to_string()), + ..Default::default() + }], + ..Default::default() + }); + let mut spec = DeploymentSpec::default(); + spec.template = pod_template; + spec.selector = LabelSelector { + match_expressions: None, + match_labels: Some(BTreeMap::from([( + "app".to_string(), + "nginx-test".to_string(), + )])), + }; + + let mut deployment = Deployment::default(); + deployment.spec = Some(spec); + deployment.metadata.name = Some("nginx-test".to_string()); + + deployment +} +fn nginx_deployment() -> Deployment { + let deployment = Deployment { + metadata: ObjectMeta { + name: Some("nginx-test".to_string()), + ..Default::default() + }, + spec: Some(DeploymentSpec { + min_ready_seconds: None, + paused: None, + progress_deadline_seconds: None, + replicas: Some(1), + revision_history_limit: Some(10), + selector: LabelSelector { + match_expressions: None, + match_labels: Some(BTreeMap::from([( + "app".to_string(), + "nginx-test".to_string(), + )])), + }, + strategy: None, + template: PodTemplateSpec { + metadata: Some(ObjectMeta { + labels: Some(BTreeMap::from([( + "app".to_string(), + "nginx-test".to_string(), + )])), + ..Default::default() + }), + spec: Some(PodSpec { + containers: vec![Container { + name: "nginx".to_string(), + image: Some("nginx".to_string()), + ..Default::default() + }], + ..Default::default() + }), + }, + }), + status: None, + }; + println!("{:?}", deployment.managed_fields()); + deployment +} diff --git a/harmony-rs/harmony_macros/Cargo.toml b/harmony-rs/harmony_macros/Cargo.toml index 7865014..6e35ebf 100644 --- a/harmony-rs/harmony_macros/Cargo.toml +++ b/harmony-rs/harmony_macros/Cargo.toml @@ -9,4 +9,9 @@ proc-macro = true [dependencies] harmony_types = { path = "../harmony_types" } quote = "1.0.37" +serde = "1.0.217" +serde_yaml = "0.9.34" syn = "2.0.90" + +[dev-dependencies] +serde = { version = "1.0.217", features = ["derive"] } diff --git a/harmony-rs/harmony_macros/src/lib.rs b/harmony-rs/harmony_macros/src/lib.rs index a49db36..2cc4c37 100644 --- a/harmony-rs/harmony_macros/src/lib.rs +++ b/harmony-rs/harmony_macros/src/lib.rs @@ -2,7 +2,9 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::{LitStr, parse_macro_input}; +use serde_yaml::Value; +use syn::LitStr; +use syn::parse_macro_input; #[proc_macro] pub fn ip(input: TokenStream) -> TokenStream { @@ -76,3 +78,41 @@ fn parse_mac_address(mac: &str) -> Result<[u8; 6], String> { Ok(bytes) } + +/// Verify that input is valid yaml by trying to deserialize it using +/// serde_yaml::from_str::(input) +/// +/// panics: If yaml is not valid +#[proc_macro] +pub fn yaml(input: TokenStream) -> TokenStream { + // TODO, accept a second argument that is the type to be deserialized to and validate at + // compile-time that deserialization is possible + // + // It does not seem to be doable with the way macros are designed : we may pass an ident to the + // macro, but the macro only has access to the ident, not the type itself. + // + // I also tried to create a restricted version of this macro, but this time serde got in the + // way : my use case is to make sure that the yaml I am given can deserialize strictly (with + // deny_unknown_attributes option on) to k8s-openapi types. But the k8s-openapi types are not + // annotated with deny_unknown_attributes and there does not seem to be a way to tell serde to + // deserialize in "strict mode" when calling the deserialization function itself. I tried + // wrapping the types in something like : + // + // ```rust + // #[derive(Deserialize, Debug)] + // #[serde(deny_unknown_fields)] + // struct Strict(pub T); + // ``` + // + // But it still does actually deserialize T strictly. I gave up for now at this point. Will + // find a solution some day! + + let yaml = parse_macro_input!(input as LitStr); + + serde_yaml::from_str::(yaml.value().as_str()).expect("Should be valid yaml"); + + quote! { + serde_yaml::from_str(#yaml) + } + .into() +}