From f03b3025baf6879a9dde5b0103fa3cd5199ead5c Mon Sep 17 00:00:00 2001 From: ElFantasma Date: Tue, 27 Feb 2024 10:19:21 -0300 Subject: [PATCH] K8s deploy script (BFT-397) (#62) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Deploy script for Kubernetes ## Why ❔ Test framework will require to deploy a number of nodes into a Kubernetes cluster --------- Co-authored-by: IAvecilla Co-authored-by: Nacho Avecilla Co-authored-by: Bruno França Co-authored-by: Grzegorz Prusak --- Dockerfile | 15 +- Makefile | 58 +- compose.yaml | 4 +- docker-entrypoint.sh | 4 +- entrypoint.sh | 5 - k8s_entrypoint.sh | 6 + node/Cargo.lock | 829 +++++++++++++++++++++++-- node/Cargo.toml | 5 +- node/deny.toml | 15 + node/libs/concurrency/Cargo.toml | 2 +- node/tools/Cargo.toml | 7 + node/tools/README.md | 54 +- node/tools/docker-config/addresses.txt | 1 + node/tools/src/bin/deployer.rs | 155 +++++ node/tools/src/bin/localnet_config.rs | 51 +- node/tools/src/config.rs | 103 ++- node/tools/src/k8s.rs | 222 +++++++ node/tools/src/lib.rs | 3 +- node/tools/src/main.rs | 22 +- node/tools/src/rpc/methods/config.rs | 48 ++ node/tools/src/rpc/methods/mod.rs | 1 + node/tools/src/rpc/server.rs | 20 +- 22 files changed, 1490 insertions(+), 140 deletions(-) delete mode 100644 entrypoint.sh create mode 100644 k8s_entrypoint.sh create mode 100644 node/tools/docker-config/addresses.txt create mode 100644 node/tools/src/bin/deployer.rs create mode 100644 node/tools/src/k8s.rs create mode 100644 node/tools/src/rpc/methods/config.rs diff --git a/Dockerfile b/Dockerfile index bedfa5ae..5f274ec1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,26 @@ # Build Stage -FROM rust:latest as build +FROM rust:latest as builder COPY /node/ /node/ -COPY Makefile . WORKDIR /node RUN apt-get update && apt-get install -y libclang-dev RUN cargo build --release -RUN cd .. && make docker_node_configs + +# Binary copy stage +FROM scratch as binary +COPY --from=builder /node/target/release/executor . # Runtime Stage FROM debian:stable-slim as runtime -COPY --from=build /node/target/release/executor /node/ -COPY --from=build /node/tools/docker-config/nodes-config /node/ +COPY /node/tools/docker_binaries/executor /node/ +COPY /node/tools/k8s_configs/ /node/k8s_config +COPY /node/tools/docker-config/ /node/docker_config COPY docker-entrypoint.sh /node/ +COPY k8s_entrypoint.sh /node/ WORKDIR /node RUN chmod +x docker-entrypoint.sh +RUN chmod +x k8s_entrypoint.sh ENTRYPOINT ["./docker-entrypoint.sh"] diff --git a/Makefile b/Makefile index 9943dc2d..e3d047a5 100644 --- a/Makefile +++ b/Makefile @@ -1,44 +1,76 @@ -.PHONY: node nodes_config docker_node_configs node_docker consensus_docker_example clean clean_docker -IP?=127.0.0.1:3054 +.PHONY: node nodes_config docker_nodes_config node_docker consensus_docker_example clean clean_docker addresses_file blank_configs +NODE?=0 DOCKER_IP=172.12.0.10 EXECUTABLE_NODE_DIR=node/tools +NODES=4 +SEED_NODES=1 # Locally run commands node: - export RUST_LOG=INFO && cd ${EXECUTABLE_NODE_DIR}/nodes-config/${IP} && cargo run -- --database ../../database/${IP} + export RUST_LOG=INFO && cd ${EXECUTABLE_NODE_DIR}/nodes-config/node_${NODE} && cargo run -- --database ../../database/node_${NODE} nodes_config: cd ${EXECUTABLE_NODE_DIR} && cargo run --bin localnet_config -- --input-addrs addresses.txt --output-dir nodes-config # Docker commands -# This command will run inside the Dockerfile and it's not necessary to use it outside there. -docker_node_configs: - cd ${EXECUTABLE_NODE_DIR} && cargo run --release --bin localnet_config -- --input-addrs docker-config/addresses.txt --output-dir docker-config/nodes-config +docker_build_executor: + docker build --output=node/tools/docker_binaries --target=binary . -node_docker: - mkdir -p ${EXECUTABLE_NODE_DIR}/docker-config - cd ${EXECUTABLE_NODE_DIR}/docker-config && rm -rf addresses.txt && echo ${DOCKER_IP}:3054 >> addresses.txt - docker-compose up -d node-1 +docker_node_image: + docker build -t consensus-node --target=runtime . + +docker_nodes_config: + cd ${EXECUTABLE_NODE_DIR} && cargo run --release --bin localnet_config -- --input-addrs docker-config/addresses.txt --output-dir docker-config + +docker_node: + $(MAKE) docker_node_image + docker run -d --name consensus-node-${NODE} --env NODE_ID="consensus-node-${NODE}" consensus-node consensus_docker_example: mkdir -p ${EXECUTABLE_NODE_DIR}/docker-config - cd ${EXECUTABLE_NODE_DIR}/docker-config && rm -rf addresses.txt && touch addresses.txt && echo 172.12.0.10:3054 >> addresses.txt && echo 172.12.0.11:3054 >> addresses.txt + cd ${EXECUTABLE_NODE_DIR}/docker-config && rm -rf addresses.txt && echo 172.12.0.10:3054 >> addresses.txt && echo 172.12.0.11:3054 >> addresses.txt + $(MAKE) docker_nodes_config + $(MAKE) docker_node_image docker-compose up -d stop_docker_nodes: docker stop consensus-node-1 consensus-node-2 +start_k8s_nodes: + cd ${EXECUTABLE_NODE_DIR} && cargo run --release --bin deployer generate-config --nodes ${NODES} + $(MAKE) docker_node_image + minikube image load consensus-node:latest + cd ${EXECUTABLE_NODE_DIR} && cargo run --release --bin deployer deploy --nodes ${NODES} --seed-nodes ${SEED_NODES} + # Clean commands -clean: clean_docker +clean: clean_docker clean_k8s rm -rf ${EXECUTABLE_NODE_DIR}/nodes-config rm -rf ${EXECUTABLE_NODE_DIR}/database +clean_k8s: + rm -rf ${EXECUTABLE_NODE_DIR}/k8s_configs + kubectl delete deployments --all + kubectl delete pods --all + clean_docker: - rm -rf ${EXECUTABLE_NODE_DIR}/docker-config docker rm -f consensus-node-1 docker rm -f consensus-node-2 docker network rm -f node-net docker image rm -f consensus-node + +addresses_file: + mkdir -p ${EXECUTABLE_NODE_DIR}/docker-config + cd ${EXECUTABLE_NODE_DIR}/docker-config && \ + rm -rf addresses.txt && \ + touch addresses.txt && \ + for n in $$(seq 0 $$((${NODES} - 1))); do echo 0.0.0.$$n:3054 >> addresses.txt; done + +blank_configs: addresses_file docker_node_configs + for n in $$(seq 0 $$((${NODES} - 1))); do \ + jq '.publicAddr = "0.0.0.0:3054"' node/tools/docker-config/nodes-config/node_$$n/config.json | \ + jq '.gossipStaticOutbound = "[]"' > node/tools/docker-config/nodes-config/node_$$n/config.tmp && \ + mv -f node/tools/docker-config/nodes-config/node_$$n/config.tmp node/tools/docker-config/nodes-config/node_$$n/config.json; \ + done diff --git a/compose.yaml b/compose.yaml index c62357cf..46edd5c3 100644 --- a/compose.yaml +++ b/compose.yaml @@ -2,7 +2,9 @@ version: "3.9" services: node-1: - build: . + build: + context: . + target: runtime image: consensus-node container_name: consensus-node-1 ports: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index ee53e262..6b8977c1 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,6 +1,6 @@ #!/bin/bash # This file works as an entrypoint of the docker container running the node binary copied inside of it. -cd $(hostname -i):3054 +cd docker_config/${NODE_ID} export RUST_LOG=INFO -../executor +../../executor $@ diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index b96a4835..00000000 --- a/entrypoint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -cd $(hostname -i):3054 -export RUST_LOG=INFO -../executor diff --git a/k8s_entrypoint.sh b/k8s_entrypoint.sh new file mode 100644 index 00000000..8f6f498f --- /dev/null +++ b/k8s_entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# This file works as an entrypoint of the kubernetes cluster running the node binary copied inside of it. + +cd k8s_config/${NODE_ID} +export RUST_LOG=INFO +../../executor $@ diff --git a/node/Cargo.lock b/node/Cargo.lock index 2484f909..715619e6 100644 --- a/node/Cargo.lock +++ b/node/Cargo.lock @@ -52,6 +52,19 @@ dependencies = [ "subtle", ] +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -61,6 +74,27 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anes" version = "0.1.6" @@ -83,9 +117,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -144,6 +178,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "getrandom", + "instant", + "rand 0.8.5", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -357,6 +402,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "chrono" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.0", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -408,9 +466,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" dependencies = [ "clap_builder", "clap_derive", @@ -418,21 +476,21 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.0", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", @@ -442,9 +500,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -463,6 +521,22 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -561,9 +635,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" dependencies = [ "cfg-if", "cpufeatures", @@ -587,6 +661,41 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "darling" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.48", +] + +[[package]] +name = "darling_macro" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.48", +] + [[package]] name = "der" version = "0.7.8" @@ -606,6 +715,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "diff" version = "0.1.13" @@ -638,6 +758,12 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + [[package]] name = "ed25519" version = "2.2.3" @@ -650,9 +776,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", @@ -730,9 +856,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" [[package]] name = "fixedbitset" @@ -746,6 +872,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -760,6 +895,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -782,6 +918,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -906,6 +1053,10 @@ name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "heck" @@ -915,9 +1066,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" [[package]] name = "hex" @@ -956,6 +1107,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -992,6 +1149,63 @@ 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", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "im" version = "15.1.0" @@ -1025,14 +1239,23 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "is-terminal" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +checksum = "fe8f25ce1159c7740ff0b9b2f5cdf4a8428742ba7c112b9f20f22cd5219c7dab" dependencies = [ "hermit-abi", - "rustix", + "libc", "windows-sys 0.52.0", ] @@ -1062,22 +1285,47 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" +dependencies = [ + "serde", + "serde_json", + "thiserror", + "treediff", +] + +[[package]] +name = "jsonpath-rust" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96acbc6188d3bd83519d053efec756aa4419de62ec47be7f28dec297f7dc9eb0" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror", +] + [[package]] name = "jsonrpsee" version = "0.21.0" @@ -1149,6 +1397,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "k8s-openapi" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301f367a36090b7dfdaac248ee3ed4f14a6a8292e7bec0f1c5e6e2e1f181cd33" +dependencies = [ + "base64 0.21.7", + "chrono", + "serde", + "serde-value", + "serde_json", +] + [[package]] name = "keccak" version = "0.1.5" @@ -1158,6 +1419,112 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "kube" +version = "0.88.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "462fe330a0617b276ec864c2255810adcdf519ecb6844253c54074b2086a97bc" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "0.88.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe0d65dd6f3adba29cfb84f19dfe55449c7f6c35425f9d8294bec40313e0b64" +dependencies = [ + "base64 0.21.7", + "bytes", + "chrono", + "either", + "futures", + "home", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-timeout", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem", + "pin-project", + "rustls", + "rustls-pemfile", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.88.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6b42844e9172f631b8263ea9ce003b9251da13beb1401580937ad206dd82f4c" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "once_cell", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.88.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5b5a111ee287bd237b8190b8c39543ea9fd22f79e9c32a36c24e08234bcda22" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.48", +] + +[[package]] +name = "kube-runtime" +version = "0.88.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc06275064c81056fbb28ea876b3fb339d970e8132282119359afca0835c0ea" +dependencies = [ + "ahash", + "async-trait", + "backoff", + "derivative", + "futures", + "hashbrown", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "smallvec", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1335,6 +1702,12 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1343,9 +1716,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -1406,19 +1779,18 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -1460,6 +1832,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "ordered-float" version = "2.10.1" @@ -1516,6 +1894,67 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pem" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pest_meta" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -1959,6 +2398,20 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -2009,6 +2462,49 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[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", +] + +[[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-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.16" @@ -2024,12 +2520,88 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "scopeguard" 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 = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.21" @@ -2066,6 +2638,17 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_json" version = "1.0.113" @@ -2077,6 +2660,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha-1" version = "0.9.8" @@ -2211,6 +2807,12 @@ dependencies = [ "sha-1", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.7.3" @@ -2233,6 +2835,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "subtle" version = "2.5.0" @@ -2263,13 +2871,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] @@ -2335,9 +2942,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe80ced77cbfb4cb91a94bf72b378b4b6791a0d9b7f09d0be747d1bdff4e68bd" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "num-conv", @@ -2364,9 +2971,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.35.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -2381,6 +2988,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.2.0" @@ -2392,6 +3009,27 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "tokio-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" +dependencies = [ + "pin-project", + "rand 0.8.5", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -2414,6 +3052,7 @@ dependencies = [ "futures-io", "futures-sink", "pin-project-lite", + "slab", "tokio", "tracing", ] @@ -2424,6 +3063,33 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "base64 0.21.7", + "bitflags 2.4.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "mime", + "pin-project-lite", "tower-layer", "tower-service", "tracing", @@ -2503,6 +3169,15 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "treediff" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d127780145176e2b5d16611cc25a900150e86e9fd79d3bde6ff3a37359c9cb5" +dependencies = [ + "serde_json", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -2515,6 +3190,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -2537,6 +3218,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "utf8parse" version = "0.2.1" @@ -2623,9 +3316,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2633,9 +3326,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -2648,9 +3341,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2658,9 +3351,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -2671,15 +3364,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -2728,6 +3421,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2866,6 +3568,26 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "zeroize" version = "1.7.0" @@ -3062,6 +3784,8 @@ dependencies = [ "async-trait", "clap", "jsonrpsee", + "k8s-openapi", + "kube", "prost", "rand 0.8.5", "rocksdb", @@ -3069,6 +3793,7 @@ dependencies = [ "serde_json", "tempfile", "tokio", + "tokio-retry", "tower", "tracing", "tracing-subscriber", diff --git a/node/Cargo.toml b/node/Cargo.toml index 9c147dc8..065b109e 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -80,10 +80,13 @@ test-casing = "0.1.0" thiserror = "1.0.40" time = "0.3.23" tokio = { version = "1.34.0", features = ["full"] } +tokio-retry = "0.3.0" tracing = { version = "0.1.37", features = ["attributes"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter", "fmt"] } jsonrpsee = { version = "0.21.0", features = ["server"] } -tower = { version = "0.4.13" } +tower = "0.4.13" +kube = { version = "0.88.1", features = ["runtime", "derive"] } +k8s-openapi = { version = "0.21.0", features = ["latest"] } # Note that "bench" profile inherits from "release" profile and # "test" profile inherits from "dev" profile. diff --git a/node/deny.toml b/node/deny.toml index 59974629..7effc437 100644 --- a/node/deny.toml +++ b/node/deny.toml @@ -40,6 +40,18 @@ allow = [ "MPL-2.0", ] +[[licenses.clarify]] +name = "ring" +# SPDX considers OpenSSL to encompass both the OpenSSL and SSLeay licenses +# https://spdx.org/licenses/OpenSSL.html +# ISC - Both BoringSSL and ring use this for their new files +# MIT - "Files in third_party/ have their own licenses, as described therein. The MIT +# license, for third_party/fiat, which, unlike other third_party directories, is +# compiled into non-test libraries, is included below." +# OpenSSL - Obviously +expression = "MIT" +license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] + [bans] # Lint level for when multiple versions of the same crate are detected multiple-versions = "deny" @@ -61,6 +73,9 @@ skip = [ { name = "block-buffer", version = "0.9.0" }, { name = "digest", version = "0.10.7" }, + # Old versions required by kube. + { name = "strsim", version = "0.10.0" }, + # Old versions required by criterion. { name = "itertools", version = "0.10.5" }, ] diff --git a/node/libs/concurrency/Cargo.toml b/node/libs/concurrency/Cargo.toml index 2597d7fa..e305f684 100644 --- a/node/libs/concurrency/Cargo.toml +++ b/node/libs/concurrency/Cargo.toml @@ -23,4 +23,4 @@ vise.workspace = true workspace = true [dev-dependencies] -assert_matches.workspace = true \ No newline at end of file +assert_matches.workspace = true diff --git a/node/tools/Cargo.toml b/node/tools/Cargo.toml index f9b5adb7..93e80fa4 100644 --- a/node/tools/Cargo.toml +++ b/node/tools/Cargo.toml @@ -26,11 +26,14 @@ rocksdb.workspace = true serde.workspace = true serde_json.workspace = true tokio.workspace = true +tokio-retry.workspace = true tracing.workspace = true tracing-subscriber.workspace = true vise-exporter.workspace = true jsonrpsee.workspace = true tower.workspace = true +kube.workspace = true +k8s-openapi.workspace = true [dev-dependencies] tempfile.workspace = true @@ -44,3 +47,7 @@ workspace = true [[bin]] name = "executor" path = "src/main.rs" + +[[bin]] +name = "deployer" +path = "src/bin/deployer.rs" diff --git a/node/tools/README.md b/node/tools/README.md index 833ce1ba..b6349665 100644 --- a/node/tools/README.md +++ b/node/tools/README.md @@ -12,13 +12,13 @@ These instructions guide you through the process of setting up and running a tes make nodes_config ``` - This command establishes a directory named `nodes-config` and creates a folder for each address listed in the `.txt` file, providing necessary configuration files for the respective node. + This command creates a directory named `nodes-config` and generates a folder for each address listed in the `.txt` file with the name `node_{NODE_NUMBER}`, providing essential configuration files for the corresponding node. The `NODE_NUMBER` is simply a numerical identifier for each node. ```bash - make node IP= + make node NODE= ``` - The default value for this command is `127.0.0.1:3054`. Note that running this command will take control of the terminal. + The default value for this command is set to `0` for launching the initial node, and you can increment the number for subsequent nodes. Note that running this command will take control of the terminal. ## Dockerized Setup @@ -53,3 +53,51 @@ make clean_docker ``` > This deletes the generated images and containers, requiring regeneration. + + +## Running in minikube + +To run a number of nodes locally in minikube, first we need to build the binary: + +```bash +make docker_build_executor +``` + +This command will create the `executor` binary to be included in a docker image. + +Before running the deployment script, ensure minikube is installed and running: + +```bash +minikube start +``` + +Then run + +```bash +make start_k8s_nodes NODES= SEED_NODES= +``` + +Here, `NODES` is the desired total amount of nodes to run in the k8s cluster (defaults to 4 if omitted), and `SEED_NODES` is the amount of those nodes to be deployed first as seed nodes (defaults to 1). + +This command will: +- Generate the configuration files for each node (this step may change in the future, as we may not need to include configuration files in the images) +- Build a docker image with the configuration files and the binary created in previous step +- Deploy the initial seed nodes +- Obtain the internal IP addresses of the seed nodes +- Deploy the rest of the nodes providing the seed nodes IP addresses to establish the connections + +You may run + +```bash +minikube dashboard +``` + +To start the minikube dashboard in order to inspect the deployed pods. Remember to use `consensus` namespace to find all consensus related infrastructure. + +Finally to clean everything up + +```bash +minikube delete --all +``` + +will remove all namespaces, deployments and pods from the minikube environment. \ No newline at end of file diff --git a/node/tools/docker-config/addresses.txt b/node/tools/docker-config/addresses.txt new file mode 100644 index 00000000..7236c599 --- /dev/null +++ b/node/tools/docker-config/addresses.txt @@ -0,0 +1 @@ +0.0.0.0:3054 diff --git a/node/tools/src/bin/deployer.rs b/node/tools/src/bin/deployer.rs new file mode 100644 index 00000000..ccfa2310 --- /dev/null +++ b/node/tools/src/bin/deployer.rs @@ -0,0 +1,155 @@ +//! Deployer for the kubernetes cluster. +use std::net::SocketAddr; +use std::str::FromStr; +use std::{fs, path::PathBuf}; + +use anyhow::Context; +use clap::{Parser, Subcommand}; +use zksync_consensus_crypto::{Text, TextFmt}; +use zksync_consensus_roles::{node, validator}; +use zksync_consensus_tools::{k8s, AppConfig, NodeAddr, NODES_PORT}; + +/// K8s namespace for consensus nodes. +const NAMESPACE: &str = "consensus"; + +/// Command line arguments. +#[derive(Debug, Parser)] +#[command(name = "deployer")] +struct DeployerCLI { + /// Subcommand to run. + #[command(subcommand)] + command: DeployerCommands, +} + +/// Subcommand arguments. +#[derive(Debug, Parser)] +struct SubCommandArgs { + /// Number of total nodes to deploy. + #[arg(long)] + nodes: usize, + /// Number of seed nodes to deploy. + #[arg(long)] + seed_nodes: Option, +} + +/// Subcommands. +#[derive(Subcommand, Debug)] +enum DeployerCommands { + /// Generate configs for the nodes. + GenerateConfig(SubCommandArgs), + /// Deploy the nodes. + Deploy(SubCommandArgs), +} + +/// Generates config for the nodes to run in the kubernetes cluster +/// Creates a directory for each node in the parent k8s_configs directory. +fn generate_config(nodes: usize) -> anyhow::Result<()> { + assert!(nodes > 0, "at least 1 node has to be specified"); + + // Generate the keys for all the replicas. + let rng = &mut rand::thread_rng(); + + let setup = validator::testonly::Setup::new(rng, nodes); + let validator_keys = setup.keys.clone(); + + // Each node will have `gossip_peers` outbound peers. + let peers = 2; + + let node_keys: Vec = (0..nodes).map(|_| node::SecretKey::generate()).collect(); + + let default_config = AppConfig::default_for(setup.genesis.clone()); + + let mut cfgs: Vec<_> = (0..nodes).map(|_| default_config.clone()).collect(); + + // Construct a gossip network with optimal diameter. + for (i, node) in node_keys.iter().enumerate() { + for j in 0..peers { + let next = (i * peers + j + 1) % nodes; + cfgs[next].add_gossip_static_inbound(node.public()); + } + } + + let manifest_path = std::env::var("CARGO_MANIFEST_DIR")?; + let root = PathBuf::from(manifest_path).join("k8s_configs"); + let _ = fs::remove_dir_all(&root); + for (i, cfg) in cfgs.into_iter().enumerate() { + let node_config_dir = root.join(format!("consensus-node-{i:0>2}")); + fs::create_dir_all(&node_config_dir) + .with_context(|| format!("create_dir_all({:?})", node_config_dir))?; + + cfg.write_to_file(&node_config_dir)?; + fs::write( + node_config_dir.join("validator_key"), + &TextFmt::encode(&validator_keys[i]), + ) + .context("fs::write()")?; + fs::write( + node_config_dir.join("node_key"), + &TextFmt::encode(&node_keys[i]), + ) + .context("fs::write()")?; + } + + Ok(()) +} + +/// Deploys the nodes to the kubernetes cluster. +async fn deploy(nodes: usize, seed_nodes: Option) -> anyhow::Result<()> { + let client = k8s::get_client().await?; + k8s::create_or_reuse_namespace(&client, NAMESPACE).await?; + + let seed_nodes = seed_nodes.unwrap_or(1); + + // deploy seed peer(s) + for i in 0..seed_nodes { + k8s::deploy_node( + &client, + i, + true, + vec![], // Seed peers don't have other peer information + NAMESPACE, + ) + .await?; + } + + // obtain seed peer(s) IP(s) + let peer_ips = k8s::get_seed_node_addrs(&client, seed_nodes, NAMESPACE).await?; + + let mut peers = vec![]; + + for i in 0..seed_nodes { + let node_id = &format!("consensus-node-{i:0>2}"); + let node_key = read_node_key_from_config(node_id)?; + let address = peer_ips.get(node_id).context("IP address not found")?; + peers.push(NodeAddr { + key: node_key.public(), + addr: SocketAddr::from_str(&format!("{address}:{NODES_PORT}"))?, + }); + } + + // deploy the rest of nodes + for i in seed_nodes..nodes { + k8s::deploy_node(&client, i, false, peers.clone(), NAMESPACE).await?; + } + + Ok(()) +} + +/// Obtain node key from config file. +fn read_node_key_from_config(node_id: &String) -> anyhow::Result { + let manifest_path = std::env::var("CARGO_MANIFEST_DIR")?; + let root = PathBuf::from(manifest_path).join("k8s_configs"); + let node_key_path = root.join(node_id).join("node_key"); + let key = fs::read_to_string(node_key_path).context("failed reading file")?; + Text::new(&key).decode().context("failed decoding key") +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let DeployerCLI { command } = DeployerCLI::parse(); + + match command { + DeployerCommands::GenerateConfig(args) => generate_config(args.nodes), + DeployerCommands::Deploy(args) => deploy(args.nodes, args.seed_nodes).await, + } +} diff --git a/node/tools/src/bin/localnet_config.rs b/node/tools/src/bin/localnet_config.rs index 27b95f15..e5ef14bb 100644 --- a/node/tools/src/bin/localnet_config.rs +++ b/node/tools/src/bin/localnet_config.rs @@ -7,24 +7,6 @@ use zksync_consensus_crypto::TextFmt; use zksync_consensus_roles::{node, validator}; use zksync_consensus_tools::AppConfig; -/// Encodes a generated proto message to json for arbitrary ProtoFmt. -fn encode_json(x: &T) -> String { - let mut s = serde_json::Serializer::pretty(vec![]); - zksync_protobuf::serde::serialize(x, &mut s).unwrap(); - String::from_utf8(s.into_inner()).unwrap() -} - -/// Replaces IP of the address with UNSPECIFIED (aka INADDR_ANY) of the corresponding IP type. -/// Opening a listener socket with an UNSPECIFIED IP, means that the new connections -/// on any network interface of the VM will be accepted. -fn with_unspecified_ip(addr: SocketAddr) -> SocketAddr { - let unspecified_ip = match addr { - SocketAddr::V4(_) => std::net::Ipv4Addr::UNSPECIFIED.into(), - SocketAddr::V6(_) => std::net::Ipv6Addr::UNSPECIFIED.into(), - }; - SocketAddr::new(unspecified_ip, addr.port()) -} - /// Command line arguments. #[derive(Debug, Parser)] struct Args { @@ -56,6 +38,7 @@ fn main() -> anyhow::Result<()> { ); } assert!(!addrs.is_empty(), "at least 1 address has to be specified"); + let metrics_server_addr = args .metrics_server_port .map(|port| SocketAddr::new(std::net::Ipv4Addr::UNSPECIFIED.into(), port)); @@ -65,47 +48,37 @@ fn main() -> anyhow::Result<()> { let setup = validator::testonly::Setup::new(rng, addrs.len()); let validator_keys = setup.keys.clone(); - let node_keys: Vec = (0..addrs.len()).map(|_| rng.gen()).collect(); // Each node will have `gossip_peers` outbound peers. let nodes = addrs.len(); let peers = 2; - let mut cfgs: Vec<_> = (0..nodes) - .map(|i| AppConfig { - server_addr: with_unspecified_ip(addrs[i]), - public_addr: addrs[i], - metrics_server_addr, + let node_keys: Vec = (0..nodes).map(|_| rng.gen()).collect(); - genesis: setup.genesis.clone(), - max_payload_size: args.payload_size, + let mut default_config = AppConfig::default_for(setup.genesis.clone()); - gossip_dynamic_inbound_limit: 0, - gossip_static_inbound: [].into(), - gossip_static_outbound: [].into(), - }) + if let Some(metrics_server_addr) = metrics_server_addr { + default_config.with_metrics_server_addr(metrics_server_addr); + } + let mut cfgs: Vec<_> = (0..nodes) + .map(|i| default_config.with_public_addr(addrs[i]).clone()) .collect(); // Construct a gossip network with optimal diameter. for i in 0..nodes { for j in 0..peers { let next = (i * peers + j + 1) % nodes; - cfgs[i] - .gossip_static_outbound - .insert(node_keys[next].public(), addrs[next]); - cfgs[next] - .gossip_static_inbound - .insert(node_keys[i].public()); + cfgs[i].add_gossip_static_outbound(node_keys[next].public(), addrs[next]); + cfgs[next].add_gossip_static_inbound(node_keys[i].public()); } } for (i, cfg) in cfgs.into_iter().enumerate() { // Recreate the directory for the node's config. - let root = args.output_dir.join(addrs[i].to_string()); + let root = args.output_dir.join(cfg.public_addr.to_string()); let _ = fs::remove_dir_all(&root); fs::create_dir_all(&root).with_context(|| format!("create_dir_all({:?})", root))?; - - fs::write(root.join("config.json"), encode_json(&cfg)).context("fs::write()")?; + cfg.write_to_file(&root)?; fs::write( root.join("validator_key"), &TextFmt::encode(&validator_keys[i]), diff --git a/node/tools/src/config.rs b/node/tools/src/config.rs index 9c9e5aff..53f608e2 100644 --- a/node/tools/src/config.rs +++ b/node/tools/src/config.rs @@ -1,10 +1,13 @@ //! Node configuration. use crate::{proto, store}; use anyhow::Context as _; +use serde_json::{ser::Formatter, Serializer}; use std::{ collections::{HashMap, HashSet}, fs, + net::{Ipv4Addr, SocketAddr}, path::{Path, PathBuf}, + str::FromStr, }; use zksync_concurrency::ctx; use zksync_consensus_bft as bft; @@ -14,6 +17,9 @@ use zksync_consensus_roles::{node, validator}; use zksync_consensus_storage::{BlockStore, BlockStoreRunner}; use zksync_protobuf::{read_required, required, serde::Serde, ProtoFmt}; +/// Ports for the nodes to listen on kubernetes pod. +pub const NODES_PORT: u16 = 3054; + /// Decodes a proto message from json for arbitrary ProtoFmt. pub fn decode_json(json: &str) -> anyhow::Result { let mut d = serde_json::Deserializer::from_str(json); @@ -22,11 +28,26 @@ pub fn decode_json(json: &str) -> anyhow::Result Ok(p) } +/// Encodes a generated proto message to json for arbitrary ProtoFmt. +pub(crate) fn encode_json(x: &T) -> String { + let s = serde_json::Serializer::pretty(vec![]); + encode_with_serializer(x, s) +} + +/// Encodes a generated proto message for arbitrary ProtoFmt with provided serializer. +pub(crate) fn encode_with_serializer( + x: &T, + mut serializer: Serializer, F>, +) -> String { + T::serialize(x, &mut serializer).unwrap(); + String::from_utf8(serializer.into_inner()).unwrap() +} + /// Pair of (public key, ip address) for a gossip network node. #[derive(Debug, Clone)] pub struct NodeAddr { pub key: node::PublicKey, - pub addr: std::net::SocketAddr, + pub addr: SocketAddr, } impl ProtoFmt for NodeAddr { @@ -48,18 +69,18 @@ impl ProtoFmt for NodeAddr { /// Node configuration including executor configuration, optional validator configuration, /// and application-specific settings (e.g. metrics scraping). -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub struct AppConfig { - pub server_addr: std::net::SocketAddr, - pub public_addr: std::net::SocketAddr, - pub metrics_server_addr: Option, + pub server_addr: SocketAddr, + pub public_addr: SocketAddr, + pub metrics_server_addr: Option, pub genesis: validator::Genesis, pub max_payload_size: usize, pub gossip_dynamic_inbound_limit: usize, pub gossip_static_inbound: HashSet, - pub gossip_static_outbound: HashMap, + pub gossip_static_outbound: HashMap, } impl ProtoFmt for AppConfig { @@ -183,6 +204,76 @@ impl<'a> ConfigPaths<'a> { } } +impl AppConfig { + pub fn default_for(genesis: validator::Genesis) -> AppConfig { + Self { + server_addr: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), NODES_PORT), + public_addr: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), NODES_PORT), + metrics_server_addr: None, + + genesis, + max_payload_size: 1000000, + + gossip_dynamic_inbound_limit: 2, + gossip_static_inbound: [].into(), + gossip_static_outbound: [].into(), + } + } + + pub fn with_server_addr(&mut self, server_addr: SocketAddr) -> &mut Self { + self.server_addr = server_addr; + self + } + + pub fn with_public_addr(&mut self, public_addr: SocketAddr) -> &mut Self { + self.public_addr = public_addr; + self + } + + pub fn with_metrics_server_addr(&mut self, metrics_server_addr: SocketAddr) -> &mut Self { + self.metrics_server_addr = Some(metrics_server_addr); + self + } + + pub fn with_gossip_dynamic_inbound_limit( + &mut self, + gossip_dynamic_inbound_limit: usize, + ) -> &mut Self { + self.gossip_dynamic_inbound_limit = gossip_dynamic_inbound_limit; + self + } + + pub fn add_gossip_static_outbound( + &mut self, + key: node::PublicKey, + addr: SocketAddr, + ) -> &mut Self { + self.gossip_static_outbound.insert(key, addr); + self + } + + pub fn add_gossip_static_inbound(&mut self, key: node::PublicKey) -> &mut Self { + self.gossip_static_inbound.insert(key); + self + } + + pub fn write_to_file(self, path: &Path) -> anyhow::Result<()> { + fs::write(path.join("config.json"), encode_json(&Serde(self))).context("fs::write()") + } + + pub fn with_max_payload_size(&mut self, max_payload_size: usize) -> &mut Self { + self.max_payload_size = max_payload_size; + self + } + + pub fn check_public_addr(&mut self) -> anyhow::Result<()> { + if let Ok(public_addr) = std::env::var("PUBLIC_ADDR") { + self.public_addr = SocketAddr::from_str(&format!("{public_addr}:{NODES_PORT}"))?; + } + Ok(()) + } +} + impl Configs { pub async fn make_executor( &self, diff --git a/node/tools/src/k8s.rs b/node/tools/src/k8s.rs new file mode 100644 index 00000000..50bf005f --- /dev/null +++ b/node/tools/src/k8s.rs @@ -0,0 +1,222 @@ +use crate::{config, NodeAddr}; +use anyhow::{anyhow, Context}; +use k8s_openapi::api::{ + apps::v1::Deployment, + core::v1::{Namespace, Pod}, +}; +use kube::{ + api::{ListParams, PostParams}, + core::ObjectList, + Api, Client, ResourceExt, +}; +use serde_json::json; +use std::collections::HashMap; +use tokio_retry::strategy::FixedInterval; +use tokio_retry::Retry; +use tracing::log::info; +use zksync_protobuf::serde::Serde; + +/// Get a kube client +pub async fn get_client() -> anyhow::Result { + Ok(Client::try_default().await?) +} + +/// Creates a namespace in k8s cluster +pub async fn create_or_reuse_namespace(client: &Client, name: &str) -> anyhow::Result<()> { + let namespaces: Api = Api::all(client.clone()); + match namespaces.get_opt(name).await? { + None => { + let namespace: Namespace = serde_json::from_value(json!({ + "apiVersion": "v1", + "kind": "Namespace", + "metadata": { + "name": name, + "labels": { + "name": name + } + } + }))?; + + let namespaces: Api = Api::all(client.clone()); + let post_params = PostParams::default(); + let result = namespaces.create(&post_params, &namespace).await?; + + info!( + "Namespace: {} ,created", + result + .metadata + .name + .context("Name not defined in metadata")? + ); + Ok(()) + } + Some(consensus_namespace) => { + info!( + "Namespace: {} ,already exists", + consensus_namespace + .metadata + .name + .context("Name not defined in metadata")? + ); + Ok(()) + } + } +} + +/// Creates a deployment +pub async fn deploy_node( + client: &Client, + node_index: usize, + is_seed: bool, + peers: Vec, + namespace: &str, +) -> anyhow::Result<()> { + let cli_args = get_cli_args(peers); + let node_name = format!("consensus-node-{node_index:0>2}"); + let deployment: Deployment = serde_json::from_value(json!({ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": node_name, + "namespace": namespace + }, + "spec": { + "selector": { + "matchLabels": { + "app": node_name + } + }, + "replicas": 1, + "template": { + "metadata": { + "labels": { + "app": node_name, + "id": node_name, + "seed": is_seed.to_string() + } + }, + "spec": { + "containers": [ + { + "name": node_name, + "image": "consensus-node", + "env": [ + { + "name": "NODE_ID", + "value": node_name + }, + { + "name": "PUBLIC_ADDR", + "valueFrom": { + "fieldRef": { + "fieldPath": "status.podIP" + } + } + } + ], + "command": ["./k8s_entrypoint.sh"], + "args": cli_args, + "imagePullPolicy": "Never", + "ports": [ + { + "containerPort": config::NODES_PORT + }, + { + "containerPort": 3154 + } + ], + "livenessProbe": { + "httpGet": { + "path": "/health", + "port": 3154 + } + }, + "readinessProbe": { + "httpGet": { + "path": "/health", + "port": 3154 + } + } + } + ] + } + } + } + }))?; + + let deployments: Api = Api::namespaced(client.clone(), namespace); + let post_params = PostParams::default(); + let result = deployments.create(&post_params, &deployment).await?; + + info!( + "Deployment: {} , created", + result + .metadata + .name + .context("Name not defined in metadata")? + ); + Ok(()) +} + +/// Returns a HashMap with mapping: node_id -> IP address +pub async fn get_seed_node_addrs( + client: &Client, + amount: usize, + namespace: &str, +) -> anyhow::Result> { + let mut seed_nodes = HashMap::new(); + let pods: Api = Api::namespaced(client.clone(), namespace); + + // Will retry 15 times during 15 seconds to allow pods to start and obtain an IP + let retry_strategy = FixedInterval::from_millis(1000).take(15); + let pod_list = Retry::spawn(retry_strategy, || get_seed_pods(&pods, amount)).await?; + + for p in pod_list { + let node_id = p.labels()["id"].clone(); + seed_nodes.insert( + node_id, + p.status + .context("Status not present")? + .pod_ip + .context("Pod IP address not present")?, + ); + } + Ok(seed_nodes) +} + +async fn get_seed_pods(pods: &Api, amount: usize) -> anyhow::Result> { + let lp = ListParams::default().labels("seed=true"); + let p = pods.list(&lp).await?; + if p.items.len() == amount && p.iter().all(is_pod_running) { + Ok(p) + } else { + Err(anyhow!("Pods are not ready")) + } +} + +fn is_pod_running(pod: &Pod) -> bool { + if let Some(status) = &pod.status { + if let Some(phase) = &status.phase { + return phase == "Running"; + } + } + false +} + +fn get_cli_args(peers: Vec) -> Vec { + if peers.is_empty() { + [].to_vec() + } else { + [ + "--add-gossip-static-outbound".to_string(), + config::encode_with_serializer( + &peers + .iter() + .map(|e| Serde(e.clone())) + .collect::>>(), + serde_json::Serializer::new(vec![]), + ), + ] + .to_vec() + } +} diff --git a/node/tools/src/lib.rs b/node/tools/src/lib.rs index f84a00f8..e0c8d2a1 100644 --- a/node/tools/src/lib.rs +++ b/node/tools/src/lib.rs @@ -1,6 +1,7 @@ //! CLI tools for the consensus node. #![allow(missing_docs)] mod config; +pub mod k8s; mod proto; mod rpc; mod store; @@ -8,5 +9,5 @@ mod store; #[cfg(test)] mod tests; -pub use config::{decode_json, AppConfig, ConfigPaths, NodeAddr}; +pub use config::{decode_json, AppConfig, ConfigPaths, NodeAddr, NODES_PORT}; pub use rpc::server::RPCServer; diff --git a/node/tools/src/main.rs b/node/tools/src/main.rs index e1f7837f..9dd4b335 100644 --- a/node/tools/src/main.rs +++ b/node/tools/src/main.rs @@ -42,7 +42,7 @@ struct Args { rpc_port: Option, /// IP address and key of the seed peers. #[arg(long)] - add_gossip_static_outbound: NodeAddrs, + add_gossip_static_outbound: Option, } impl Args { @@ -101,13 +101,16 @@ async fn main() -> anyhow::Result<()> { .load() .context("config_paths().load()")?; + // if `PUBLIC_ADDR` env var is set, use it to override publicAddr in config + configs.app.check_public_addr().context("Public Address")?; + // Add gossipStaticOutbound pairs from cli to config - configs.app.gossip_static_outbound.extend( - args.add_gossip_static_outbound - .0 - .into_iter() - .map(|e| (e.0.key, e.0.addr)), - ); + if let Some(addrs) = args.add_gossip_static_outbound { + configs + .app + .gossip_static_outbound + .extend(addrs.0.into_iter().map(|e| (e.0.key, e.0.addr))); + } let (executor, runner) = configs .make_executor(ctx) @@ -120,7 +123,10 @@ async fn main() -> anyhow::Result<()> { } else { rpc_addr.set_port(rpc_addr.port() + 100); } - let rpc_server = RPCServer::new(rpc_addr); + + // cloning configuration to let RPCServer show it + // TODO this should be queried in real time instead, to reflect any possible change in config + let rpc_server = RPCServer::new(rpc_addr, configs.app.clone()); // Initialize the storage. scope::run!(ctx, |ctx, s| async { diff --git a/node/tools/src/rpc/methods/config.rs b/node/tools/src/rpc/methods/config.rs new file mode 100644 index 00000000..f03e9353 --- /dev/null +++ b/node/tools/src/rpc/methods/config.rs @@ -0,0 +1,48 @@ +//! Peers method for RPC server. +use crate::{config::encode_json, decode_json, AppConfig}; + +use super::RPCMethod; +use jsonrpsee::types::{error::ErrorCode, Params}; +use std::fs::{self}; +use zksync_protobuf::serde::Serde; + +/// Config method for RPC server. +pub(crate) struct ConfigInfo; + +// RPCMethod trait should be more general to allow external parameters like this case +// TODO fix the trait and implement this code in it +impl ConfigInfo { + /// Provide the node's config information + pub(crate) fn info(config: AppConfig) -> Result { + // This may change in the future since we are assuming that the executor binary is being run inside the config directory. + Ok(serde_json::json!({ + "config": encode_json(&Serde(config)) + })) + } +} + +impl RPCMethod for ConfigInfo { + /// Config response for /config endpoint. + fn callback(_params: Params) -> Result { + // This may change in the future since we are assuming that the executor binary is being run inside the config directory. + let node_config = + fs::read_to_string("config.json").map_err(|_e| ErrorCode::InternalError)?; + let node_config = decode_json::>(&node_config) + .map_err(|_e| ErrorCode::InternalError)? + .0; + let config = encode_json(&Serde(node_config)); + Ok(serde_json::json!({ + "config": config + })) + } + + /// Config method name. + fn method() -> &'static str { + "config" + } + + /// Method path for GET requests. + fn path() -> &'static str { + "/config" + } +} diff --git a/node/tools/src/rpc/methods/mod.rs b/node/tools/src/rpc/methods/mod.rs index 2cac6a52..ab8f2fee 100644 --- a/node/tools/src/rpc/methods/mod.rs +++ b/node/tools/src/rpc/methods/mod.rs @@ -10,5 +10,6 @@ pub(crate) trait RPCMethod { fn path() -> &'static str; } +pub(crate) mod config; pub(crate) mod health_check; pub(crate) mod peers; diff --git a/node/tools/src/rpc/server.rs b/node/tools/src/rpc/server.rs index 6d2d5131..3b66dfa0 100644 --- a/node/tools/src/rpc/server.rs +++ b/node/tools/src/rpc/server.rs @@ -1,4 +1,6 @@ -use super::methods::{health_check::HealthCheck, peers::PeersInfo, RPCMethod}; +use crate::AppConfig; + +use super::methods::{config::ConfigInfo, health_check::HealthCheck, peers::PeersInfo, RPCMethod}; use jsonrpsee::server::{middleware::http::ProxyGetRequestLayer, RpcModule, Server}; use std::net::SocketAddr; use zksync_concurrency::{ctx, scope}; @@ -7,11 +9,13 @@ use zksync_concurrency::{ctx, scope}; pub struct RPCServer { /// IP address to bind to. ip_address: SocketAddr, + /// AppConfig + config: AppConfig, } impl RPCServer { - pub fn new(ip_address: SocketAddr) -> Self { - Self { ip_address } + pub fn new(ip_address: SocketAddr, config: AppConfig) -> Self { + Self { ip_address, config } } /// Runs the RPC server. @@ -26,6 +30,10 @@ impl RPCServer { .layer(ProxyGetRequestLayer::new( PeersInfo::path(), PeersInfo::method(), + )?) + .layer(ProxyGetRequestLayer::new( + ConfigInfo::path(), + ConfigInfo::method(), )?); let server = Server::builder() @@ -39,6 +47,12 @@ impl RPCServer { })?; module.register_method(PeersInfo::method(), |params, _| PeersInfo::callback(params))?; + // TODO find a better way to implement this as I had to clone the clone and move it to pass the borrow checker + let config = self.config.clone(); + module.register_method(ConfigInfo::method(), move |_params, _| { + ConfigInfo::info(config.clone()) + })?; + let handle = server.start(module); scope::run!(ctx, |ctx, s| async { s.spawn_bg(async {