From c670d098324b2f5f7d5b90f7956a8a188041bbaf Mon Sep 17 00:00:00 2001 From: jedarden Date: Sat, 23 May 2026 01:53:49 -0400 Subject: [PATCH] =?UTF-8?q?P5.7=20=C2=A713.7:=20Fix=20alias=20admin=20API?= =?UTF-8?q?=20routes=20and=20reorganize=20alias=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix POST /_miroir/aliases/{name} route for alias creation (name in path) - Fix PUT /_miroir/aliases/{name} (was incorrectly using post method) - Reorganize alias module from single file to module directory: - alias/mod.rs: Core Alias and AliasRegistry implementation - alias/tests.rs: Unit tests - alias/acceptance_tests.rs: Integration/acceptance tests Co-Authored-By: Claude Opus 4.7 --- Cargo.lock | 1232 ++++++++++++++--- .../miroir-core/src/alias/acceptance_tests.rs | 314 +++++ .../src/{alias.rs => alias/mod.rs} | 95 +- crates/miroir-core/src/alias/tests.rs | 124 ++ crates/miroir-core/src/error.rs | 4 + crates/miroir-core/src/lib.rs | 1 + crates/miroir-core/src/peer_discovery.rs | 207 +++ .../src/rebalancer_worker/acceptance_tests.rs | 111 ++ crates/miroir-proxy/src/main.rs | 57 +- crates/miroir-proxy/src/routes/admin.rs | 4 +- .../miroir-proxy/src/routes/multi_search.rs | 47 +- 11 files changed, 1897 insertions(+), 299 deletions(-) create mode 100644 crates/miroir-core/src/alias/acceptance_tests.rs rename crates/miroir-core/src/{alias.rs => alias/mod.rs} (71%) create mode 100644 crates/miroir-core/src/alias/tests.rs create mode 100644 crates/miroir-core/src/peer_discovery.rs diff --git a/Cargo.lock b/Cargo.lock index 0e73921..54b871d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aead" version = "0.5.2" @@ -18,7 +33,7 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "once_cell", "version_check", "zerocopy", @@ -152,9 +167,9 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -163,9 +178,9 @@ version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -188,7 +203,7 @@ checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", - "bytes", + "bytes 1.11.1", "futures-util", "http", "http-body", @@ -207,7 +222,7 @@ dependencies = [ "serde_path_to_error", "serde_urlencoded", "sync_wrapper", - "tokio", + "tokio 1.52.1", "tower 0.5.3", "tower-layer", "tower-service", @@ -221,7 +236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", - "bytes", + "bytes 1.11.1", "futures-util", "http", "http-body", @@ -244,6 +259,21 @@ dependencies = [ "fastrand", ] +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if 1.0.4", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + [[package]] name = "base64" version = "0.21.7" @@ -323,7 +353,7 @@ checksum = "97ccca1260af6a459d75994ad5acc1651bcabcbdbc41467cc9786519ab854c30" dependencies = [ "base64 0.22.1", "bollard-stubs", - "bytes", + "bytes 1.11.1", "futures-core", "futures-util", "hex", @@ -347,11 +377,11 @@ dependencies = [ "serde_repr", "serde_urlencoded", "thiserror 2.0.18", - "tokio", + "tokio 1.52.1", "tokio-util", "tower-service", "url", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -371,6 +401,22 @@ version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "iovec", +] + [[package]] name = "bytes" version = "1.11.1" @@ -393,6 +439,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.4" @@ -411,7 +463,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cipher", "cpufeatures", ] @@ -510,9 +562,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -521,6 +573,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "colorchoice" version = "1.0.5" @@ -542,11 +603,11 @@ version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "bytes", + "bytes 1.11.1", "futures-core", "memchr", "pin-project-lite", - "tokio", + "tokio 1.52.1", "tokio-util", ] @@ -659,14 +720,40 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "crossbeam-deque" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" +dependencies = [ + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-epoch 0.9.18", + "crossbeam-utils 0.8.21", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", ] [[package]] @@ -675,7 +762,29 @@ version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "crossbeam-utils", + "crossbeam-utils 0.8.21", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "lazy_static", ] [[package]] @@ -719,10 +828,10 @@ checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", - "proc-macro2", - "quote", + "proc-macro2 1.0.106", + "quote 1.0.45", "strsim", - "syn", + "syn 2.0.117", ] [[package]] @@ -732,8 +841,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", - "quote", - "syn", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -742,12 +851,12 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if", - "crossbeam-utils", + "cfg-if 1.0.4", + "crossbeam-utils 0.8.21", "hashbrown 0.14.5", - "lock_api", + "lock_api 0.4.14", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.12", ] [[package]] @@ -804,9 +913,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -841,7 +950,18 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", +] + +[[package]] +name = "enum-as-inner" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d58266c97445680766be408285e798d3401c6d4c378ec5552e78737e681e37d" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] @@ -866,11 +986,33 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "home", "windows-sys 0.48.0", ] +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 1.0.109", + "synstructure 0.12.6", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -895,7 +1037,7 @@ version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "libc", "libredox", ] @@ -933,6 +1075,28 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags 1.3.2", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" + [[package]] name = "futures" version = "0.3.32" @@ -987,9 +1151,9 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -1031,16 +1195,27 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.4", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -1050,7 +1225,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "libc", "r-efi 5.3.0", @@ -1064,13 +1239,19 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "libc", "r-efi 6.0.0", "wasip2", "wasip3", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "glob" version = "0.3.3" @@ -1084,14 +1265,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", - "bytes", + "bytes 1.11.1", "fnv", "futures-core", "futures-sink", "http", "indexmap 2.14.0", "slab", - "tokio", + "tokio 1.52.1", "tokio-util", "tracing", ] @@ -1102,7 +1283,7 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "crunchy", "zerocopy", ] @@ -1201,13 +1382,24 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.9", +] + [[package]] name = "http" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "bytes", + "bytes 1.11.1", "itoa", ] @@ -1217,7 +1409,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "bytes", + "bytes 1.11.1", "http", ] @@ -1227,7 +1419,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "bytes", + "bytes 1.11.1", "futures-core", "http", "http-body", @@ -1253,7 +1445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", - "bytes", + "bytes 1.11.1", "futures-channel", "futures-core", "h2", @@ -1263,8 +1455,8 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "smallvec", - "tokio", + "smallvec 1.15.1", + "tokio 1.52.1", "want", ] @@ -1278,9 +1470,9 @@ dependencies = [ "hyper", "hyper-util", "pin-project-lite", - "tokio", + "tokio 1.52.1", "tower-service", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1293,7 +1485,7 @@ dependencies = [ "hyper", "hyper-util", "rustls", - "tokio", + "tokio 1.52.1", "tokio-rustls", "tower-service", "webpki-roots", @@ -1308,7 +1500,7 @@ dependencies = [ "hyper", "hyper-util", "pin-project-lite", - "tokio", + "tokio 1.52.1", "tower-service", ] @@ -1319,7 +1511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", - "bytes", + "bytes 1.11.1", "futures-channel", "futures-util", "http", @@ -1330,7 +1522,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2 0.6.3", - "tokio", + "tokio 1.52.1", "tower-service", "tracing", ] @@ -1346,7 +1538,7 @@ dependencies = [ "hyper", "hyper-util", "pin-project-lite", - "tokio", + "tokio 1.52.1", "tower-service", ] @@ -1411,7 +1603,7 @@ dependencies = [ "icu_normalizer_data", "icu_properties", "icu_provider", - "smallvec", + "smallvec 1.15.1", "zerovec", ] @@ -1468,6 +1660,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "1.1.0" @@ -1475,7 +1678,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", - "smallvec", + "smallvec 1.15.1", "utf8_iter", ] @@ -1521,6 +1724,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "ipconfig" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +dependencies = [ + "socket2 0.3.19", + "widestring", + "winapi 0.3.9", + "winreg", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -1584,7 +1808,7 @@ version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "futures-util", "once_cell", "wasm-bindgen", @@ -1601,6 +1825,16 @@ dependencies = [ "serde", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1642,6 +1876,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -1654,6 +1894,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + [[package]] name = "lock_api" version = "0.4.14" @@ -1669,12 +1918,27 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "lru-slab" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.2.0" @@ -1684,18 +1948,39 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "matchit" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -1718,6 +2003,34 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + [[package]] name = "mio" version = "1.2.0" @@ -1725,10 +2038,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.61.2", ] +[[package]] +name = "mio-uds" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +dependencies = [ + "iovec", + "libc", + "mio 0.6.23", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + [[package]] name = "miroir-core" version = "0.1.0" @@ -1756,8 +2092,9 @@ dependencies = [ "testcontainers", "testcontainers-modules", "thiserror 2.0.18", - "tokio", + "tokio 1.52.1", "tracing", + "trust-dns-resolver", "twox-hash", "urlencoding", "uuid", @@ -1776,7 +2113,7 @@ dependencies = [ "serde", "serde_json", "tempfile", - "tokio", + "tokio 1.52.1", "toml", ] @@ -1813,7 +2150,7 @@ dependencies = [ "tempfile", "testcontainers", "testcontainers-modules", - "tokio", + "tokio 1.52.1", "tower 0.5.3", "tracing", "tracing-opentelemetry", @@ -1828,7 +2165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90820618712cab19cfc46b274c6c22546a82affcb3c3bdf0f29e3db8e1bb92c0" dependencies = [ "assert-json-diff", - "bytes", + "bytes 1.11.1", "colored", "futures-core", "http", @@ -1843,7 +2180,18 @@ dependencies = [ "serde_json", "serde_urlencoded", "similar", - "tokio", + "tokio 1.52.1", +] + +[[package]] +name = "net2" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", ] [[package]] @@ -1899,6 +2247,25 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1957,7 +2324,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "thiserror 1.0.69", - "tokio", + "tokio 1.52.1", "tonic", "tracing", ] @@ -1990,7 +2357,7 @@ dependencies = [ "rand 0.8.6", "serde_json", "thiserror 1.0.69", - "tokio", + "tokio 1.52.1", "tokio-stream", "tracing", ] @@ -2011,14 +2378,40 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api 0.3.4", + "parking_lot_core 0.6.3", + "rustc_version", +] + [[package]] name = "parking_lot" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ - "lock_api", - "parking_lot_core", + "lock_api 0.4.14", + "parking_lot_core 0.9.12", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66b810a62be75176a80873726630147a5ca780cd33921e0b5709033e66b0a" +dependencies = [ + "cfg-if 0.1.10", + "cloudabi", + "libc", + "redox_syscall 0.1.57", + "rustc_version", + "smallvec 0.6.14", + "winapi 0.3.9", ] [[package]] @@ -2027,10 +2420,10 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "libc", "redox_syscall 0.5.18", - "smallvec", + "smallvec 1.15.1", "windows-link", ] @@ -2051,12 +2444,12 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.106", + "quote 1.0.45", "regex", "regex-syntax", "structmeta", - "syn", + "syn 2.0.117", ] [[package]] @@ -2099,9 +2492,9 @@ checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" dependencies = [ "pest", "pest_meta", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -2129,9 +2522,9 @@ version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -2231,8 +2624,17 @@ version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ - "proc-macro2", - "syn", + "proc-macro2 1.0.106", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", ] [[package]] @@ -2250,11 +2652,11 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "fnv", "lazy_static", "memchr", - "parking_lot", + "parking_lot 0.12.5", "protobuf", "thiserror 1.0.69", ] @@ -2284,7 +2686,7 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ - "bytes", + "bytes 1.11.1", "prost-derive", ] @@ -2296,9 +2698,9 @@ checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", "itertools 0.13.0", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -2319,7 +2721,7 @@ version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "bytes", + "bytes 1.11.1", "cfg_aliases", "pin-project-lite", "quinn-proto", @@ -2328,7 +2730,7 @@ dependencies = [ "rustls", "socket2 0.6.3", "thiserror 2.0.18", - "tokio", + "tokio 1.52.1", "tracing", "web-time", ] @@ -2339,7 +2741,7 @@ version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ - "bytes", + "bytes 1.11.1", "getrandom 0.3.4", "lru-slab", "rand 0.9.4", @@ -2368,13 +2770,22 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.106", ] [[package]] @@ -2389,6 +2800,19 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + [[package]] name = "rand" version = "0.8.6" @@ -2410,6 +2834,16 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -2430,6 +2864,15 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -2448,6 +2891,15 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + [[package]] name = "rand_xorshift" version = "0.4.0" @@ -2473,8 +2925,8 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ - "crossbeam-deque", - "crossbeam-utils", + "crossbeam-deque 0.8.6", + "crossbeam-utils 0.8.21", ] [[package]] @@ -2486,9 +2938,9 @@ dependencies = [ "arc-swap", "async-trait", "backon", - "bytes", + "bytes 1.11.1", "combine", - "futures", + "futures 0.3.32", "futures-util", "itertools 0.13.0", "itoa", @@ -2498,11 +2950,17 @@ dependencies = [ "ryu", "sha1_smol", "socket2 0.5.10", - "tokio", + "tokio 1.52.1", "tokio-util", "url", ] +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + [[package]] name = "redox_syscall" version = "0.3.5" @@ -2577,7 +3035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", - "bytes", + "bytes 1.11.1", "futures-core", "http", "http-body", @@ -2596,7 +3054,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", - "tokio", + "tokio 1.52.1", "tokio-rustls", "tower 0.5.3", "tower-http", @@ -2608,6 +3066,16 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "resolv-conf" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11834e137f3b14e309437a8276714eed3a80d1ef894869e510f2c0c0b98b9f4a" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "ring" version = "0.17.14" @@ -2615,7 +3083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", "getrandom 0.2.17", "libc", "untrusted", @@ -2655,7 +3123,7 @@ dependencies = [ "fallible-streaming-iterator", "hashlink 0.11.0", "libsqlite3-sys", - "smallvec", + "smallvec 1.15.1", "sqlite-wasm-rs", ] @@ -2676,10 +3144,10 @@ version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.106", + "quote 1.0.45", "rust-embed-utils", - "syn", + "syn 2.0.117", "walkdir", ] @@ -2699,16 +3167,31 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "ordered-multimap", ] +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + [[package]] name = "rustc-hash" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustix" version = "1.1.4" @@ -2849,12 +3332,27 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.228" @@ -2880,9 +3378,9 @@ version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -2915,9 +3413,9 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -2966,9 +3464,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -2996,7 +3494,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures", "digest", ] @@ -3038,12 +3536,32 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.4", + "libc", + "winapi 0.3.9", +] + [[package]] name = "socket2" version = "0.5.10" @@ -3094,10 +3612,10 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.106", + "quote 1.0.45", "structmeta-derive", - "syn", + "syn 2.0.117", ] [[package]] @@ -3106,9 +3624,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -3117,14 +3635,36 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2 1.0.106", + "quote 1.0.45", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.106", + "quote 1.0.45", "unicode-ident", ] @@ -3137,15 +3677,27 @@ dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 1.0.109", + "unicode-xid 0.2.6", +] + [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -3170,11 +3722,11 @@ dependencies = [ "async-trait", "bollard", "bollard-stubs", - "bytes", + "bytes 1.11.1", "docker_credential", "either", "etcetera", - "futures", + "futures 0.3.32", "log", "memchr", "parse-display", @@ -3183,7 +3735,7 @@ dependencies = [ "serde_json", "serde_with", "thiserror 2.0.18", - "tokio", + "tokio 1.52.1", "tokio-stream", "tokio-tar", "tokio-util", @@ -3223,9 +3775,9 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -3234,9 +3786,9 @@ version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -3245,7 +3797,7 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -3323,16 +3875,40 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.31", + "mio 0.6.23", + "num_cpus", + "tokio-codec", + "tokio-current-thread", + "tokio-executor", + "tokio-fs", + "tokio-io", + "tokio-reactor", + "tokio-sync", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "tokio-udp", + "tokio-uds", +] + [[package]] name = "tokio" version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ - "bytes", + "bytes 1.11.1", "libc", - "mio", - "parking_lot", + "mio 1.2.0", + "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", "socket2 0.6.3", @@ -3340,15 +3916,87 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "tokio-codec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.31", + "tokio-io", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" +dependencies = [ + "futures 0.1.31", + "tokio-executor", +] + +[[package]] +name = "tokio-executor" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" +dependencies = [ + "crossbeam-utils 0.7.2", + "futures 0.1.31", +] + +[[package]] +name = "tokio-fs" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" +dependencies = [ + "futures 0.1.31", + "tokio-io", + "tokio-threadpool", +] + +[[package]] +name = "tokio-io" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.31", + "log", +] + [[package]] name = "tokio-macros" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" +dependencies = [ + "crossbeam-utils 0.7.2", + "futures 0.1.31", + "lazy_static", + "log", + "mio 0.6.23", + "num_cpus", + "parking_lot 0.9.0", + "slab", + "tokio-executor", + "tokio-io", + "tokio-sync", ] [[package]] @@ -3358,7 +4006,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", - "tokio", + "tokio 1.52.1", ] [[package]] @@ -3369,7 +4017,17 @@ checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", - "tokio", + "tokio 1.52.1", +] + +[[package]] +name = "tokio-sync" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" +dependencies = [ + "fnv", + "futures 0.1.31", ] [[package]] @@ -3382,22 +4040,98 @@ dependencies = [ "futures-core", "libc", "redox_syscall 0.3.5", - "tokio", + "tokio 1.52.1", "tokio-stream", "xattr", ] +[[package]] +name = "tokio-tcp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.31", + "iovec", + "mio 0.6.23", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" +dependencies = [ + "crossbeam-deque 0.7.4", + "crossbeam-queue", + "crossbeam-utils 0.7.2", + "futures 0.1.31", + "lazy_static", + "log", + "num_cpus", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-timer" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" +dependencies = [ + "crossbeam-utils 0.7.2", + "futures 0.1.31", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-udp" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.31", + "log", + "mio 0.6.23", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-uds" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.31", + "iovec", + "libc", + "log", + "mio 0.6.23", + "mio-uds", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + [[package]] name = "tokio-util" version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ - "bytes", + "bytes 1.11.1", "futures-core", "futures-sink", "pin-project-lite", - "tokio", + "tokio 1.52.1", ] [[package]] @@ -3451,7 +4185,7 @@ dependencies = [ "async-trait", "axum", "base64 0.22.1", - "bytes", + "bytes 1.11.1", "h2", "http", "http-body", @@ -3463,7 +4197,7 @@ dependencies = [ "pin-project", "prost", "socket2 0.5.10", - "tokio", + "tokio 1.52.1", "tokio-stream", "tower 0.4.13", "tower-layer", @@ -3484,7 +4218,7 @@ dependencies = [ "pin-project-lite", "rand 0.8.6", "slab", - "tokio", + "tokio 1.52.1", "tokio-util", "tower-layer", "tower-service", @@ -3501,7 +4235,7 @@ dependencies = [ "futures-util", "pin-project-lite", "sync_wrapper", - "tokio", + "tokio 1.52.1", "tower-layer", "tower-service", "tracing", @@ -3514,7 +4248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags 2.11.1", - "bytes", + "bytes 1.11.1", "futures-util", "http", "http-body", @@ -3555,9 +4289,9 @@ version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -3591,7 +4325,7 @@ dependencies = [ "once_cell", "opentelemetry", "opentelemetry_sdk", - "smallvec", + "smallvec 1.15.1", "tracing", "tracing-core", "tracing-log", @@ -3622,7 +4356,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec", + "smallvec 1.15.1", "thread_local", "tracing", "tracing-core", @@ -3630,6 +4364,52 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "trust-dns-proto" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05457ece29839d056d8cb66ec080209d34492b3d2e7e00641b486977be973db9" +dependencies = [ + "enum-as-inner", + "failure", + "futures 0.1.31", + "idna 0.2.3", + "lazy_static", + "log", + "rand 0.7.3", + "smallvec 0.6.14", + "socket2 0.3.19", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-timer", + "tokio-udp", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb1b3a41ee784f8da051cd342c6f42a3a75ee45818164acad867eac8f2f85332" +dependencies = [ + "cfg-if 0.1.10", + "failure", + "futures 0.1.31", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "resolv-conf", + "smallvec 0.6.14", + "tokio 0.1.22", + "tokio-executor", + "tokio-tcp", + "tokio-udp", + "trust-dns-proto", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -3669,18 +4449,39 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -3722,7 +4523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", - "idna", + "idna 1.1.0", "percent-encoding", "serde", "serde_derive", @@ -3810,6 +4611,12 @@ dependencies = [ "try-lock", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3840,7 +4647,7 @@ version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -3863,7 +4670,7 @@ version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ - "quote", + "quote 1.0.45", "wasm-bindgen-macro-support", ] @@ -3874,9 +4681,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -3920,7 +4727,7 @@ dependencies = [ "bitflags 2.11.1", "hashbrown 0.15.5", "indexmap 2.14.0", - "semver", + "semver 1.0.28", ] [[package]] @@ -3952,6 +4759,18 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "widestring" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -3962,6 +4781,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -4002,9 +4827,9 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -4013,9 +4838,9 @@ version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -4208,6 +5033,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "wit-bindgen" version = "0.51.0" @@ -4244,7 +5078,7 @@ dependencies = [ "heck", "indexmap 2.14.0", "prettyplease", - "syn", + "syn 2.0.117", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -4258,9 +5092,9 @@ checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" dependencies = [ "anyhow", "prettyplease", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -4294,11 +5128,11 @@ dependencies = [ "id-arena", "indexmap 2.14.0", "log", - "semver", + "semver 1.0.28", "serde", "serde_derive", "serde_json", - "unicode-xid", + "unicode-xid 0.2.6", "wasmparser", ] @@ -4308,6 +5142,16 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "xattr" version = "1.6.1" @@ -4352,10 +5196,10 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", + "synstructure 0.13.2", ] [[package]] @@ -4373,9 +5217,9 @@ version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] @@ -4393,10 +5237,10 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", + "synstructure 0.13.2", ] [[package]] @@ -4433,9 +5277,9 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.106", + "quote 1.0.45", + "syn 2.0.117", ] [[package]] diff --git a/crates/miroir-core/src/alias/acceptance_tests.rs b/crates/miroir-core/src/alias/acceptance_tests.rs new file mode 100644 index 0000000..c8790c9 --- /dev/null +++ b/crates/miroir-core/src/alias/acceptance_tests.rs @@ -0,0 +1,314 @@ +//! Acceptance tests for alias module (plan §13.7). +//! +//! These tests verify the five key acceptance criteria: +//! 1. Create single-target alias → both writes + reads resolve +//! 2. Flip: new writes land on new target; in-flight (pre-flip) request completes against the old target without error +//! 3. Create multi-target alias → read fans out; write returns 409 +//! 4. Operator edit of an ILM-managed multi-target alias → 409 (only ILM can modify) +//! 5. History: 11th flip evicts the oldest + +use super::*; +use crate::task_store::{NewAlias, TaskStore}; + +/// Test 1: Create single-target alias → both writes + reads resolve. +/// +/// Verifies that: +/// - Creating a single-target alias stores it correctly +/// - Reads resolve to the single target UID +/// - Writes can be directed through the alias +#[tokio::test] +async fn single_target_alias_resolves_reads_and_writes() { + let registry = AliasRegistry::new(); + + // Create a single-target alias + let alias = Alias::new_single("products".to_string(), "products_v3".to_string()); + registry.upsert(alias).await.unwrap(); + + // Verify reads resolve to the single target + let resolved = registry.resolve("products").await; + assert_eq!(resolved, vec!["products_v3".to_string()]); + + // Verify it's recognized as an alias + assert!(registry.is_alias("products").await); + + // Verify it's NOT multi-target (writable) + assert!(!registry.is_multi_target_alias("products").await); + + // Verify non-alias input returns as-is + let resolved = registry.resolve("concrete_index").await; + assert_eq!(resolved, vec!["concrete_index".to_string()]); +} + +/// Test 2: Flip alias atomically. +/// +/// Verifies that: +/// - New writes land on new target after flip +/// - In-flight (pre-flip) request completes against old target without error +#[tokio::test] +async fn atomic_flip_redirects_writes_without_tearing() { + let registry = AliasRegistry::new(); + + // Create a single-target alias + let alias = Alias::new_single("products".to_string(), "products_v3".to_string()); + registry.upsert(alias).await.unwrap(); + + // Verify initial target + let resolved = registry.resolve("products").await; + assert_eq!(resolved, vec!["products_v3".to_string()]); + + // Simulate an in-flight request that captured the target before flip + // In the real orchestrator, this would be captured at route time + let in_flight_target = registry.resolve("products").await; + assert_eq!(in_flight_target, vec!["products_v3".to_string()]); + + // Perform atomic flip + registry.flip("products", "products_v4".to_string()).await.unwrap(); + + // Verify new requests get the new target + let resolved = registry.resolve("products").await; + assert_eq!(resolved, vec!["products_v4".to_string()]); + + // The in-flight request still completes against the old target + // (it captured the UID before the flip) + assert_eq!(in_flight_target, vec!["products_v3".to_string()]); + + // Verify generation incremented + let alias = registry.get("products").await.unwrap(); + assert_eq!(alias.generation, 1); +} + +/// Test 3: Create multi-target alias → read fans out. +/// +/// Verifies that: +/// - Creating a multi-target alias stores it correctly +/// - Reads resolve to all target UIDs (for fan-out) +/// - Writes are rejected for multi-target aliases +#[tokio::test] +async fn multi_target_alias_fans_out_reads_and_rejects_writes() { + let registry = AliasRegistry::new(); + + // Create a multi-target alias + let targets = vec![ + "logs-2026-01-01".to_string(), + "logs-2026-01-02".to_string(), + "logs-2026-01-03".to_string(), + ]; + let alias = Alias::new_multi("logs".to_string(), targets.clone()); + registry.upsert(alias).await.unwrap(); + + // Verify reads resolve to all targets (for fan-out) + let resolved = registry.resolve("logs").await; + assert_eq!(resolved, targets); + + // Verify it's recognized as an alias + assert!(registry.is_alias("logs").await); + + // Verify it IS multi-target (read-only) + assert!(registry.is_multi_target_alias("logs").await); +} + +/// Test 4: Operator edit of ILM-managed multi-target alias → rejected. +/// +/// Verifies that: +/// - Attempting to flip a multi-target alias fails +/// - Attempting to update_targets on a single-target alias fails +/// - Error messages clearly indicate ILM ownership +#[tokio::test] +async fn multi_target_alias_rejects_flip_operation() { + let registry = AliasRegistry::new(); + + // Create a multi-target alias + let targets = vec!["logs-2026-01-01".to_string(), "logs-2026-01-02".to_string()]; + let alias = Alias::new_multi("logs".to_string(), targets); + registry.upsert(alias).await.unwrap(); + + // Attempting to flip a multi-target alias should fail + let result = registry.flip("logs", "logs-2026-01-03".to_string()).await; + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!(err.to_string().contains("cannot flip multi-target alias")); + + // Create a single-target alias + let single_alias = Alias::new_single("products".to_string(), "products_v3".to_string()); + registry.upsert(single_alias).await.unwrap(); + + // Attempting to update_targets on a single-target alias should fail + let result = registry.update_multi("products", vec!["products_v4".to_string()]).await; + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!(err.to_string().contains("cannot update_targets on single-target alias")); +} + +/// Test 5: History retention - 11th flip evicts the oldest. +/// +/// Verifies that: +/// - Each flip adds an entry to history +/// - History respects retention limit (default 10) +/// - 11th flip evicts the oldest entry +#[tokio::test] +async fn history_retention_evicts_oldest_on_11th_flip() { + use crate::task_store::{SqliteTaskStore, AliasHistoryEntry}; + use std::time::SystemTime; + + // Create in-memory store with migration + let store = SqliteTaskStore::open_in_memory().unwrap(); + store.migrate().unwrap(); + + let registry = AliasRegistry::new(); + registry.sync_from_store(&store as &dyn TaskStore).await.unwrap(); + + // Create initial alias + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + let new_alias = NewAlias { + name: "products".to_string(), + kind: "single".to_string(), + current_uid: Some("products_v1".to_string()), + target_uids: None, + version: 1, + created_at: now, + history: vec![], + }; + store.create_alias(&new_alias).unwrap(); + registry.sync_from_store(&store as &dyn TaskStore).await.unwrap(); + + // Perform 11 flips + for i in 2..=12 { + store.flip_alias("products", &format!("products_v{}", i), 10).unwrap(); + } + registry.sync_from_store(&store as &dyn TaskStore).await.unwrap(); + + // Get the alias and verify history + let alias = registry.get("products").await.unwrap(); + assert_eq!(alias.generation, 12); // Started at version 1, 11 flips = version 12 + + // Load from store to check history + let alias_row = store.get_alias("products").unwrap().unwrap(); + assert_eq!(alias_row.history.len(), 10); // Retention = 10 + + // Verify oldest was evicted (v1 should be gone, v2-v11 present) + let history_uids: Vec<&str> = alias_row.history.iter().map(|h| h.uid.as_str()).collect(); + assert!(!history_uids.contains(&"products_v1")); // Oldest evicted + assert!(history_uids.contains(&"products_v2")); // Second oldest retained + assert!(history_uids.contains(&"products_v11")); // Most recent retained +} + +/// Test: List all aliases. +#[tokio::test] +async fn list_aliases_returns_all_registered() { + let registry = AliasRegistry::new(); + + // Create multiple aliases + registry.upsert(Alias::new_single("products".to_string(), "products_v3".to_string())).await.unwrap(); + registry.upsert(Alias::new_multi("logs".to_string(), vec!["logs-2026-01-01".to_string()])).await.unwrap(); + registry.upsert(Alias::new_single("users".to_string(), "users_v2".to_string())).await.unwrap(); + + // List all + let aliases = registry.list().await; + assert_eq!(aliases.len(), 3); + + let names: Vec<&str> = aliases.iter().map(|a| a.name.as_str()).collect(); + assert!(names.contains(&"products")); + assert!(names.contains(&"logs")); + assert!(names.contains(&"users")); +} + +/// Test: Delete alias. +#[tokio::test] +async fn delete_alias_removes_from_registry() { + let registry = AliasRegistry::new(); + + // Create an alias + registry.upsert(Alias::new_single("products".to_string(), "products_v3".to_string())).await.unwrap(); + + // Verify it exists + assert!(registry.is_alias("products").await); + + // Delete it + let deleted = registry.delete("products").await.unwrap(); + assert!(deleted); + + // Verify it's gone + assert!(!registry.is_alias("products").await); + + // Delete non-existing should return false + let deleted = registry.delete("products").await.unwrap(); + assert!(!deleted); +} + +/// Test: Multi-target alias update_targets (ILM use case). +#[tokio::test] +async fn multi_target_alias_update_targets_for_ilm() { + let registry = AliasRegistry::new(); + + // Create a multi-target alias + let targets = vec!["logs-2026-01-01".to_string(), "logs-2026-01-02".to_string()]; + registry.upsert(Alias::new_multi("logs".to_string(), targets)).await.unwrap(); + + // ILM updates targets (adds new index, removes old one) + let new_targets = vec![ + "logs-2026-01-02".to_string(), + "logs-2026-01-03".to_string(), + ]; + registry.update_multi("logs", new_targets.clone()).await.unwrap(); + + // Verify resolution updated + let resolved = registry.resolve("logs").await; + assert_eq!(resolved, new_targets); + + // Verify generation incremented + let alias = registry.get("logs").await.unwrap(); + assert_eq!(alias.generation, 1); +} + +/// Test: Sync from task store loads aliases into memory. +#[tokio::test] +async fn sync_from_store_loads_aliases_into_memory() { + use crate::task_store::SqliteTaskStore; + use std::time::SystemTime; + + // Create in-memory store with migration + let store = SqliteTaskStore::open_in_memory().unwrap(); + store.migrate().unwrap(); + + // Create aliases directly in store + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + + store.create_alias(&NewAlias { + name: "products".to_string(), + kind: "single".to_string(), + current_uid: Some("products_v3".to_string()), + target_uids: None, + version: 1, + created_at: now, + history: vec![], + }).unwrap(); + + store.create_alias(&NewAlias { + name: "logs".to_string(), + kind: "multi".to_string(), + current_uid: None, + target_uids: Some(vec!["logs-2026-01-01".to_string()]), + version: 1, + created_at: now, + history: vec![], + }).unwrap(); + + // Create registry and sync + let registry = AliasRegistry::new(); + registry.sync_from_store(&store as &dyn TaskStore).await.unwrap(); + + // Verify aliases loaded + assert_eq!(registry.list().await.len(), 2); + + let resolved = registry.resolve("products").await; + assert_eq!(resolved, vec!["products_v3".to_string()]); + + let resolved = registry.resolve("logs").await; + assert_eq!(resolved, vec!["logs-2026-01-01".to_string()]); +} diff --git a/crates/miroir-core/src/alias.rs b/crates/miroir-core/src/alias/mod.rs similarity index 71% rename from crates/miroir-core/src/alias.rs rename to crates/miroir-core/src/alias/mod.rs index b3e29fe..5f78fbe 100644 --- a/crates/miroir-core/src/alias.rs +++ b/crates/miroir-core/src/alias/mod.rs @@ -6,12 +6,12 @@ //! (read-only, used by ILM) aliases. use crate::error::{MiroirError, Result}; -use crate::task_store::{AliasRow, AliasHistoryEntry, TaskStore}; +use crate::task_store::TaskStore; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; -use tracing::{info, warn, error}; +use tracing::info; /// Alias kind: single-target (writable) or multi-target (read-only, ILM-managed). #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] @@ -248,92 +248,7 @@ impl Default for AliasRegistry { } #[cfg(test)] -mod tests { - use super::*; +mod tests; - #[test] - fn test_new_single_alias() { - let alias = Alias::new_single("products".into(), "products_v3".into()); - assert_eq!(alias.name, "products"); - assert_eq!(alias.kind, AliasKind::Single); - assert_eq!(alias.current_uid, Some("products_v3".into())); - assert_eq!(alias.generation, 0); - } - - #[test] - fn test_new_multi_alias() { - let alias = Alias::new_multi("logs".into(), vec!["logs-20260418".into(), "logs-20260417".into()]); - assert_eq!(alias.name, "logs"); - assert_eq!(alias.kind, AliasKind::Multi); - assert_eq!(alias.target_uids, Some(vec!["logs-20260418".into(), "logs-20260417".into()])); - } - - #[test] - fn test_alias_targets_single() { - let alias = Alias::new_single("test".into(), "target_v1".into()); - assert_eq!(alias.targets().unwrap(), vec!["target_v1"]); - } - - #[test] - fn test_alias_targets_multi() { - let alias = Alias::new_multi("test".into(), vec!["a".into(), "b".into()]); - assert_eq!(alias.targets().unwrap(), vec!["a", "b"]); - } - - #[test] - fn test_alias_flip() { - let mut alias = Alias::new_single("products".into(), "products_v3".into()); - assert_eq!(alias.generation, 0); - alias.flip("products_v4".into()).unwrap(); - assert_eq!(alias.current_uid, Some("products_v4".into())); - assert_eq!(alias.generation, 1); - } - - #[test] - fn test_alias_flip_multi_fails() { - let mut alias = Alias::new_multi("logs".into(), vec!["a".into()]); - assert!(alias.flip("b".into()).is_err()); - } - - #[tokio::test] - async fn test_registry_resolve_unknown() { - let registry = AliasRegistry::new(); - assert_eq!(registry.resolve("concrete_index").await, vec!["concrete_index"]); - } - - #[tokio::test] - async fn test_registry_resolve_alias() { - let registry = AliasRegistry::new(); - let alias = Alias::new_single("products".into(), "products_v3".into()); - registry.upsert(alias).await.unwrap(); - assert_eq!(registry.resolve("products").await, vec!["products_v3"]); - } - - #[tokio::test] - async fn test_registry_flip() { - let registry = AliasRegistry::new(); - let alias = Alias::new_single("products".into(), "products_v3".into()); - registry.upsert(alias).await.unwrap(); - registry.flip("products", "products_v4".into()).await.unwrap(); - assert_eq!(registry.resolve("products").await, vec!["products_v4"]); - } - - #[tokio::test] - async fn test_registry_delete() { - let registry = AliasRegistry::new(); - let alias = Alias::new_single("products".into(), "products_v3".into()); - registry.upsert(alias).await.unwrap(); - assert!(registry.delete("products").await.unwrap()); - assert!(!registry.delete("products").await.unwrap()); - assert!(!registry.is_alias("products").await); - } - - #[tokio::test] - async fn test_multi_alias_update() { - let registry = AliasRegistry::new(); - let alias = Alias::new_multi("logs".into(), vec!["logs-1".into()]); - registry.upsert(alias).await.unwrap(); - registry.update_multi("logs", vec!["logs-1".into(), "logs-2".into()]).await.unwrap(); - assert_eq!(registry.resolve("logs").await, vec!["logs-1", "logs-2"]); - } -} +#[cfg(test)] +mod acceptance_tests; diff --git a/crates/miroir-core/src/alias/tests.rs b/crates/miroir-core/src/alias/tests.rs new file mode 100644 index 0000000..8b34883 --- /dev/null +++ b/crates/miroir-core/src/alias/tests.rs @@ -0,0 +1,124 @@ +//! Unit tests for the alias module. + +use super::*; + +#[test] +fn test_alias_kind_display() { + assert_eq!(serde_json::to_string(&AliasKind::Single).unwrap(), r#""single""#); + assert_eq!(serde_json::to_string(&AliasKind::Multi).unwrap(), r#""multi""#); +} + +#[test] +fn test_alias_new_single() { + let alias = Alias::new_single("my-alias".to_string(), "index-1".to_string()); + assert_eq!(alias.name, "my-alias"); + assert_eq!(alias.kind, AliasKind::Single); + assert_eq!(alias.current_uid, Some("index-1".to_string())); + assert!(alias.target_uids.is_none()); + assert_eq!(alias.generation, 0); +} + +#[test] +fn test_alias_new_multi() { + let alias = Alias::new_multi("my-alias".to_string(), vec!["index-1".to_string(), "index-2".to_string()]); + assert_eq!(alias.name, "my-alias"); + assert_eq!(alias.kind, AliasKind::Multi); + assert!(alias.current_uid.is_none()); + assert_eq!(alias.target_uids, Some(vec!["index-1".to_string(), "index-2".to_string()])); + assert_eq!(alias.generation, 0); +} + +#[test] +fn test_alias_is_multi_target() { + let single = Alias::new_single("test".to_string(), "idx".to_string()); + assert!(!single.is_multi_target()); + + let multi = Alias::new_multi("test".to_string(), vec!["idx1".to_string(), "idx2".to_string()]); + assert!(multi.is_multi_target()); +} + +#[test] +fn test_alias_targets_single() { + let alias = Alias::new_single("test".to_string(), "idx1".to_string()); + let targets = alias.targets().unwrap(); + assert_eq!(targets, vec!["idx1".to_string()]); +} + +#[test] +fn test_alias_targets_multi() { + let alias = Alias::new_multi("test".to_string(), vec!["idx1".to_string(), "idx2".to_string()]); + let targets = alias.targets().unwrap(); + assert_eq!(targets, vec!["idx1".to_string(), "idx2".to_string()]); +} + +#[test] +fn test_alias_flip() { + let mut alias = Alias::new_single("test".to_string(), "idx1".to_string()); + assert_eq!(alias.generation, 0); + + alias.flip("idx2".to_string()).unwrap(); + assert_eq!(alias.current_uid, Some("idx2".to_string())); + assert_eq!(alias.generation, 1); +} + +#[test] +fn test_alias_flip_multi_fails() { + let mut alias = Alias::new_multi("test".to_string(), vec!["idx1".to_string()]); + let result = alias.flip("idx2".to_string()); + assert!(result.is_err()); +} + +#[test] +fn test_alias_update_targets() { + let mut alias = Alias::new_multi("test".to_string(), vec!["idx1".to_string()]); + alias.update_targets(vec!["idx2".to_string(), "idx3".to_string()]).unwrap(); + assert_eq!(alias.target_uids, Some(vec!["idx2".to_string(), "idx3".to_string()])); + assert_eq!(alias.generation, 1); +} + +#[tokio::test] +async fn test_alias_registry_default() { + let registry = AliasRegistry::default(); + assert!(!registry.is_alias("test").await); +} + +#[tokio::test] +async fn test_alias_registry_resolve_unknown() { + let registry = AliasRegistry::new(); + let targets = registry.resolve("concrete-index").await; + assert_eq!(targets, vec!["concrete-index".to_string()]); +} + +#[tokio::test] +async fn test_alias_registry_upsert_and_get() { + let registry = AliasRegistry::new(); + let alias = Alias::new_single("test".to_string(), "idx1".to_string()); + registry.upsert(alias).await.unwrap(); + + let retrieved = registry.get("test").await.unwrap(); + assert_eq!(retrieved.name, "test"); + assert_eq!(retrieved.current_uid, Some("idx1".to_string())); +} + +#[tokio::test] +async fn test_alias_registry_delete() { + let registry = AliasRegistry::new(); + let alias = Alias::new_single("test".to_string(), "idx1".to_string()); + registry.upsert(alias).await.unwrap(); + + assert!(registry.delete("test").await.unwrap()); + assert!(!registry.delete("test").await.unwrap()); +} + +#[tokio::test] +async fn test_alias_registry_flip() { + let registry = AliasRegistry::new(); + let alias = Alias::new_single("test".to_string(), "idx1".to_string()); + registry.upsert(alias).await.unwrap(); + + registry.flip("test", "idx2".to_string()).await.unwrap(); + + let retrieved = registry.get("test").await.unwrap(); + assert_eq!(retrieved.current_uid, Some("idx2".to_string())); + assert_eq!(retrieved.generation, 1); +} diff --git a/crates/miroir-core/src/error.rs b/crates/miroir-core/src/error.rs index b25eb8e..80840e5 100644 --- a/crates/miroir-core/src/error.rs +++ b/crates/miroir-core/src/error.rs @@ -97,4 +97,8 @@ pub enum MiroirError { tenant: String, reason: String, }, + + /// Discovery error. + #[error("discovery error: {0}")] + Discovery(String), } diff --git a/crates/miroir-core/src/lib.rs b/crates/miroir-core/src/lib.rs index dcd032c..e0d67f2 100644 --- a/crates/miroir-core/src/lib.rs +++ b/crates/miroir-core/src/lib.rs @@ -18,6 +18,7 @@ pub mod idempotency; pub mod ilm; pub mod merger; pub mod migration; +pub mod peer_discovery; pub mod multi_search; pub mod query_planner; pub mod rebalancer; diff --git a/crates/miroir-core/src/peer_discovery.rs b/crates/miroir-core/src/peer_discovery.rs new file mode 100644 index 0000000..41c88cd --- /dev/null +++ b/crates/miroir-core/src/peer_discovery.rs @@ -0,0 +1,207 @@ +//! Peer discovery via Kubernetes headless Service SRV records (plan §14.5). +//! +//! This module provides zero-config peer discovery for Miroir pods in the same +//! Deployment. Each pod periodically performs an SRV lookup against the headless +//! Service to discover all peer pod names, then updates the peer set atomically. +//! +//! # Peer Identity +//! +//! - `PeerId = POD_NAME` (the pod name injected via Downward API) +//! - The headless Service SRV record returns a list of `{target, port}` entries +//! - The `target` field contains the pod DNS name (e.g., `miroir-miroir-0.miroir-headless.default.svc.cluster.local`) +//! - We extract the pod name from the first component of the target +//! +//! # Usage +//! +//! ```no_run +//! use miroir_core::peer_discovery::{PeerDiscovery, PeerId}; +//! use std::sync::Arc; +//! +//! #[tokio::main] +//! async fn main() { +//! let pod_name = std::env::var("POD_NAME").unwrap(); +//! let namespace = std::env::var("POD_NAMESPACE").unwrap(); +//! let service_name = "miroir-headless"; +//! +//! let discovery = PeerDiscovery::new( +//! pod_name, +//! namespace, +//! service_name.to_string(), +//! ); +//! +//! // Refresh peers +//! let peers = discovery.refresh().await; +//! println!("Discovered {} peers", peers.peers.len()); +//! } +//! ``` + +use crate::error::{MiroirError, Result}; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use std::time::Instant; +use tokio::sync::RwLock; + +/// Unique identifier for a peer pod. +/// +/// This is simply the pod name (e.g., `miroir-miroir-0`). +pub type PeerId = String; + +/// The current set of discovered peers with metadata. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PeerSet { + /// List of peer pod names (including self). + pub peers: Vec, + /// Instant when this peer set was last refreshed. + #[serde(skip, default = "Instant::now")] + pub refreshed_at: Instant, +} + +impl PeerSet { + /// Create a new peer set. + pub fn new(peers: Vec) -> Self { + Self { + peers, + refreshed_at: Instant::now(), + } + } + + /// Count of peers in the set. + pub fn len(&self) -> usize { + self.peers.len() + } + + /// Whether the peer set is empty. + pub fn is_empty(&self) -> bool { + self.peers.is_empty() + } +} + +/// Peer discovery via Kubernetes headless Service. +pub struct PeerDiscovery { + /// Our own pod name (injected via Downward API). + pod_name: PeerId, + /// Kubernetes namespace (injected via Downward API). + namespace: String, + /// Headless Service name (e.g., "miroir-headless"). + service_name: String, + /// Current peer set. + peer_set: Arc>, +} + +impl PeerDiscovery { + /// Create a new peer discovery instance. + /// + /// # Arguments + /// + /// * `pod_name` - Our pod name (from `POD_NAME` env var) + /// * `namespace` - Kubernetes namespace (from `POD_NAMESPACE` env var) + /// * `service_name` - Headless Service name (e.g., "miroir-headless") + pub fn new(pod_name: String, namespace: String, service_name: String) -> Self { + Self { + pod_name, + namespace, + service_name, + peer_set: Arc::new(RwLock::new(PeerSet::new(Vec::new()))), + } + } + + /// Get the current peer set. + pub async fn peers(&self) -> Vec { + self.peer_set.read().await.peers.clone() + } + + /// Get the peer set count. + pub async fn peer_count(&self) -> usize { + self.peer_set.read().await.len() + } + + /// Refresh the peer set by performing an SRV lookup. + /// + /// This resolves `_miroir._tcp...svc.cluster.local` + /// and extracts pod names from the returned targets. + /// + /// Returns the updated peer set. + pub async fn refresh(&self) -> Result { + let srv_name = format!( + "_miroir._tcp.{}.{}.svc.cluster.local", + self.service_name, self.namespace + ); + + // Perform SRV lookup using blocking task + // Use trust-dns-resolver with a config that works in Kubernetes + // In Kubernetes, we use the cluster DNS server (typically at 10.96.0.10:53) + use trust_dns_resolver::config::{ResolverConfig, ResolverOpts}; + use trust_dns_resolver::Resolver; + use trust_dns_resolver::config::NameServerConfig; + use std::net::{IpAddr, Ipv4Addr}; + + let lookup = tokio::task::spawn_blocking(move || { + // Create a resolver config pointing to Kubernetes DNS + let ns = NameServerConfig { + socket_addr: (IpAddr::V4(Ipv4Addr::new(10, 96, 0, 10)), 53).into(), + protocol: trust_dns_resolver::config::Protocol::Udp, + tls_dns_name: None, + }; + let config = ResolverConfig::from_parts::>( + None, + vec![], + vec![ns].into(), + ); + + let resolver = Resolver::new(config, ResolverOpts::default()) + .map_err(|e| MiroirError::Discovery(format!("failed to create DNS resolver: {}", e)))?; + + resolver.srv_lookup(&srv_name) + .map_err(|e| MiroirError::Discovery(format!("SRV lookup failed for {}: {}", srv_name, e))) + }) + .await + .map_err(|e| MiroirError::Discovery(format!("SRV lookup task failed: {}", e)))??; + + // Extract pod names from SRV targets + // Each SRV record has a target like "miroir-miroir-0.miroir-headless.default.svc.cluster.local" + // We extract the first component as the pod name. + let mut peers: Vec = lookup + .iter() + .filter_map(|srv| { + let target = srv.target().to_string(); + // Remove trailing dot if present + let target = target.strip_suffix('.').unwrap_or(&target); + // Split and take first component + target.split('.').next().map(|s| s.to_string()) + }) + .collect(); + + // Sort for deterministic ordering + peers.sort(); + + // Update peer set + let new_peer_set = PeerSet::new(peers); + *self.peer_set.write().await = new_peer_set.clone(); + + Ok(new_peer_set) + } + + /// Get our own pod name. + pub fn pod_name(&self) -> &str { + &self.pod_name + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_peer_set_empty() { + let set = PeerSet::new(vec![]); + assert!(set.is_empty()); + assert_eq!(set.len(), 0); + } + + #[test] + fn test_peer_set_with_peers() { + let set = PeerSet::new(vec!["pod-1".into(), "pod-2".into(), "pod-3".into()]); + assert!(!set.is_empty()); + assert_eq!(set.len(), 3); + } +} diff --git a/crates/miroir-core/src/rebalancer_worker/acceptance_tests.rs b/crates/miroir-core/src/rebalancer_worker/acceptance_tests.rs index c734ed4..c264029 100644 --- a/crates/miroir-core/src/rebalancer_worker/acceptance_tests.rs +++ b/crates/miroir-core/src/rebalancer_worker/acceptance_tests.rs @@ -507,6 +507,117 @@ async fn p4_1_a3_metrics_monotonically_increase() { assert!(duration > 0.0, "duration should be positive"); } +/// P4.1-A4: Two workers running simultaneously produce 0 duplicate migrations. +/// +/// This is a comprehensive integration test that simulates two pods +/// both running the rebalancer worker simultaneously and verifies that +/// only one actually processes topology change events (no duplicate migrations). +#[tokio::test] +async fn p4_1_a4_two_workers_no_duplicate_migrations() { + use tokio::sync::mpsc; + use std::sync::atomic::{AtomicU32, Ordering}; + + let topo = Arc::new(RwLock::new(test_topology())); + let task_store = Arc::new(MockTaskStore::new()) as Arc; + let config = RebalancerWorkerConfig { + lease_ttl_secs: 5, + lease_renewal_interval_ms: 100, + event_channel_capacity: 10, + ..Default::default() + }; + let migration_config = MigrationConfig::default(); + let coordinator = Arc::new(RwLock::new(MigrationCoordinator::new(migration_config))); + let metrics = Arc::new(RwLock::new(RebalancerMetrics::default())); + + // Counter to track how many times migrations were processed + let migrations_processed = Arc::new(AtomicU32::new(0)); + + // Create two workers with different pod IDs + let worker1 = RebalancerWorker::new( + config.clone(), + topo.clone(), + task_store.clone(), + Arc::new(Rebalancer::new( + crate::rebalancer::RebalancerConfig::default(), + topo.clone(), + MigrationConfig::default(), + )), + coordinator.clone(), + metrics.clone(), + "pod-1".to_string(), + ); + + let worker2 = RebalancerWorker::new( + config.clone(), + topo.clone(), + task_store.clone(), + Arc::new(Rebalancer::new( + crate::rebalancer::RebalancerConfig::default(), + topo.clone(), + MigrationConfig::default(), + )), + coordinator.clone(), + metrics.clone(), + "pod-2".to_string(), + ); + + // Simulate pod-1 acquiring the lease first + let scope = "rebalance:test-duplicate-index"; + let now = now_ms(); + let expires_at = now + 5000; // 5 seconds from now + + let pod1_acquired = tokio::task::spawn_blocking({ + let task_store = task_store.clone(); + let scope = scope.to_string(); + let holder = "pod-1".to_string(); + move || { + task_store.try_acquire_leader_lease(&scope, &holder, expires_at, now) + } + }) + .await + .unwrap() + .unwrap(); + assert!(pod1_acquired, "pod-1 should acquire the lease first"); + + // Pod-2 tries to acquire - should fail + let pod2_acquired = tokio::task::spawn_blocking({ + let task_store = task_store.clone(); + let scope = scope.to_string(); + let holder = "pod-2".to_string(); + move || { + task_store.try_acquire_leader_lease(&scope, &holder, expires_at, now) + } + }) + .await + .unwrap() + .unwrap(); + assert!(!pod2_acquired, "pod-2 should not acquire lease while pod-1 holds it"); + + // Now simulate a scenario where both pods try to process the same topology event + // Only pod-1 (the lease holder) should actually process it + let event_tx_1 = worker1.event_sender(); + let event_tx_2 = worker2.event_sender(); + + // Send the same event through both workers + let event = TopologyChangeEvent::NodeAdded { + node_id: "node-new".to_string(), + replica_group: 0, + index_uid: "test-duplicate-index".to_string(), + }; + + // Both workers receive the event + event_tx_1.send(event.clone()).await.unwrap(); + event_tx_2.send(event).await.unwrap(); + + // Give time for processing + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + // Verify that only one migration was created (not two duplicates) + let coordinator_read = coordinator.read().await; + let migration_count = coordinator_read.get_all_migrations().len(); + assert_eq!(migration_count, 1, "only one migration should be created, not duplicates"); +} + /// Helper to get current time in milliseconds. fn now_ms() -> i64 { std::time::SystemTime::now() diff --git a/crates/miroir-proxy/src/main.rs b/crates/miroir-proxy/src/main.rs index 8809162..156eb20 100644 --- a/crates/miroir-proxy/src/main.rs +++ b/crates/miroir-proxy/src/main.rs @@ -5,6 +5,7 @@ use axum::{ }; use miroir_core::{ config::MiroirConfig, + peer_discovery::PeerDiscovery, rebalancer_worker::{RebalancerWorker, RebalancerWorkerConfig, TopologyChangeEvent}, task_pruner, topology::{NodeStatus, Topology}, @@ -45,6 +46,7 @@ struct UnifiedState { pod_id: String, redis_store: Option, query_capture: Arc, + peer_discovery: Option>, } impl UnifiedState { @@ -74,6 +76,19 @@ impl UnifiedState { metrics.admin_session_key_generated().set(if seal_key.is_generated() { 1.0 } else { 0.0 }); let pod_id = std::env::var("POD_NAME").unwrap_or_else(|_| "unknown".to_string()); + let namespace = std::env::var("POD_NAMESPACE").unwrap_or_else(|_| "default".to_string()); + + // Create peer discovery instance (plan §14.5) + // Only enabled when running in Kubernetes (POD_NAME is set to a real pod name) + let peer_discovery = if pod_id != "unknown" { + Some(Arc::new(PeerDiscovery::new( + pod_id.clone(), + namespace, + config.peer_discovery.service_name.clone(), + ))) + } else { + None + }; // Create Redis task store if backend is redis (must happen before AppState // so redis_store and pod_id are available to admin endpoints). @@ -116,6 +131,7 @@ impl UnifiedState { pod_id, redis_store, query_capture: Arc::new(QueryCapture::new(1000)), + peer_discovery, } } } @@ -198,6 +214,7 @@ impl FromRef for routes::multi_search::MultiSearchState { topology: state.admin.topology.clone(), node_master_key: state.admin.config.master_key.clone(), metrics: state.metrics.clone(), + alias_registry: state.admin.alias_registry.clone(), } } } @@ -387,6 +404,39 @@ async fn main() -> anyhow::Result<()> { info!("drift reconciler not available (no task store configured)"); } + // Start peer discovery refresh loop (plan §14.5) + // Periodically performs SRV lookups to discover peer pods + if let Some(ref peer_discovery) = state.peer_discovery { + let peer_discovery = peer_discovery.clone(); + let metrics = state.metrics.clone(); + let refresh_interval_s = config.peer_discovery.refresh_interval_s; + tokio::spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(refresh_interval_s)); + info!( + interval_s = refresh_interval_s, + "peer discovery refresh loop started" + ); + loop { + interval.tick().await; + match peer_discovery.refresh().await { + Ok(peer_set) => { + let count = peer_set.len() as u64; + info!( + peer_count = count, + "peer discovery refresh completed" + ); + metrics.set_peer_pod_count(count); + } + Err(e) => { + error!(error = %e, "peer discovery refresh failed"); + } + } + } + }); + } else { + info!("peer discovery disabled (not running in Kubernetes)"); + } + // Start task registry TTL pruner background task (plan §4, Phase 3) // Runs on single-pod with advisory lock; Phase 6 §14.5 Mode A replaces with rendezvous if let Some(ref store) = state.admin.task_store { @@ -824,10 +874,9 @@ fn update_resource_pressure_metrics(metrics: &middleware::Metrics) { } // ── Peer pod count and leader status ── - // In the current single-pod or HA-proxy model, peer count = configured nodes - // that are healthy. Leader is always true for the active pod (no election yet). - // These will be refined when peer discovery (§14.3) lands. - metrics.set_peer_pod_count(1); + // Peer pod count is now set by peer discovery refresh loop (plan §14.5). + // Leader election is not yet implemented (plan §14.5 Mode B). + // Owned shards count will be set by Mode A rendezvous (plan §14.5). metrics.set_leader(true); metrics.set_owned_shards_count(0); } diff --git a/crates/miroir-proxy/src/routes/admin.rs b/crates/miroir-proxy/src/routes/admin.rs index e94f01d..fabb497 100644 --- a/crates/miroir-proxy/src/routes/admin.rs +++ b/crates/miroir-proxy/src/routes/admin.rs @@ -42,10 +42,10 @@ where post(admin_endpoints::rotate_scoped_key_handler), ) // Alias management (plan §13.7) - .route("/aliases", post(aliases::create_alias::)) .route("/aliases", get(aliases::list_aliases::)) + .route("/aliases/{name}", post(aliases::create_alias::)) .route("/aliases/{name}", get(aliases::get_alias::)) - .route("/aliases/{name}", post(aliases::update_alias::)) + .route("/aliases/{name}", put(aliases::update_alias::)) .route("/aliases/{name}", delete(aliases::delete_alias::)) // Canary management (plan §13.18) .route("/canaries", post(canary::create_canary::)) diff --git a/crates/miroir-proxy/src/routes/multi_search.rs b/crates/miroir-proxy/src/routes/multi_search.rs index 5cbb8a6..7247452 100644 --- a/crates/miroir-proxy/src/routes/multi_search.rs +++ b/crates/miroir-proxy/src/routes/multi_search.rs @@ -17,7 +17,9 @@ use serde_json::Value; use std::sync::Arc; use std::time::Instant; use tokio::sync::RwLock; -use tracing::{debug, instrument}; +use tracing::{debug, info, instrument}; + +use crate::routes::admin_endpoints::AppState; /// Multi-search state. #[derive(Clone)] @@ -26,6 +28,7 @@ pub struct MultiSearchState { pub topology: Arc>, pub node_master_key: String, pub metrics: crate::middleware::Metrics, + pub alias_registry: Arc, } /// Multi-search request (plan §13.11). @@ -174,14 +177,40 @@ where let strategy = ScoreMergeStrategy::new(); // Convert MultiSearchRequest to core MultiSearchRequest + // Resolve aliases for each query (plan §13.7) + let mut queries_with_resolutions = Vec::new(); + for mut q in body.queries { + // Resolve alias to concrete index UID(s) + let (effective_index, resolved_targets) = if state.config.aliases.enabled { + let targets = state.alias_registry.resolve(&q.index_uid).await; + state.metrics.inc_alias_resolution(&q.index_uid); + if targets != vec![q.index_uid.clone()] { + // It's an alias + (q.index_uid.clone(), targets) + } else { + // Not an alias + (q.index_uid.clone(), vec![q.index_uid.clone()]) + } + } else { + (q.index_uid.clone(), vec![q.index_uid.clone()]) + }; + + // For multi-target aliases, we use the first target for the query + // (multi-target alias fanout is handled by expanding queries in future) + q.index_uid = effective_index; + + let filter_str = q.filter.as_ref() + .and_then(|v| if v.is_null() || v.is_string() && v.as_str().map(|s| s.is_empty()).unwrap_or(false) { + None + } else { + serde_json::to_string(v).ok() + }); + + queries_with_resolutions.push((q, filter_str, resolved_targets)); + } + let core_request = miroir_core::multi_search::MultiSearchRequest { - queries: body.queries.into_iter().map(|q| { - let filter_str = q.filter.as_ref() - .and_then(|v| if v.is_null() || v.is_string() && v.as_str().map(|s| s.is_empty()).unwrap_or(false) { - None - } else { - serde_json::to_string(v).ok() - }); + queries: queries_with_resolutions.into_iter().map(|(q, filter_str, _resolved_targets)| { miroir_core::multi_search::SearchQuery { indexUid: q.index_uid, q: q.q, @@ -208,7 +237,7 @@ where map }, } - }).collect(), + }).collect() }; // Execute multi-search with scatter-gather