diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 6e951ca..0fea51d 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -216,18 +216,15 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" -dependencies = [ - "bytemuck_derive", -] +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "bytemuck_derive" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", @@ -236,9 +233,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" @@ -256,12 +253,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chrono" version = "0.4.42" @@ -359,10 +350,19 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cortexbrain-common" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5daea06747f06e000deaa52b7aceb504ddc309c061badf76e0b4b3d146ebf3a4" dependencies = [ "anyhow", + "aya", + "bytemuck", + "bytemuck_derive", + "bytes", + "k8s-openapi", + "kube", + "opentelemetry", + "opentelemetry-appender-tracing", + "opentelemetry-otlp", + "opentelemetry-stdout", + "opentelemetry_sdk", "tracing", "tracing-subscriber", ] @@ -390,8 +390,6 @@ dependencies = [ [[package]] name = "cortexflow_agent_api" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bfebbb2894a8d2edec3c4f3631952860c34706b798aa8d77ea2806ddd6fc476" dependencies = [ "anyhow", "aya", @@ -399,7 +397,6 @@ dependencies = [ "bytemuck_derive", "chrono", "cortexbrain-common", - "cortexflow_identity", "prost", "tokio", "tokio-stream", @@ -412,27 +409,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "cortexflow_identity" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5725a802e4f494b5fab4c69b1455a32dd3804b52a58c665a7d751eeae93ddfca" -dependencies = [ - "anyhow", - "aya", - "bytemuck", - "bytemuck_derive", - "bytes", - "cortexbrain-common", - "k8s-openapi", - "kube", - "libc", - "nix", - "tokio", - "tracing", - "tracing-subscriber", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -512,6 +488,17 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.15.0" @@ -603,12 +590,34 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -630,6 +639,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -822,6 +832,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ + "base64", "bytes", "futures-channel", "futures-core", @@ -829,7 +840,9 @@ dependencies = [ "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -861,6 +874,108 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.11.0" @@ -871,6 +986,22 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1019,6 +1150,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + [[package]] name = "lock_api" version = "0.4.13" @@ -1056,15 +1193,6 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -1088,19 +1216,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -1149,6 +1264,105 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.16", + "tracing", +] + +[[package]] +name = "opentelemetry-appender-tracing" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2" +dependencies = [ + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "opentelemetry-http" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry", + "reqwest", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" +dependencies = [ + "http", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "reqwest", + "thiserror 2.0.16", + "tokio", + "tonic", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", + "tonic-prost", +] + +[[package]] +name = "opentelemetry-stdout" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8887887e169414f637b18751487cce4e095be787d23fad13c454e2fb1b3811" +dependencies = [ + "chrono", + "opentelemetry", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand", + "thiserror 2.0.16", + "tokio", + "tokio-stream", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -1288,6 +1502,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -1396,6 +1628,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.3", +] + [[package]] name = "redox_syscall" version = "0.5.17" @@ -1445,6 +1706,40 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +[[package]] +name = "reqwest" +version = "0.12.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "ring" version = "0.17.14" @@ -1631,6 +1926,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -1701,6 +2008,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "strsim" version = "0.11.1" @@ -1729,6 +2042,20 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "tempfile" @@ -1792,6 +2119,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.49.0" @@ -1964,10 +2301,13 @@ dependencies = [ "base64", "bitflags", "bytes", + "futures-util", "http", "http-body", + "iri-string", "mime", "pin-project-lite", + "tower", "tower-layer", "tower-service", "tracing", @@ -2089,6 +2429,24 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -2158,6 +2516,19 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.104" @@ -2190,6 +2561,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "windows-core" version = "0.62.1" @@ -2426,8 +2807,111 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cfbcae0..a14b527 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -22,7 +22,7 @@ tonic = "0.14.2" tonic-reflection = "0.14.2" prost-types = "0.14.3" prost = "0.14.3" -cortexflow_agent_api = {version = "0.1.1",features = ["client"]} +cortexflow_agent_api = {path = "../core/api",features = ["client"]} kube = "2.0.1" k8s-openapi = {version = "0.26.0", features = ["v1_34"]} diff --git a/cli/src/install.rs b/cli/src/install.rs index bdb1ea1..105853c 100644 --- a/cli/src/install.rs +++ b/cli/src/install.rs @@ -2,8 +2,10 @@ use crate::errors::CliError; use crate::essential::{BASE_COMMAND, connect_to_client, create_config_file, create_configs}; use clap::{Args, Subcommand}; use colored::Colorize; -use kube::Error; +use k8s_openapi::api::core::v1::ConfigMap; use kube::core::ErrorResponse; +use kube::{Api, Client, Error}; +use std::thread::sleep; use std::{process::Command, thread, time::Duration}; // docs: @@ -38,6 +40,8 @@ pub enum InstallCommands { about = "Deploys a simple example contained in deploy-test-pod.yaml" )] TestPods, + #[command(name = "blocklist", about = "Install or Repair blocklist configmap")] + Blocklist, } //install args @@ -206,6 +210,84 @@ async fn install_simple_example_component() -> Result<(), CliError> { } } +// docs: +pub async fn install_blocklist_configmap() -> Result<(), CliError> { + match connect_to_client().await { + Ok(client) => { + println!( + "{} {}", + "=====>".blue().bold(), + "Checking if the Blocklist configmap exists" + ); + sleep(Duration::from_secs(1)); + let blocklist_exists = check_if_blocklist_exists(client).await?; + if !blocklist_exists { + println!( + "{} {}", + "=====>".blue().bold(), + "Blocklist configmap does not exist".red().bold() + ); + sleep(Duration::from_secs(1)); + println!("{} {}", "=====>".bold().blue(), "Creating configmap"); + let metdata_configs = create_configs(); + sleep(Duration::from_secs(1)); + match create_config_file(metdata_configs).await { + Ok(_) => { + println!( + "{} {}", + "=====>".bold().blue(), + "Configmap created/repaired successfully".bold().green() + ) + } + Err(e) => { + return Err(CliError::InstallerError { + reason: e.to_string(), + }); + } + } + return Ok(()); + } else { + println!() + } + + Ok(()) + } + Err(e) => { + return Err(CliError::ClientError(Error::Api(ErrorResponse { + status: "failed".to_string(), + message: "Failed to connect to kubernetes client".to_string(), + reason: e.to_string(), + code: 404, + }))); + } + } +} + +// docs: +async fn check_if_blocklist_exists(client: Client) -> Result { + let namespace = "cortexflow"; + let name = "cortexbrain-client-config"; + let api: Api = Api::namespaced(client, namespace); + match api.get(name).await { + Ok(_) => { + println!( + "{} {}", + "=====>".bold().blue(), + "Blocklist configmap exists".green().bold() + ); + Ok(true) + } + Err(_) => { + println!( + "{} {}", + "=====>".bold().blue(), + "Blocklist configmap doesn not exists".red().bold(), + ); + Ok(false) + } + } +} + //docs: // // This is an auxiliary function to help manage the cortexflow components during the installation diff --git a/cli/src/main.rs b/cli/src/main.rs index 0a5ac46..8d543cd 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -18,7 +18,7 @@ use crate::install::{InstallArgs, InstallCommands, install_cortexflow, install_s use crate::logs::{LogsArgs, logs_command}; use crate::monitoring::{ MonitorArgs, MonitorCommands, list_features, monitor_dropped_packets, monitor_identity_events, - monitor_latency_metrics, + monitor_latency_metrics, monitor_tracked_veth, }; use crate::policies::{ PoliciesArgs, PoliciesCommands, check_blocklist, create_blocklist, remove_ip, @@ -68,7 +68,7 @@ enum Commands { struct SetArgs { val: String, } - +//TODO: add command for monitoring veth interfaces async fn args_parser() -> Result<(), CliError> { let args = Cli::parse(); debug!("Arguments {:?}", args.cmd); @@ -80,6 +80,10 @@ async fn args_parser() -> Result<(), CliError> { InstallCommands::TestPods => { install_simple_example().await?; } + InstallCommands::Blocklist => { + //install or repair blocklist configmap + let _ = install::install_blocklist_configmap().await?; + } }, Some(Commands::Uninstall) => { uninstall().await?; @@ -120,6 +124,9 @@ async fn args_parser() -> Result<(), CliError> { MonitorCommands::Droppedpackets => { let _ = monitor_dropped_packets().await?; } + MonitorCommands::Veth => { + let _ = monitor_tracked_veth().await?; + } }, Some(Commands::Policies(policies_args)) => { match policies_args.policy_cmd { diff --git a/cli/src/monitoring.rs b/cli/src/monitoring.rs index b7cf3e2..72a94b8 100644 --- a/cli/src/monitoring.rs +++ b/cli/src/monitoring.rs @@ -8,7 +8,10 @@ use std::result::Result::Ok; use tonic_reflection::pb::v1::server_reflection_response::MessageResponse; use agent_api::client::{connect_to_client, connect_to_server_reflection}; -use agent_api::requests::{get_all_features, send_active_connection_request}; +use agent_api::requests::{ + get_all_features, send_active_connection_request, send_dropped_packets_request, + send_latency_metrics_request, send_tracked_veth_request, +}; use crate::errors::CliError; use clap::{Args, Subcommand}; @@ -33,6 +36,11 @@ pub enum MonitorCommands { about = "Monitor the dropped packets metrics detected by the metrics service" )] Droppedpackets, + #[command( + name = "veth", + about = "Monitor tracked veth interfaces from the identity service" + )] + Veth, } // cfcli monitor @@ -40,8 +48,6 @@ pub enum MonitorCommands { pub struct MonitorArgs { #[command(subcommand)] pub monitor_cmd: MonitorCommands, - //#[arg(long, short)] - //pub flags: Option, } pub async fn list_features() -> Result<(), CliError> { @@ -168,7 +174,7 @@ pub async fn monitor_latency_metrics() -> Result<(), CliError> { "Connected to CortexFlow Client".green() ); //send request to get latency metrics - match agent_api::requests::send_latency_metrics_request(client).await { + match send_latency_metrics_request(client).await { Ok(response) => { let resp = response.into_inner(); if resp.metrics.is_empty() { @@ -237,7 +243,7 @@ pub async fn monitor_dropped_packets() -> Result<(), CliError> { "Connected to CortexFlow Client".green() ); //send request to get dropped packets metrics - match agent_api::requests::send_dropped_packets_request(client).await { + match send_dropped_packets_request(client).await { Ok(response) => { let resp = response.into_inner(); if resp.metrics.is_empty() { @@ -291,6 +297,50 @@ pub async fn monitor_dropped_packets() -> Result<(), CliError> { Ok(()) } +pub async fn monitor_tracked_veth() -> Result<(), CliError> { + println!( + "{} {}", + "=====>".blue().bold(), + "Connecting to cortexflow Client".white() + ); + match connect_to_client().await { + Ok(client) => match send_tracked_veth_request(client).await { + Ok(response) => { + let veth_response = response.into_inner(); + if veth_response.tot_monitored_veth == 0 { + println!("{} {} ", "=====>".blue().bold(), "No tracked veth found"); + Ok(()) + } else { + println!( + "{} {} {} {} ", + "=====>".blue().bold(), + "Found:", + &veth_response.tot_monitored_veth, + "tracked veth" + ); + for veth in veth_response.veth_names.iter() { + println!("{} {}", "=====>".blue().bold(), &veth); + } + Ok(()) + } + } + Err(e) => { + return Err(CliError::AgentError( + tonic_reflection::server::Error::InvalidFileDescriptorSet(e.to_string()), + )); + } + }, + Err(e) => { + return Err(CliError::ClientError(kube::Error::Api(ErrorResponse { + status: "failed".to_string(), + message: "Failed to connect to kubernetes client".to_string(), + reason: e.to_string(), + code: 404, + }))); + } + } +} + fn convert_timestamp_to_date(timestamp: u64) -> String { DateTime::from_timestamp_micros(timestamp as i64) .map(|dt| dt.to_string()) diff --git a/core/Cargo.lock b/core/Cargo.lock index e980659..23ea751 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -275,9 +275,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "camino" @@ -407,19 +407,16 @@ version = "0.1.0" dependencies = [ "anyhow", "aya", + "bytemuck", + "bytemuck_derive", + "bytes", "k8s-openapi", "kube", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "cortexbrain-common" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5daea06747f06e000deaa52b7aceb504ddc309c061badf76e0b4b3d146ebf3a4" -dependencies = [ - "anyhow", + "opentelemetry", + "opentelemetry-appender-tracing", + "opentelemetry-otlp", + "opentelemetry-stdout", + "opentelemetry_sdk", "tracing", "tracing-subscriber", ] @@ -433,8 +430,7 @@ dependencies = [ "bytemuck", "bytemuck_derive", "chrono", - "cortexbrain-common 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cortexflow_identity 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cortexbrain-common", "prost", "tokio", "tokio-stream", @@ -451,39 +447,16 @@ dependencies = [ name = "cortexflow_identity" version = "0.1.1" dependencies = [ - "anyhow", - "aya", - "bytemuck", - "bytemuck_derive", - "bytes", - "cortexbrain-common 0.1.0", - "k8s-openapi", - "kube", - "nix", - "tokio", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "cortexflow_identity" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5725a802e4f494b5fab4c69b1455a32dd3804b52a58c665a7d751eeae93ddfca" -dependencies = [ - "anyhow", "aya", "bytemuck", "bytemuck_derive", "bytes", - "cortexbrain-common 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cortexbrain-common", "k8s-openapi", "kube", - "libc", "nix", "tokio", "tracing", - "tracing-subscriber", ] [[package]] @@ -544,6 +517,17 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.15.0" @@ -641,12 +625,34 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -668,6 +674,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -866,6 +873,7 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ + "base64", "bytes", "futures-channel", "futures-core", @@ -873,7 +881,9 @@ dependencies = [ "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -905,6 +915,108 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.12.0" @@ -915,6 +1027,22 @@ dependencies = [ "hashbrown 0.16.0", ] +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "itertools" version = "0.14.0" @@ -1047,6 +1175,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + [[package]] name = "lock_api" version = "0.4.14" @@ -1101,7 +1235,7 @@ dependencies = [ "aya-log", "bytemuck", "bytes", - "cortexbrain-common 0.1.0", + "cortexbrain-common", "libc", "nix", "tokio", @@ -1218,6 +1352,105 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.17", + "tracing", +] + +[[package]] +name = "opentelemetry-appender-tracing" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2" +dependencies = [ + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "opentelemetry-http" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry", + "reqwest", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" +dependencies = [ + "http", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "reqwest", + "thiserror 2.0.17", + "tokio", + "tonic", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", + "tonic-prost", +] + +[[package]] +name = "opentelemetry-stdout" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8887887e169414f637b18751487cce4e095be787d23fad13c454e2fb1b3811" +dependencies = [ + "chrono", + "opentelemetry", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand", + "thiserror 2.0.17", + "tokio", + "tokio-stream", +] + [[package]] name = "ordered-float" version = "2.10.1" @@ -1351,6 +1584,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -1471,6 +1722,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1509,6 +1789,40 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "reqwest" +version = "0.12.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "ring" version = "0.17.14" @@ -1705,6 +2019,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -1775,6 +2101,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "subtle" version = "2.6.1" @@ -1797,6 +2129,20 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "tempfile" @@ -1860,6 +2206,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.48.0" @@ -2032,10 +2388,13 @@ dependencies = [ "base64", "bitflags", "bytes", + "futures-util", "http", "http-body", + "iri-string", "mime", "pin-project-lite", + "tower", "tower-layer", "tower-service", "tracing", @@ -2157,6 +2516,24 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "valuable" version = "0.1.1" @@ -2206,6 +2583,19 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.105" @@ -2238,6 +2628,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "which" version = "7.0.3" @@ -2477,8 +2877,111 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/core/api/Cargo.toml b/core/api/Cargo.toml index 988ac46..3fd811d 100644 --- a/core/api/Cargo.toml +++ b/core/api/Cargo.toml @@ -3,7 +3,13 @@ name = "cortexflow_agent_api" version = "0.1.1" edition = "2024" description = "CortexFlow agent API" -authors = ["Lorenzo Tettamanti", "Pranav Verma", "Lorenzo Bradanini","Siddharth Sutar","Andrea Bozzo"] +authors = [ + "Lorenzo Tettamanti", + "Pranav Verma", + "Lorenzo Bradanini", + "Siddharth Sutar", + "Andrea Bozzo", +] documentation = "https://docs.cortexflow.org" homepage = "https://docs.cortexflow.org" repository = "https://github.com/CortexFlow/CortexBrain" @@ -23,14 +29,17 @@ tonic = "0.14.0" tonic-prost = "0.14.0" tracing = "0.1.41" aya = "0.13.1" -cortexbrain-common = "0.1.0" +cortexbrain-common = { path = "../common", features = [ + "map-handlers", + "kernel-structs", + "buffer-reader" +] } tonic-reflection = "0.14.0" tonic-build = "0.14.0" tracing-subscriber = "0.3.19" tokio-stream = "0.1.17" -bytemuck = {version ="1.23.0"} +bytemuck = { version = "1.23.0" } bytemuck_derive = "1.10.1" -cortexflow_identity = {version = "0.1.1", features = ["enums"]} chrono = "0.4.42" [build-dependencies] diff --git a/core/api/protos/agent.proto b/core/api/protos/agent.proto index 3cd236b..345ad40 100644 --- a/core/api/protos/agent.proto +++ b/core/api/protos/agent.proto @@ -68,6 +68,13 @@ message DroppedPacketsResponse { uint32 total_drops = 3; // Total drops across all connections } +// Veth Info + +message VethResponse{ + string status = 1; + repeated string veth_names = 2; // List of active veth interface names + int32 tot_monitored_veth = 3; +} //declare agent api service Agent{ @@ -81,11 +88,14 @@ service Agent{ // remove ip from blocklist endpoint rpc RmIpFromBlocklist(RmIpFromBlocklistRequest) returns (RmIpFromBlocklistResponse); - // metrics data + // metrics data endpoint rpc GetLatencyMetrics(google.protobuf.Empty) returns (LatencyMetricsResponse); - // dropped packets + // dropped packets endpoint rpc GetDroppedPacketsMetrics(google.protobuf.Empty) returns (DroppedPacketsResponse); + + // active veth info endpoint + rpc GetTrackedVeth(google.protobuf.Empty) returns (VethResponse); } message AddIpToBlocklistRequest{ diff --git a/core/api/src/agent.rs b/core/api/src/agent.rs index c6f5126..03b103d 100644 --- a/core/api/src/agent.rs +++ b/core/api/src/agent.rs @@ -121,6 +121,16 @@ pub struct DroppedPacketsResponse { pub total_drops: u32, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct VethResponse { + #[prost(string, tag = "1")] + pub status: ::prost::alloc::string::String, + /// List of active veth interface names + #[prost(string, repeated, tag = "2")] + pub veth_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(int32, tag = "3")] + pub tot_monitored_veth: i32, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct AddIpToBlocklistRequest { #[prost(string, optional, tag = "1")] pub ip: ::core::option::Option<::prost::alloc::string::String>, @@ -341,7 +351,7 @@ pub mod agent_client { .insert(GrpcMethod::new("agent.Agent", "RmIpFromBlocklist")); self.inner.unary(req, path, codec).await } - /// metrics data + /// metrics data endpoint pub async fn get_latency_metrics( &mut self, request: impl tonic::IntoRequest<()>, @@ -366,7 +376,7 @@ pub mod agent_client { .insert(GrpcMethod::new("agent.Agent", "GetLatencyMetrics")); self.inner.unary(req, path, codec).await } - /// dropped packets + /// dropped packets endpoint pub async fn get_dropped_packets_metrics( &mut self, request: impl tonic::IntoRequest<()>, @@ -391,6 +401,28 @@ pub mod agent_client { .insert(GrpcMethod::new("agent.Agent", "GetDroppedPacketsMetrics")); self.inner.unary(req, path, codec).await } + /// active veth info endpoint + pub async fn get_tracked_veth( + &mut self, + request: impl tonic::IntoRequest<()>, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/agent.Agent/GetTrackedVeth", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("agent.Agent", "GetTrackedVeth")); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -437,7 +469,7 @@ pub mod agent_server { tonic::Response, tonic::Status, >; - /// metrics data + /// metrics data endpoint async fn get_latency_metrics( &self, request: tonic::Request<()>, @@ -445,7 +477,7 @@ pub mod agent_server { tonic::Response, tonic::Status, >; - /// dropped packets + /// dropped packets endpoint async fn get_dropped_packets_metrics( &self, request: tonic::Request<()>, @@ -453,6 +485,11 @@ pub mod agent_server { tonic::Response, tonic::Status, >; + /// active veth info endpoint + async fn get_tracked_veth( + &self, + request: tonic::Request<()>, + ) -> std::result::Result, tonic::Status>; } /// declare agent api #[derive(Debug)] @@ -787,6 +824,46 @@ pub mod agent_server { }; Box::pin(fut) } + "/agent.Agent/GetTrackedVeth" => { + #[allow(non_camel_case_types)] + struct GetTrackedVethSvc(pub Arc); + impl tonic::server::UnaryService<()> + for GetTrackedVethSvc { + type Response = super::VethResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call(&mut self, request: tonic::Request<()>) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_tracked_veth(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetTrackedVethSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { let mut response = http::Response::new( diff --git a/core/api/src/api.rs b/core/api/src/api.rs index 27641b4..3d9ac32 100644 --- a/core/api/src/api.rs +++ b/core/api/src/api.rs @@ -1,12 +1,11 @@ #![allow(warnings)] use anyhow::Context; use chrono::Local; -use cortexbrain_common::{ - formatters::{format_ipv4, format_ipv6}, -}; +use cortexbrain_common::formatters::{format_ipv4, format_ipv6}; +use cortexbrain_common::map_handlers::load_perf_event_array_from_mapdata; use prost::bytes::BytesMut; -use std::{str::FromStr, sync::Arc}; use std::sync::Mutex; +use std::{str::FromStr, sync::Arc}; use tonic::{Request, Response, Status}; use tracing::info; @@ -22,26 +21,24 @@ use std::collections::HashMap; use tokio::sync::mpsc; use tokio::task; -use crate::{ - agent::{ - ConnectionEvent, DroppedPacketMetric, DroppedPacketsResponse, - LatencyMetric, LatencyMetricsResponse, - }, +use crate::agent::{ + ConnectionEvent, DroppedPacketMetric, DroppedPacketsResponse, LatencyMetric, + LatencyMetricsResponse, }; use crate::structs::{NetworkMetrics, PacketLog, TimeStampMetrics}; // * contains agent api configuration use crate::agent::{ - agent_server::Agent, ActiveConnectionResponse, AddIpToBlocklistRequest, BlocklistResponse, - RequestActiveConnections, RmIpFromBlocklistRequest, RmIpFromBlocklistResponse, + ActiveConnectionResponse, AddIpToBlocklistRequest, BlocklistResponse, RequestActiveConnections, + RmIpFromBlocklistRequest, RmIpFromBlocklistResponse, VethResponse, agent_server::Agent, }; use crate::constants::PIN_BLOCKLIST_MAP_PATH; use crate::helpers::comm_to_string; use aya::maps::Map; +use cortexbrain_common::buffer_type::IpProtocols; use cortexbrain_common::constants::BPF_PATH; -use cortexflow_identity::enums::IpProtocols; use std::net::Ipv4Addr; use tracing::warn; @@ -54,6 +51,8 @@ pub struct AgentApi { latency_metrics_tx: mpsc::Sender, Status>>, dropped_packet_metrics_rx: Mutex, Status>>>, dropped_packet_metrics_tx: mpsc::Sender, Status>>, + tracked_veth_rx: Mutex, Status>>>, + tracked_veth_tx: mpsc::Sender, Status>>, } //* Event sender trait. Takes an event from a map and send that to the mpsc channel @@ -94,6 +93,18 @@ pub trait EventSender: Send + Sync + 'static { let _ = tx.send(event).await; } + async fn send_tracked_veth_event(&self, event: Vec); + async fn send_tracked_veth_event_map( + &self, + map: Vec, + tx: mpsc::Sender, Status>>, + ) { + let status = Status::new(tonic::Code::Ok, "success"); + let event = Ok(map); + let _ = tx.send(event).await; + } + + // TODO: add the event sender for the tracked veth } // send event function. takes an HashMap and send that using mpsc event_tx @@ -113,39 +124,38 @@ impl EventSender for AgentApi { self.send_dropped_packet_metrics_event_map(event, self.dropped_packet_metrics_tx.clone()) .await; } + async fn send_tracked_veth_event(&self, event: Vec) { + self.send_tracked_veth_event_map(event, self.tracked_veth_tx.clone()) + .await; + } } //initialize a default trait for AgentApi. Loads a name and a bpf istance. //this trait is essential for init the Agent. impl Default for AgentApi { - //TODO:this part needs a better error handling fn default() -> Self { - // load connections maps mapdata - let active_connection_mapdata = MapData::from_pin("/sys/fs/bpf/maps/events_map") - .expect("cannot open events_map Mapdata"); - let active_connection_map = Map::PerfEventArray(active_connection_mapdata); //creates a PerfEventArray from the mapdata - - let mut active_connection_events_array = PerfEventArray::try_from(active_connection_map) - .expect("Error while initializing events array"); - - // load network metrics maps mapdata - let network_metrics_mapdata = MapData::from_pin("/sys/fs/bpf/trace_maps/net_metrics") - .expect("cannot open net_metrics Mapdata"); - let network_metrics_map = Map::PerfEventArray(network_metrics_mapdata); //creates a PerfEventArray from the mapdata - let mut network_metrics_events_array = PerfEventArray::try_from(network_metrics_map) - .expect("Error while initializing network metrics array"); - - // load time stamp events maps mapdata - let time_stamp_events_mapdata = MapData::from_pin("/sys/fs/bpf/trace_maps/time_stamp_events") - .expect("cannot open time_stamp_events Mapdata"); - let time_stamp_events_map = Map::PerfEventArray(time_stamp_events_mapdata); // - let mut time_stamp_events_array = PerfEventArray::try_from(time_stamp_events_map) - .expect("Error while initializing time stamp events array"); - - //init a mpsc channel + // + // init MapData from the kernel space + // + + // TODO: in the future will be better to not use .unwrap() + let mut active_connection_events_array = + load_perf_event_array_from_mapdata("/sys/fs/bpf/maps/events_map").unwrap(); + let mut network_metrics_events_array = + load_perf_event_array_from_mapdata("/sys/fs/bpf/trace_maps/net_metrics").unwrap(); + let mut time_stamp_events_array = + load_perf_event_array_from_mapdata("/sys/fs/bpf/trace_maps/time_stamp_events").unwrap(); + let mut tracked_veth_events_array = + load_perf_event_array_from_mapdata("/sys/fs/bpf/maps/tracked_veth_map").unwrap(); + + // + // init a mpsc channels with TX (transmission) and RX(Receiver) components + // + let (conn_tx, conn_rx) = mpsc::channel(1024); let (lat_tx, lat_rx) = mpsc::channel(2048); let (drop_tx, drop_rx) = mpsc::channel(2048); + let (tracked_veth_tx, tracked_veth_rx) = mpsc::channel(1024); let api = AgentApi { active_connection_event_rx: conn_rx.into(), @@ -154,6 +164,8 @@ impl Default for AgentApi { latency_metrics_tx: lat_tx.clone(), dropped_packet_metrics_rx: Mutex::new(drop_rx), dropped_packet_metrics_tx: drop_tx.clone(), + tracked_veth_rx: Mutex::new(tracked_veth_rx), + tracked_veth_tx: tracked_veth_tx.clone(), }; // For network metrics @@ -198,12 +210,7 @@ impl Default for AgentApi { Ok(proto) => { info!( "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{}", - event_id, - proto, - src, - src_port, - dst, - dst_port + event_id, proto, src, src_port, dst, dst_port ); info!("creating vector for the aggregated data"); let mut evt = Vec::new(); @@ -296,18 +303,18 @@ impl Default for AgentApi { if dropped_packet_metrics.sk_drops > 0 { let mut evt = Vec::new(); info!( - "Dropped Packet Metric - tgid: {}, process_name: {}, sk_drops: {}, sk_err: {}, sk_err_soft: {}, sk_backlog_len: {}, sk_wmem_queued: {}, sk_rcvbuf: {}, sk_ack_backlog: {}, timestamp_us: {}", - dropped_packet_metrics.tgid, - dropped_packet_metrics.process_name, - dropped_packet_metrics.sk_drops, - dropped_packet_metrics.sk_err, - dropped_packet_metrics.sk_err_soft, - dropped_packet_metrics.sk_backlog_len, - dropped_packet_metrics.sk_wmem_queued, - dropped_packet_metrics.sk_rcvbuf, - dropped_packet_metrics.sk_ack_backlog, - dropped_packet_metrics.timestamp_us - ); + "Dropped Packet Metric - tgid: {}, process_name: {}, sk_drops: {}, sk_err: {}, sk_err_soft: {}, sk_backlog_len: {}, sk_wmem_queued: {}, sk_rcvbuf: {}, sk_ack_backlog: {}, timestamp_us: {}", + dropped_packet_metrics.tgid, + dropped_packet_metrics.process_name, + dropped_packet_metrics.sk_drops, + dropped_packet_metrics.sk_err, + dropped_packet_metrics.sk_err_soft, + dropped_packet_metrics.sk_backlog_len, + dropped_packet_metrics.sk_wmem_queued, + dropped_packet_metrics.sk_rcvbuf, + dropped_packet_metrics.sk_ack_backlog, + dropped_packet_metrics.timestamp_us + ); evt.push(dropped_packet_metrics.clone()); let _ = drop_tx.send(Ok(evt)).await; } @@ -408,6 +415,8 @@ impl Default for AgentApi { } }); + // TODO: spawn a task to read the events from the maps and send the events using the EventSender trait + api } } @@ -659,4 +668,32 @@ impl Agent for AgentApi { Ok(Response::new(response)) } + + async fn get_tracked_veth( + &self, + request: Request<()>, + ) -> Result, Status> { + let req = request.into_inner(); + info!("Getting tracked veth metrics"); + let mut tracked_veth = Vec::::new(); + let mut tot_veth = 0 as i32; + + while let Ok(evt) = self.tracked_veth_rx.lock().unwrap().try_recv() { + if let Ok(vec) = evt { + tracked_veth.extend(vec); + } + } + tot_veth = tracked_veth.len() as i32; + + info!("Total tracked veth events: {}", tot_veth); + info!("Tracked veth: {:?}", &tracked_veth); + + let response = VethResponse { + status: "success".to_string(), + veth_names: tracked_veth, + tot_monitored_veth: tot_veth, + }; + + Ok(Response::new(response)) + } } diff --git a/core/api/src/client.rs b/core/api/src/client.rs index 844ea75..096b176 100644 --- a/core/api/src/client.rs +++ b/core/api/src/client.rs @@ -1,29 +1,23 @@ +use crate::agent::agent_client::AgentClient; use anyhow::Error; use std::result::Result::Ok; -use tonic::{transport::Channel}; -use tonic_reflection::pb::v1::{ - server_reflection_client::ServerReflectionClient, -}; -use crate::agent::agent_client::AgentClient; +use tonic::transport::Channel; +use tonic_reflection::pb::v1::server_reflection_client::ServerReflectionClient; -const AGENT_IP : &str = "http://127.0.0.1:9090"; +const AGENT_IP: &str = "http://127.0.0.1:9090"; -#[cfg(feature="client")] +#[cfg(feature = "client")] pub async fn connect_to_client() -> Result, Error> { //this methods force a HTTP/2 connection from a static string //FIXME: this will require an update to ensure a protected connection - let channel = Channel::from_static(AGENT_IP) - .connect() - .await?; + let channel = Channel::from_static(AGENT_IP).connect().await?; let client = AgentClient::new(channel); Ok(client) } -#[cfg(feature="client")] +#[cfg(feature = "client")] pub async fn connect_to_server_reflection() -> Result, Error> { //this methods force a HTTP/2 connection from a static string - let channel = Channel::from_static(AGENT_IP) - .connect() - .await?; + let channel = Channel::from_static(AGENT_IP).connect().await?; let client = ServerReflectionClient::new(channel); Ok(client) } diff --git a/core/api/src/requests.rs b/core/api/src/requests.rs index a518f4a..06a4030 100644 --- a/core/api/src/requests.rs +++ b/core/api/src/requests.rs @@ -1,26 +1,25 @@ use anyhow::Error; use std::result::Result::Ok; -use tonic::{ Request, Response, Streaming, transport::Channel }; +use tonic::{Request, Response, Streaming, transport::Channel}; use tonic_reflection::pb::v1::{ - ServerReflectionRequest, - ServerReflectionResponse, - server_reflection_client::ServerReflectionClient, - server_reflection_request::MessageRequest, + ServerReflectionRequest, ServerReflectionResponse, + server_reflection_client::ServerReflectionClient, server_reflection_request::MessageRequest, }; -use crate::agent::agent_client::AgentClient; use crate::agent::ActiveConnectionResponse; -use crate::agent::RequestActiveConnections; -use crate::agent::BlocklistResponse; use crate::agent::AddIpToBlocklistRequest; -use crate::agent::RmIpFromBlocklistRequest; -use crate::agent::RmIpFromBlocklistResponse; +use crate::agent::BlocklistResponse; use crate::agent::DroppedPacketsResponse; use crate::agent::LatencyMetricsResponse; +use crate::agent::RequestActiveConnections; +use crate::agent::RmIpFromBlocklistRequest; +use crate::agent::RmIpFromBlocklistResponse; +use crate::agent::VethResponse; +use crate::agent::agent_client::AgentClient; #[cfg(feature = "client")] pub async fn send_active_connection_request( - mut client: AgentClient + mut client: AgentClient, ) -> Result, Error> { let request = Request::new(RequestActiveConnections { pod_ip: None }); let response = client.active_connections(request).await?; @@ -29,13 +28,17 @@ pub async fn send_active_connection_request( #[cfg(feature = "client")] pub async fn get_all_features( - mut client: ServerReflectionClient + mut client: ServerReflectionClient, ) -> Result>, Error> { let request = ServerReflectionRequest { host: "".to_string(), - message_request: Some(MessageRequest::FileContainingSymbol("agent.Agent".to_string())), + message_request: Some(MessageRequest::FileContainingSymbol( + "agent.Agent".to_string(), + )), }; - let response = client.server_reflection_info(tokio_stream::iter(vec![request])).await?; + let response = client + .server_reflection_info(tokio_stream::iter(vec![request])) + .await?; Ok(response) } @@ -43,7 +46,7 @@ pub async fn get_all_features( #[cfg(feature = "client")] pub async fn send_create_blocklist_request( mut client: AgentClient, - ip: &str + ip: &str, ) -> Result, Error> { let ip = Some(ip.to_string()); let request = Request::new(AddIpToBlocklistRequest { ip }); @@ -53,7 +56,7 @@ pub async fn send_create_blocklist_request( #[cfg(feature = "client")] pub async fn send_check_blocklist_request( - mut client: AgentClient + mut client: AgentClient, ) -> Result, Error> { let request = Request::new(()); let response = client.check_blocklist(request).await?; @@ -63,7 +66,7 @@ pub async fn send_check_blocklist_request( #[cfg(feature = "client")] pub async fn remove_ip_from_blocklist_request( mut client: AgentClient, - ip: &str + ip: &str, ) -> Result, Error> { let ip = ip.to_string(); let request = Request::new(RmIpFromBlocklistRequest { ip }); @@ -76,9 +79,7 @@ pub async fn send_dropped_packets_request( mut client: AgentClient, ) -> Result, Error> { let request = Request::new(()); - let response = client.get_dropped_packets_metrics( - request - ).await?; + let response = client.get_dropped_packets_metrics(request).await?; Ok(response) } @@ -87,8 +88,15 @@ pub async fn send_latency_metrics_request( mut client: AgentClient, ) -> Result, Error> { let request = Request::new(()); - let response = client.get_latency_metrics( - request - ).await?; + let response = client.get_latency_metrics(request).await?; + Ok(response) +} + +#[cfg(feature = "client")] +pub async fn send_tracked_veth_request( + mut client: AgentClient, +) -> Result, Error> { + let request = Request::new(()); + let response = client.get_tracked_veth(request).await?; Ok(response) } diff --git a/core/common/Cargo.toml b/core/common/Cargo.toml index 854c04e..b8e840d 100644 --- a/core/common/Cargo.toml +++ b/core/common/Cargo.toml @@ -10,13 +10,24 @@ homepage = "https://docs.cortexflow.org" repository = "https://github.com/CortexFlow/CortexBrain" [dependencies] -tracing = "0.1" +tracing = { version = "0.1", features = ["std"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } anyhow = "1.0" kube = { version = "2.0.1", features = ["client"] } k8s-openapi = { version = "0.26.0", features = ["v1_34"] } aya = "0.13.1" +opentelemetry = "0.31.0" +opentelemetry_sdk = { version = "0.31.0", features = ["logs", "rt-tokio"] } +opentelemetry-stdout = { version = "0.31.0", features = ["logs"] } +opentelemetry-appender-tracing = "0.31.1" +opentelemetry-otlp = { version = "0.31.0", features = ["logs", "grpc-tonic"] } +bytemuck = "1.25.0" +bytes = "1.11.0" +bytemuck_derive = "1.10.2" [features] map-handlers = [] program-handlers = [] +network-structs = [] +buffer-reader = [] +experimental = [] diff --git a/core/common/src/buffer_type.rs b/core/common/src/buffer_type.rs new file mode 100644 index 0000000..2c25ada --- /dev/null +++ b/core/common/src/buffer_type.rs @@ -0,0 +1,325 @@ +use bytemuck_derive::Zeroable; +use bytes::BytesMut; +use std::net::Ipv4Addr; +use tracing::{error, info, warn}; + +// +// IpProtocols enum to reconstruct the packet protocol based on the +// IPV4 Header Protocol code +// + +#[derive(Debug)] +#[repr(u8)] +pub enum IpProtocols { + ICMP = 1, + TCP = 6, + UDP = 17, +} + +// +// TryFrom Trait implementation for IpProtocols enum +// This is used to reconstruct the packet protocol based on the +// IPV4 Header Protocol code +// + +impl TryFrom for IpProtocols { + type Error = (); + fn try_from(proto: u8) -> Result { + match proto { + 1 => Ok(IpProtocols::ICMP), + 6 => Ok(IpProtocols::TCP), + 17 => Ok(IpProtocols::UDP), + _ => Err(()), + } + } +} + +// +// Structure PacketLog +//This structure is used to store the packet information +// +#[cfg(feature = "network-structs")] +#[repr(C)] +#[derive(Clone, Copy, Zeroable)] +pub struct PacketLog { + pub proto: u8, + pub src_ip: u32, + pub src_port: u16, + pub dst_ip: u32, + pub dst_port: u16, + pub pid: u32, +} +#[cfg(feature = "network-structs")] +unsafe impl aya::Pod for PacketLog {} + +#[cfg(feature = "network-structs")] +#[repr(C)] +#[derive(Clone, Copy)] +pub struct VethLog { + pub name: [u8; 16], // 16 bytes: veth interface name + pub state: u64, // 8 bytes: state variable (unsigned long in kernel) + pub dev_addr: [u32; 8], // 32 bytes: device address + pub event_type: u8, // 1 byte: 1 for veth creation, 2 for veth destruction + pub netns: u32, // 4 bytes: network namespace inode number + pub pid: u32, // 4 bytes: PID that triggered the event +} + +#[cfg(feature = "network-structs")] +#[repr(C)] +#[derive(Clone, Copy)] +pub struct TcpPacketRegistry { + pub proto: u8, + pub src_ip: u32, + pub dst_ip: u32, + pub src_port: u16, + pub dst_port: u16, + pub pid: u32, + pub command: [u8; 16], + pub cgroup_id: u64, +} + +// docs: +// This function perform a byte swap from little-endian to big-endian +// It's used to reconstruct the correct IPv4 address from the u32 representation +// +// Takes a u32 address in big-endian format and returns a Ipv4Addr with reversed octets +// +#[inline(always)] +pub fn reverse_be_addr(addr: u32) -> Ipv4Addr { + let octects = addr.to_be_bytes(); + let [a, b, c, d] = [octects[3], octects[2], octects[1], octects[0]]; + let reversed_ip = Ipv4Addr::new(a, b, c, d); + reversed_ip +} + + +// enum BuffersType +#[cfg(feature = "buffer-reader")] +pub enum BufferType { + PacketLog, + TcpPacketRegistry, + VethLog, +} + +// IDEA: this is an experimental implementation to centralize buffer reading logic +// TODO: add variant for cortexflow API exporter +#[cfg(feature = "buffer-reader")] +impl BufferType { + pub async fn read_packet_log(buffers: &mut [BytesMut], tot_events: i32, offset: i32) { + for i in offset..tot_events { + let vec_bytes = &buffers[i as usize]; + if vec_bytes.len() < std::mem::size_of::() { + error!( + "Corrupted data. Readed {:?} bytes expected {} bytes", + vec_bytes, + std::mem::size_of::() + ) + } + if vec_bytes.len() >= std::mem::size_of::() { + let pl: PacketLog = + unsafe { std::ptr::read_unaligned(vec_bytes.as_ptr() as *const _) }; // reading raw bytes + + // extracting struct info from bytes + let src_ip = reverse_be_addr(pl.src_ip); + let dst_ip = reverse_be_addr(pl.dst_ip); + let src_port = u16::from_be(pl.src_port); + let dst_port = u16::from_be(pl.dst_port); + let event_id = pl.pid; + let protocol = pl.proto; + + // protocol extraction + match IpProtocols::try_from(protocol) { + Ok(proto) => { + info!( + "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{}", + event_id, proto, src_ip, src_port, dst_ip, dst_port + ); + } + Err(e) => { + error!("Unknown protocol. Data maybe corrupted. Reason:{:?}", e); + } + } + } + } + } + pub async fn read_tcp_registry_log(buffers: &mut [BytesMut], tot_events: i32, offset: i32) { + for i in offset..tot_events { + let vec_bytes = &buffers[i as usize]; + if vec_bytes.len() < std::mem::size_of::() { + error!( + "Corrupted data. Readed {:?} bytes expected {} bytes", + vec_bytes, + std::mem::size_of::() + ) + } + if vec_bytes.len() >= std::mem::size_of::() { + let pl: TcpPacketRegistry = + unsafe { std::ptr::read_unaligned(vec_bytes.as_ptr() as *const _) }; // reading raw bytes + + // extracting struct info from bytes + let src = reverse_be_addr(pl.src_ip); + let dst = reverse_be_addr(pl.dst_ip); + let src_port = u16::from_be(pl.src_port); + let dst_port = u16::from_be(pl.dst_port); + let event_id = pl.pid; + let command = pl.command.to_vec(); + let end = command + .iter() + .position(|&x| x == 0) + .unwrap_or(command.len()); + let command_str = String::from_utf8_lossy(&command[..end]).to_string(); + let cgroup_id = pl.cgroup_id; + let protocol = pl.proto; + + // protocol extraction + match IpProtocols::try_from(protocol) { + Ok(proto) => { + info!( + "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{} Command: {} Cgroup_id: {}", + event_id, + proto, + src, + src_port, + dst, + dst_port, + command_str, + cgroup_id //proc_content + ); + } + Err(e) => { + error!("Unknown protocol. Data maybe corrupted. Reason:{:?}", e); + } + } + } + } + } + pub async fn read_and_handle_veth_log( + //link_ids: Arc>>, + //bpf: Arc>, + buffers: &mut [BytesMut], + tot_events: i32, + offset: i32, + ) { + for i in offset..tot_events { + let vec_bytes = &buffers[i as usize]; + if vec_bytes.len() < std::mem::size_of::() { + error!( + "Corrupted data. Readed {:?} bytes expected {} bytes", + vec_bytes, + std::mem::size_of::() + ) + } + if vec_bytes.len() >= std::mem::size_of::() { + let pl: VethLog = + unsafe { std::ptr::read_unaligned(vec_bytes.as_ptr() as *const _) }; // reading raw bytes + + // extracting struct info from bytes + let name_bytes = pl.name; + + let dev_addr_bytes = pl.dev_addr; + let name = std::str::from_utf8(&name_bytes); + let state = pl.state; + + let dev_addr = dev_addr_bytes; + let netns = pl.netns; + let mut event_type = String::new(); + + // event_type extraction + match pl.event_type { + 1 => { + event_type = "creation".to_string(); + match name { + Ok(veth_name) => { + info!( + "[{}] Veth Event: Type: {} Name: {} Dev_addr: {:x?} State: {}", + netns, + event_type, + veth_name.trim_end_matches("\0"), + dev_addr, + state + ); + // TODO: this logic needs to live in a separate space + // FIXME: consider to update this logic to reduce the overhead. + //match attach_detach_veth( + // bpf.clone(), + // 1, + // veth_name, + // link_ids.clone(), + //) + //.await + //{ + // Ok(_) => { + // info!( + // "[{}] Successfully attached Attach/Detach function for veth: {}", + // netns, + // veth_name.trim_end_matches("\0") + // ); + // } + // Err(e) => { + // info!( + // "[{}] Error attaching Attach/Detach function. Error : {}", + // netns, e + // ); + // } + //} + } + Err(e) => { + error!( + "Failed to extract veth name during event_type = creation (1).Reason:{}", + e + ); + } + } + } + 2 => { + event_type = "deletion".to_string(); + match name { + Ok(veth_name) => { + info!( + "[{}] Veth Event: Type: {} Name: {} Dev_addr: {:x?} State: {}", + netns, + event_type, + veth_name.trim_end_matches("\0"), + dev_addr, + state + ); + // TODO: this logic needs to live in a separate space + //match attach_detach_veth( + // bpf.clone(), + // 2, + // veth_name, + // link_ids.clone(), + //) + //.await + //{ + // Ok(_) => { + // info!( + // "[{}] Successfully attached Attach/Detach function for veth: {}", + // netns, + // veth_name.trim_end_matches("\0") + // ); + // } + // Err(e) => { + // info!( + // "[{}] Error attaching Attach/Detach function. Error : {}", + // netns, e + // ); + // } + // } + } + Err(e) => { + error!( + "Failed to extract veth name during event_type = deletion (2).Reason:{}", + e + ); + } + } + } + _ => { + warn!("Unknown event type") + } + } + } + } + } +} diff --git a/core/common/src/lib.rs b/core/common/src/lib.rs index 1d015a2..9623afd 100644 --- a/core/common/src/lib.rs +++ b/core/common/src/lib.rs @@ -1,7 +1,10 @@ +#[cfg(feature = "buffer-reader")] +#[cfg(feature = "kernel-structs")] +pub mod buffer_type; pub mod constants; pub mod formatters; pub mod logger; #[cfg(feature = "map-handlers")] pub mod map_handlers; #[cfg(feature = "program-handlers")] -pub mod program_handlers; \ No newline at end of file +pub mod program_handlers; diff --git a/core/common/src/logger.rs b/core/common/src/logger.rs index 5a1b890..ab06f79 100644 --- a/core/common/src/logger.rs +++ b/core/common/src/logger.rs @@ -1,4 +1,7 @@ -use tracing_subscriber::{fmt::format::FmtSpan, EnvFilter}; +use tracing_subscriber::Layer; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan}; /// Initialize the default logger configuration used across CortexBrain components. /// @@ -35,3 +38,47 @@ pub fn init_logger_without_time() { .with_line_number(false) .init(); } + +use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge; +use opentelemetry_otlp::{LogExporter, WithExportConfig}; +use opentelemetry_sdk::Resource; +use opentelemetry_sdk::logs::SdkLoggerProvider; + +pub fn otlp_logger_init(service_name: String) -> SdkLoggerProvider { + //exporter and provider initialization + let otlp_endpoint = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT") + .unwrap_or_else(|_| "http://localhost:4317".to_string()); + + let exporter = LogExporter::builder() + .with_tonic() + .with_endpoint(otlp_endpoint) + .build() + .expect("Failed to create OTLP exporter"); + + //needs a service name + let provider = SdkLoggerProvider::builder() + .with_resource(Resource::builder().with_service_name(service_name).build()) + .with_batch_exporter(exporter) + .build(); + + //maybe we will need some filter later + //init otel_filter and layer + let otel_layer = OpenTelemetryTracingBridge::new(&provider); + + // init fmt filter and layer + let fmt_filter = EnvFilter::new("info").add_directive("opentelemetry=debug".parse().unwrap()); + let fmt_layer = tracing_subscriber::fmt::layer() + .with_thread_names(true) + .with_line_number(false) + .with_target(false) + .pretty() + .with_filter(fmt_filter); + + //init tracing subscriber with otel layer + tracing_subscriber::registry() + .with(otel_layer) + .with(fmt_layer) + .init(); + + provider +} diff --git a/core/common/src/map_handlers.rs b/core/common/src/map_handlers.rs index 2e22736..fc2ef8d 100644 --- a/core/common/src/map_handlers.rs +++ b/core/common/src/map_handlers.rs @@ -87,15 +87,22 @@ pub fn map_pinner(maps: BpfMapsData, path: &PathBuf) -> Result, Error> } #[cfg(feature = "map-handlers")] -pub async fn populate_blocklist(map: &mut Map) -> Result<(), Error> { +pub async fn populate_blocklist() -> Result<(), Error> { + use aya::maps::MapData; + // load mapdata from path + + let mapdata = MapData::from_pin("/sys/fs/bpf/maps/Blocklist") + .map_err(|e| anyhow::anyhow!("Failed to load blocklist_map: {}", e))?; + + let map = Map::HashMap(mapdata); + let mut blocklist_map = HashMap::<_, [u8; 4], [u8; 4]>::try_from(map)?; + let client = Client::try_default() .await .expect("Cannot connect to Kubernetes Client"); let namespace = "cortexflow"; let configmap = "cortexbrain-client-config"; - let mut blocklist_map = HashMap::<_, [u8; 4], [u8; 4]>::try_from(map)?; - let api: Api = Api::namespaced(client, namespace); match api.get(configmap).await { std::result::Result::Ok(configs) => { @@ -124,3 +131,21 @@ pub async fn populate_blocklist(map: &mut Map) -> Result<(), Error> { } } } + +#[cfg(feature = "map-handlers")] +pub fn load_perf_event_array_from_mapdata( + path: &'static str, +) -> Result, Error> { + use aya::maps::MapData; + use aya::maps::PerfEventArray; + + let map_data = MapData::from_pin(path) + .map_err(|e| anyhow::anyhow!("Cannot load mapdata from pin {:?} .Reason: {}", &path, e))?; + + let map = Map::PerfEventArray(map_data); + + let perf_event_array = PerfEventArray::try_from(map).map_err(|e| { + anyhow::anyhow!("Cannot initialize perf_event_array from map. Reason: {}", e) + })?; + Ok(perf_event_array) +} diff --git a/core/src/components/conntracker/src/data_structures.rs b/core/src/components/conntracker/src/data_structures.rs index 4de05cc..41a9552 100644 --- a/core/src/components/conntracker/src/data_structures.rs +++ b/core/src/components/conntracker/src/data_structures.rs @@ -50,17 +50,18 @@ pub struct ConnArray { // #[repr(C)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub struct VethLog { - pub name: [u8; 16], - pub state: u64, // state var type: long unsigned int - pub dev_addr: [u32; 8], - pub event_type: u8, // i choose 1 for veth creation or 2 for veth destruction - pub netns: u32, - pub pid: u32 - + pub name: [u8; 16], // 16 bytes: veth interface name + pub state: u64, // 8 bytes: state variable (unsigned long in kernel) + pub dev_addr: [u32; 8], // 32 bytes: device address + pub event_type: u8, // 1 byte: 1 for veth creation, 2 for veth destruction + pub netns: u32, // 4 bytes: network namespace inode number + pub pid: u32, // 4 bytes: PID that triggered the event + // padding automatically added by Rust for alignment } + // TODO: write documentation about this structure #[repr(C)] #[derive(Clone,Copy,Debug)] @@ -103,7 +104,7 @@ pub static mut CONNTRACKER: LruPerCpuHashMap = #[map(name = "veth_identity_map")] pub static mut VETH_EVENTS: PerfEventArray = PerfEventArray::new(0); -#[map(name = "Blocklist")] +#[map(name = "Blocklist", pinning = "by_name")] pub static mut BLOCKLIST: HashMap<[u8;4], [u8;4]> = HashMap::<[u8;4], [u8;4]>::with_max_entries(1024, 0); //here i need to pass an address like this: [135,171,168,192] diff --git a/core/src/components/conntracker/src/veth_tracer.rs b/core/src/components/conntracker/src/veth_tracer.rs index e2f07e7..146b66d 100644 --- a/core/src/components/conntracker/src/veth_tracer.rs +++ b/core/src/components/conntracker/src/veth_tracer.rs @@ -35,7 +35,7 @@ pub fn try_veth_tracer(ctx: ProbeContext, mode: u8) -> Result { // state field let state_offset = 168; - let state: u8 = read_linux_inner_value::(net_device_pointer as *const u8, state_offset)?; + let state: u64 = read_linux_inner_value::(net_device_pointer as *const u8, state_offset)?; // dev_addr let dev_addr_offset = 1080; @@ -52,7 +52,7 @@ pub fn try_veth_tracer(ctx: ProbeContext, mode: u8) -> Result { // compose the structure let veth_data = VethLog { name: name_buf, - state: state.into(), + state: state, dev_addr: dev_addr_buf, event_type: mode, netns: inum, diff --git a/core/src/components/identity/Cargo.toml b/core/src/components/identity/Cargo.toml index f5bdb37..bb55412 100644 --- a/core/src/components/identity/Cargo.toml +++ b/core/src/components/identity/Cargo.toml @@ -15,7 +15,6 @@ struct = [] enums = [] experimental = ["struct", "enums"] - [dependencies] aya = "0.13.1" bytes = "1.4" @@ -27,12 +26,15 @@ tokio = { version = "1.48.0", features = [ "time", "macros", ] } -anyhow = "1.0" tracing = "0.1.41" -tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } bytemuck = { version = "1.23.0", features = ["derive"] } -bytemuck_derive = "1.10.1" -cortexbrain-common = { path = "../../../common/", features = ["map-handlers","program-handlers"] } +cortexbrain-common = { path = "../../../common/", features = [ + "map-handlers", + "program-handlers", + "network-structs", + "buffer-reader", +] } nix = { version = "0.30.1", features = ["net"] } kube = { version = "2.0.1", features = ["client"] } k8s-openapi = { version = "0.26.0", features = ["v1_34"] } +bytemuck_derive = "1.10.2" diff --git a/core/src/components/identity/src/enums.rs b/core/src/components/identity/src/enums.rs deleted file mode 100644 index b0b271b..0000000 --- a/core/src/components/identity/src/enums.rs +++ /dev/null @@ -1,12 +0,0 @@ -/* - * IpProtocols enum to reconstruct the packet protocol based on the - * IPV4 Header Protocol code - */ -#[cfg(feature="enums")] -#[derive(Debug)] -#[repr(u8)] -pub enum IpProtocols { - ICMP = 1, - TCP = 6, - UDP = 17, -} \ No newline at end of file diff --git a/core/src/components/identity/src/helpers.rs b/core/src/components/identity/src/helpers.rs index 9512789..6439e61 100644 --- a/core/src/components/identity/src/helpers.rs +++ b/core/src/components/identity/src/helpers.rs @@ -1,129 +1,64 @@ -#![allow(warnings)] -use crate::enums::IpProtocols; use crate::structs::{PacketLog, TcpPacketRegistry, VethLog}; -use anyhow::Error; +use cortexbrain_common::buffer_type::{reverse_be_addr,IpProtocols}; + +use aya::Ebpf; use aya::programs::tc::SchedClassifierLinkId; use aya::{ - Bpf, maps::{MapData, perf::PerfEventArrayBuffer}, programs::{SchedClassifier, TcAttachType}, }; use bytes::BytesMut; -use k8s_openapi::api::core::v1::Pod; -use kube::api::ObjectList; -use kube::{Api, Client}; use nix::net::if_::if_nameindex; -use std::collections::HashMap; -use std::fs; -use std::result::Result::Ok; -use std::sync::Mutex; use std::{ - borrow::BorrowMut, - net::Ipv4Addr, - sync::{ - Arc, - atomic::{AtomicBool, Ordering}, - }, + borrow::BorrowMut, collections::HashMap, net::Ipv4Addr, result::Result::Ok, sync::Arc, + sync::Mutex, }; -use tokio::time; -use tracing::{debug, error, info, warn}; +use tracing::{debug, error, event, info, span, warn}; /* - * TryFrom Trait implementation for IpProtocols enum - * This is used to reconstruct the packet protocol based on the - * IPV4 Header Protocol code - */ - -impl TryFrom for IpProtocols { - type Error = (); - fn try_from(proto: u8) -> Result { - match proto { - 1 => Ok(IpProtocols::ICMP), - 6 => Ok(IpProtocols::TCP), - 17 => Ok(IpProtocols::UDP), - _ => Err(()), - } - } -} - -/* helper functions to read and log net events in the container */ -pub async fn display_events>( - mut perf_buffers: Vec>, - //running: Arc, - mut buffers: Vec, -) { - // FIXME: here maybe we need to use a loop with tokio::select - while true { - for buf in perf_buffers.iter_mut() { - match buf.read_events(&mut buffers) { - std::result::Result::Ok(events) => { - for i in 0..events.read { - let data = &buffers[i]; - if data.len() >= std::mem::size_of::() { - let pl: PacketLog = - unsafe { std::ptr::read(data.as_ptr() as *const _) }; - let src = reverse_be_addr(pl.src_ip); - let dst = reverse_be_addr(pl.dst_ip); - let src_port = u16::from_be(pl.src_port); - let dst_port = u16::from_be(pl.dst_port); - let event_id = pl.pid; - - match IpProtocols::try_from(pl.proto) { - std::result::Result::Ok(proto) => { - info!( - "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{}", - event_id, proto, src, src_port, dst, dst_port - ); - } - Err(_) => { - info!( - "Event Id: {} Protocol: Unknown ({})", - event_id, pl.proto - ); - } - }; - } else { - warn!("Received packet data too small: {} bytes", data.len()); - } - } - } - Err(e) => { - error!("Error reading events: {:?}", e); - } - } - } - tokio::time::sleep(std::time::Duration::from_millis(100)).await; - } -} - -pub fn reverse_be_addr(addr: u32) -> Ipv4Addr { - let mut octects = addr.to_be_bytes(); - let [a, b, c, d] = [octects[3], octects[2], octects[1], octects[0]]; - let reversed_ip = Ipv4Addr::new(a, b, c, d); - reversed_ip -} - pub async fn display_veth_events>( - bpf: Arc>, + bpf: Arc>, mut perf_buffers: Vec>, - //running: Arc, mut buffers: Vec, - mut link_ids: Arc>>, + link_ids: Arc>>, ) { // FIXME: here maybe we need to use a loop with tokio::select - while true { + loop { for buf in perf_buffers.iter_mut() { match buf.read_events(&mut buffers) { std::result::Result::Ok(events) => { - for i in 0..events.read { + // debug: log the readed events + if events.read > 0 { + debug!("Read {} veth events", events.read); + } + // debug: log the lost events + if events.lost > 0 { + debug!("Lost {} veth events", events.lost); + } + let offset = 0 as usize; + for i in offset..events.read { let data = &buffers[i]; + let veth_events_span = span!(tracing::Level::INFO, "corrupted_veth_events"); + // error: data is smaller that the vethlog structure + let _enter = veth_events_span.enter(); + if data.len() < std::mem::size_of::() { + warn!( + "Corrupted data. data_len = {} data_ptr = {}. Min size required: {} bytes", + data.len(), + data.as_ptr() as usize, + std::mem::size_of::() + ); + continue; + } + // correct size: data is logged correctly if data.len() >= std::mem::size_of::() { let vethlog: VethLog = - unsafe { std::ptr::read(data.as_ptr() as *const _) }; + unsafe { std::ptr::read_unaligned(data.as_ptr() as *const _) }; + //TODO: can this pattern be safe instead of using unsafe? let name_bytes = vethlog.name; - let dev_addr_bytes = vethlog.dev_addr.to_vec(); + let dev_addr_bytes = vethlog.dev_addr; let name = std::str::from_utf8(&name_bytes); let state = vethlog.state; @@ -141,13 +76,16 @@ pub async fn display_veth_events>( } match name { std::result::Result::Ok(veth_name) => { - info!( - "[{}] Triggered action: register_netdevice event_type:{:?} Manipulated veth: {:?} state:{:?} dev_addr:{:?}", + let veth_events_span = span!(tracing::Level::INFO, "veth_event", veth_name = %veth_name.trim_end_matches("\0"), event_type = %event_type.as_str()); + let _enter = veth_events_span.enter(); + event!( + tracing::Level::INFO, + "[{}] Veth Event: Type: {} Name: {} Dev_addr: {:x?} State: {}", netns, event_type, - veth_name.trim_end_matches("\0").to_string(), - state, - dev_addr + veth_name.trim_end_matches("\0"), + dev_addr, + state ); match attach_detach_veth( bpf.clone(), @@ -158,18 +96,33 @@ pub async fn display_veth_events>( .await { std::result::Result::Ok(_) => { - info!("Attach/Detach veth function attached correctly"); + event!( + tracing::Level::INFO, + "[{}] Successfully attached Attach/Detach function for veth: {}", + netns, + veth_name.trim_end_matches("\0") + ); + } + Err(e) => { + let failed_veth_events_span = span!(tracing::Level::ERROR, "failed_veth_event_attach_detach", veth_name = %veth_name.trim_end_matches("\0")); + let _enter = failed_veth_events_span.enter(); + event!( + tracing::Level::ERROR, + "[{}] Error attaching Attach/Detach function. Error : {}", + netns, + e + ) } - Err(e) => error!( - "Error attaching Attach/Detach function. Error : {}", - e - ), } } - Err(_) => info!("Unknown name or corrupted field"), + Err(e) => { + event!( + tracing::Level::WARN, + "Corrupted veth name field. Error: {:?}", + e + ); + } } - } else { - warn!("Corrupted data"); } } } @@ -182,12 +135,21 @@ pub async fn display_veth_events>( } } + */ +// docs: +// This function checks if the given interface name is in the list of ignored interfaces +// Takes a interface name (iface) as &str and returns true if the interface should be ignored +// Typically we want to ignore eth0,docker0,tunl0,lo interfaces because they are not relevant for the internal monitoring +// pub fn ignore_iface(iface: &str) -> bool { let ignored_interfaces = ["eth0", "docker0", "tunl0", "lo"]; ignored_interfaces.contains(&iface) } -//filter the interfaces,exclude docker0,eth0,lo interfaces +// docs: +// This function retrieves the list of veth interfaces on the system, filtering out ignored interfaces with +// the ignore_iface function. +// pub fn get_veth_channels() -> Vec { //filter interfaces and save the output in the let mut interfaces: Vec = Vec::new(); @@ -205,9 +167,9 @@ pub fn get_veth_channels() -> Vec { interfaces } - +/* async fn attach_detach_veth( - bpf: Arc>, + bpf: Arc>, event_type: u8, iface: &str, link_ids: Arc>>, @@ -218,7 +180,13 @@ async fn attach_detach_veth( ); match event_type { 1 => { - let mut bpf = bpf.lock().unwrap(); + // + // EVENT_TYPE 1: Attach the program to the veth inferfaces + // + + let mut bpf = bpf + .lock() + .map_err(|e| anyhow::anyhow!("Cannot get value from lock : {}", e))?; let program: &mut SchedClassifier = bpf .program_mut("identity_classifier") .ok_or_else(|| anyhow::anyhow!("program 'identity_classifier' not found"))? @@ -231,7 +199,9 @@ async fn attach_detach_veth( return Ok(()); } - let mut link_ids = link_ids.lock().unwrap(); + let mut link_ids = link_ids + .lock() + .map_err(|e| anyhow::anyhow!("Cannot get value from lock when attaching: {}", e))?; match program.attach(iface, TcAttachType::Ingress) { std::result::Result::Ok(link_id) => { info!( @@ -244,8 +214,14 @@ async fn attach_detach_veth( } } 2 => { + // + // EVENT_TYPE 2: Detach the program from the veth interfaces // INFO: Detaching occurs automatically when veth is deleted by kernel itself - let mut link_ids = link_ids.lock().unwrap(); + // + + let mut link_ids = link_ids + .lock() + .map_err(|e| anyhow::anyhow!("Cannot get value from lock when detaching: {}", e))?; match link_ids.remove(iface) { Some(_) => { info!("Successfully detached program from interface {}", iface); @@ -263,352 +239,286 @@ async fn attach_detach_veth( Ok(()) } -// CHECK THIS DIR: /sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice -/* helper functions to display events from the TcpPacketRegistry structure */ -pub async fn display_tcp_registry_events>( - mut perf_buffers: Vec>, - //running: Arc, - mut buffers: Vec, -) { - // FIXME: here maybe we need to use a loop with tokio::select - while true { - for buf in perf_buffers.iter_mut() { - match buf.read_events(&mut buffers) { - std::result::Result::Ok(events) => { - for i in 0..events.read { - let data = &buffers[i]; - if data.len() >= std::mem::size_of::() { - let tcp_pl: TcpPacketRegistry = - unsafe { std::ptr::read(data.as_ptr() as *const _) }; - let src = reverse_be_addr(tcp_pl.src_ip); - let dst = reverse_be_addr(tcp_pl.dst_ip); - let src_port = u16::from_be(tcp_pl.src_port); - let dst_port = u16::from_be(tcp_pl.dst_port); - let event_id = tcp_pl.pid; - let command = tcp_pl.command.to_vec(); - let end = command - .iter() - .position(|&x| x == 0) - .unwrap_or(command.len()); - let command_str = String::from_utf8_lossy(&command[..end]).to_string(); - let cgroup_id = tcp_pl.cgroup_id; + */ +// enum BuffersType +pub enum BufferType { + PacketLog, + TcpPacketRegistry, + VethLog, +} - match IpProtocols::try_from(tcp_pl.proto) { - std::result::Result::Ok(proto) => { - info!( - "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{} Command: {} Cgroup_id: {}", - event_id, - proto, - src, - src_port, - dst, - dst_port, - command_str, - cgroup_id //proc_content - ); - } - Err(_) => { - info!( - "Event Id: {} Protocol: Unknown ({})", - event_id, tcp_pl.proto - ); - } - }; - } else { - warn!("Received packet data too small: {} bytes", data.len()); - } +// TODO: add variant for OTEL log exporters +impl BufferType { + async fn read_packet_log(buffers: &mut [BytesMut], tot_events: i32, offset: i32) { + for i in offset..tot_events { + let vec_bytes = &buffers[i as usize]; + if vec_bytes.len() < std::mem::size_of::() { + error!( + "Corrupted data. Readed {:?} bytes expected {} bytes", + vec_bytes, + std::mem::size_of::() + ) + } + if vec_bytes.len() >= std::mem::size_of::() { + let pl: PacketLog = + unsafe { std::ptr::read_unaligned(vec_bytes.as_ptr() as *const _) }; // reading raw bytes + + // extracting struct info from bytes + let src_ip = reverse_be_addr(pl.src_ip); + let dst_ip = reverse_be_addr(pl.dst_ip); + let src_port = u16::from_be(pl.src_port); + let dst_port = u16::from_be(pl.dst_port); + let event_id = pl.pid; + let protocol = pl.proto; + + // protocol extraction + match IpProtocols::try_from(protocol) { + Ok(proto) => { + info!( + "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{}", + event_id, proto, src_ip, src_port, dst_ip, dst_port + ); + } + Err(e) => { + error!("Unknown protocol. Data maybe corrupted. Reason:{:?}", e); } - } - Err(e) => { - error!("Error reading events: {:?}", e); } } } - tokio::time::sleep(std::time::Duration::from_millis(100)).await; } -} - -#[cfg(feature = "experimental")] -pub async fn scan_cgroup_paths(path: String) -> Result, Error> { - let mut cgroup_paths: Vec = Vec::new(); - let default_path = "/sys/fs/cgroup/kubepods.slice".to_string(); - - let target_path = if fs::metadata(&path).is_err() { - error!("Using default path: {}", &default_path); - default_path - } else { - path - }; - let entries = match fs::read_dir(&target_path) { - Ok(entries) => entries, - Err(e) => { - error!( - "Error reading cgroup directory {:?}: {}", - &target_path.clone(), - e - ); - return Ok(cgroup_paths); + async fn read_tcp_registry_log(buffers: &mut [BytesMut], tot_events: i32, offset: i32) { + for i in offset..tot_events { + let vec_bytes = &buffers[i as usize]; + if vec_bytes.len() < std::mem::size_of::() { + error!( + "Corrupted data. Readed {:?} bytes expected {} bytes", + vec_bytes, + std::mem::size_of::() + ) + } + if vec_bytes.len() >= std::mem::size_of::() { + let pl: TcpPacketRegistry = + unsafe { std::ptr::read_unaligned(vec_bytes.as_ptr() as *const _) }; // reading raw bytes + + // extracting struct info from bytes + let src = reverse_be_addr(pl.src_ip); + let dst = reverse_be_addr(pl.dst_ip); + let src_port = u16::from_be(pl.src_port); + let dst_port = u16::from_be(pl.dst_port); + let event_id = pl.pid; + let command = pl.command.to_vec(); + let end = command + .iter() + .position(|&x| x == 0) + .unwrap_or(command.len()); + let command_str = String::from_utf8_lossy(&command[..end]).to_string(); + let cgroup_id = pl.cgroup_id; + let protocol = pl.proto; + + // protocol extraction + match IpProtocols::try_from(protocol) { + Ok(proto) => { + info!( + "Event Id: {} Protocol: {:?} SRC: {}:{} -> DST: {}:{} Command: {} Cgroup_id: {}", + event_id, + proto, + src, + src_port, + dst, + dst_port, + command_str, + cgroup_id //proc_content + ); + } + Err(e) => { + error!("Unknown protocol. Data maybe corrupted. Reason:{:?}", e); + } + } + } } - }; - for entry in entries { - if let Ok(entry) = entry { - let path = entry.path(); - if path.is_dir() { - if let Some(path_str) = path.to_str() { - cgroup_paths.push(path_str.to_string()); + } + async fn read_and_handle_veth_log( + //link_ids: Arc>>, + //bpf: Arc>, + buffers: &mut [BytesMut], + tot_events: i32, + offset: i32, + ) { + for i in offset..tot_events { + let vec_bytes = &buffers[i as usize]; + if vec_bytes.len() < std::mem::size_of::() { + error!( + "Corrupted data. Readed {:?} bytes expected {} bytes", + vec_bytes, + std::mem::size_of::() + ) + } + if vec_bytes.len() >= std::mem::size_of::() { + let pl: VethLog = + unsafe { std::ptr::read_unaligned(vec_bytes.as_ptr() as *const _) }; // reading raw bytes + + // extracting struct info from bytes + let name_bytes = pl.name; + + let dev_addr_bytes = pl.dev_addr; + let name = std::str::from_utf8(&name_bytes); + let state = pl.state; + + let dev_addr = dev_addr_bytes; + let netns = pl.netns; + let mut event_type = String::new(); + + // event_type extraction + match pl.event_type { + 1 => { + event_type = "creation".to_string(); + match name { + Ok(veth_name) => { + info!( + "[{}] Veth Event: Type: {} Name: {} Dev_addr: {:x?} State: {}", + netns, + event_type, + veth_name.trim_end_matches("\0"), + dev_addr, + state + ); + // TODO: this logic needs to live in a separate space + //match attach_detach_veth( + // bpf.clone(), + // 1, + // veth_name, + // link_ids.clone(), + //) + //.await + //{ + // Ok(_) => { + // info!( + // "[{}] Successfully attached Attach/Detach function for veth: {}", + // netns, + // veth_name.trim_end_matches("\0") + // ); + // } + // Err(e) => { + // info!( + // "[{}] Error attaching Attach/Detach function. Error : {}", + // netns, e + // ); + // } + //} + } + Err(e) => { + error!( + "Failed to extract veth name during event_type = creation (1).Reason:{}", + e + ); + } + } + } + 2 => { + event_type = "deletion".to_string(); + match name { + Ok(veth_name) => { + info!( + "[{}] Veth Event: Type: {} Name: {} Dev_addr: {:x?} State: {}", + netns, + event_type, + veth_name.trim_end_matches("\0"), + dev_addr, + state + ); + // TODO: this logic needs to live in a separate space + //match attach_detach_veth( + // bpf.clone(), + // 2, + // veth_name, + // link_ids.clone(), + //) + //.await + //{ + // Ok(_) => { + // info!( + // "[{}] Successfully attached Attach/Detach function for veth: {}", + // netns, + // veth_name.trim_end_matches("\0") + // ); + // } + // Err(e) => { + // info!( + // "[{}] Error attaching Attach/Detach function. Error : {}", + // netns, e + // ); + // } + // } + } + Err(e) => { + error!( + "Failed to extract veth name during event_type = deletion (2).Reason:{}", + e + ); + } + } + } + _ => { + warn!("Unknown event type") + } } } } } - - Ok(cgroup_paths) } -#[cfg(feature = "experimental")] -struct ServiceIdentity { - uid: String, - container_id: String, -} +// docs: read buffer function: +// template function that take a mut perf_event_array_buffer of type T and a mutable buffer of Vec -#[cfg(feature = "experimental")] -pub async fn scan_cgroup_cronjob(time_delta: u64) -> Result<(), Error> { - let interval = std::time::Duration::from_secs(time_delta); +pub async fn read_perf_buffer>( + //bpf: Arc>, // this is only for read_and_handle_veth_logs fn + //link_ids: Arc>>, // this is only for read_and_handle_veth_logs fn + mut array_buffers: Vec>, + mut buffers: Vec, + buffer_type: BufferType, +) { + // loop over the buffers loop { - let scanned_paths = scan_cgroup_paths("/sys/fs/cgroup/kubelet.slice".to_string()) - .await - .expect("An error occured during the cgroup scan"); - //--> this should return : - // /sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice - // /sys/fs/cgroup/kubelet.slice/kubelet.service - let mut scanned_subpaths = Vec::::new(); - for path in scanned_paths { - //info!("Scanned cgroup path: {}", path); - // scan the subgroups - let subpaths = scan_cgroup_paths(path.to_string()).await; - match subpaths { - Ok(paths) => { - for subpath in paths { - scanned_subpaths.push(subpath); + for buf in array_buffers.iter_mut() { + match buf.read_events(&mut buffers) { + Ok(events) => { + // triggered if some events are lost + if events.lost > 0 { + tracing::debug!("Lost events: {} ", events.lost); } - // ---> this should return the cgroups files and also : - // kubelet-kubepods-burstable.slice - // kubelet-kubepods-besteffort.slice - - // this directories needs to be scanned again to get further information about the pods - // for example: - // kubelet-kubepods-besteffort-pod088f8704_24f0_4636_a8e2_13f75646f370.slice - // where pod088f8704_24f0_4636_a8e2_13f75646f370 is the pod UID - } - Err(e) => { - error!("An error occured during the cgroup subpath scan: {}", e); - continue; - } - } - } - - let mut scanned_subpaths_v2 = Vec::::new(); - // second cgroup scan level to get the pod UIDs - for scanned_subpath in &scanned_subpaths { - let subpaths_v2 = scan_cgroup_paths(scanned_subpath.to_string()).await; - match subpaths_v2 { - Ok(paths) => { - for sub2 in paths { - info!("Debugging sub2: {}", &sub2); //return e.g. /sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podb8701d38_3791_422d_ad15_890ad1a0844b.slice/docker-f2e265659293676231ecb38fafccc97b1a42b75be192c32a602bc8ea579dc866.scope - scanned_subpaths_v2.push(sub2); - // this contains the addressed like this - //kubelet-kubepods-besteffort-pod088f8704_24f0_4636_a8e2_13f75646f370.slice + // triggered if some events are readed + if events.read > 0 { + tracing::debug!("Readed events: {}", events.read); + let offset = 0; + let tot_events = events.read as i32; + + //read the events in the buffer + match buffer_type { + BufferType::PacketLog => { + BufferType::read_packet_log(&mut buffers, tot_events, offset).await + } + BufferType::TcpPacketRegistry => { + BufferType::read_tcp_registry_log(&mut buffers, tot_events, offset) + .await + } + BufferType::VethLog => { + BufferType::read_and_handle_veth_log( + //link_ids.clone(), + //bpf.clone(), + &mut buffers, + tot_events, + offset, + ) + .await + } + } } } Err(e) => { - error!("An error occured during the cgroup subpath v2 scan: {}", e); - continue; + error!("Cannot read events from buffer. Reason: {} ", e); } } } - - let mut uids = Vec::::new(); - let mut identites = Vec::::new(); - - //read the subpaths to extract the pod uid - for subpath in scanned_subpaths_v2 { - let uid = extract_pod_uid(subpath.clone()) - .expect("An error occured during the extraction of pod UIDs"); - let container_id = extract_container_id(subpath.clone()) - .expect("An error occured during the extraction of the docker container id"); - debug!("Debugging extracted UID: {:?}", &uid); - // create a linked list for each service - let service_identity = ServiceIdentity { uid, container_id }; - identites.push(service_identity); //push the linked list in a vector of ServiceIdentity structure. Each struct contains the uid and the container id - } - - // get pod information from UID and store the info in an HashMqp for O(1) access - let service_map = get_pod_info().await?; - - //info!("Debugging Identites vector: {:?}", identites); - for service in identites { - let name = service_cache(service_map.clone(), service.uid.clone()); - let uid = service.uid; - let id = service.container_id; - info!( - "[Identity]: name: {:?} uid: {:?} docker container id {:?} ", - name, uid, id - ); - } - - info!( - "Cronjob completed a cgroup scan cycle. Next scan will be in {} seconds", - time_delta - ); - time::sleep(interval).await; - } -} -#[cfg(feature = "experimental")] -fn service_cache(service_map: HashMap, uid: String) -> String { - service_map.get(&uid).cloned().unwrap_or_else(|| { - error!("Service not found for uid: {}", uid); - "unknown".to_string() - }) -} -#[cfg(feature = "experimental")] -fn extract_container_id(cgroup_path: String) -> Result { - let splits: Vec<&str> = cgroup_path.split("/").collect(); - - let index = extract_target_from_splits(splits.clone(), "docker-")?; - let docker_id_split = splits[index] - .trim_start_matches("docker-") - .trim_end_matches(".scope"); - Ok(docker_id_split.to_string()) -} - -// IDEA: add cgroup docker process mapping in ServiceIdentity structure -#[cfg(feature = "experimental")] -fn extract_pod_uid(cgroup_path: String) -> Result { - // example of cgroup path: - // /sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod93580201_87d5_44e6_9779_f6153ca17637.slice - // or - // /sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-burstable.slice/kubelet-kubepods-burstable-poddd3a1c6b_af40_41b1_8e1c_9e31fe8d96cb.slice - - // split the path by "/" - let splits: Vec<&str> = cgroup_path.split("/").collect(); - debug!("Debugging splits: {:?}", &splits); - - let index = extract_target_from_splits(splits.clone(), "-pod")?; - - let pod_split = splits[index] - .trim_start_matches("kubelet-kubepods-besteffort-") - .trim_start_matches("kubelet-kubepods-burstable-") - .trim_start_matches("kubepods-besteffort-") - .trim_start_matches("kubepods-burstable-"); - - let uid_ = pod_split - .trim_start_matches("pod") - .trim_end_matches(".slice"); //return uids with underscore (_) [ex.dd3a1c6b_af40_41b1_8e1c_9e31fe8d96cb] - - let uid = uid_.replace("_", "-"); - Ok(uid.to_string()) -} -#[cfg(feature = "experimental")] -fn extract_target_from_splits(splits: Vec<&str>, target: &str) -> Result { - for (index, split) in splits.iter().enumerate() { - // find the split that contains the word 'pod' - if split.contains(target) { - debug!("Target index; {}", index); - return Ok(index); - } - } - Err(Error::msg("'-pod' word not found in split")) -} - -/* unfortunately you cannot query the pods using the uids directly from ListParams */ -#[cfg(feature = "experimental")] -async fn query_all_pods() -> Result, Error> { - let client = Client::try_default() - .await - .expect("Cannot connect to kubernetes client"); - let pods: Api = Api::all(client); - let lp = kube::api::ListParams::default(); // default list params - let pod_list = pods - .list(&lp) - .await - .expect("An error occured during the pod list extraction"); - - Ok(pod_list) -} - -// fast pod caching system -#[cfg(feature = "experimental")] -async fn get_pod_info() -> Result, Error> { - let all_pods = query_all_pods().await?; - - let mut service_map = HashMap::::new(); - - for pod in all_pods { - if let (Some(name), Some(uid)) = (pod.metadata.name, pod.metadata.uid) { - service_map.insert(uid, name); - } - } // insert the pod name and uid from the KubeAPI - - Ok(service_map) -} - -#[cfg(feature = "experimental")] -mod tests { - use tracing_subscriber::fmt::format; - - use crate::helpers::{extract_container_id, extract_pod_uid, extract_target_from_splits}; - - #[test] - fn extract_uid_from_string() { - let cgroup_paths = vec!["/sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string(), - "/sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string()]; - - let mut uid_vec = Vec::::new(); - - for cgroup_path in cgroup_paths { - let uid = extract_pod_uid(cgroup_path) - .map_err(|e| format!("An error occured {}", e)) - .unwrap(); - uid_vec.push(uid); - } - - let check = vec![ - "231bd2d7-0f09-4781-a4e1-e4ea026342dd".to_string(), - "231bd2d7-0f09-4781-a4e1-e4ea026342dd".to_string(), - ]; - - assert_eq!(uid_vec, check); - } - - #[test] - fn test_extract_target_index() { - let cgroup_paths = vec!["/sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string(), - "/sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string()]; - - let mut index_vec = Vec::::new(); - for cgroup_path in cgroup_paths { - let splits: Vec<&str> = cgroup_path.split("/").collect(); - - let target_index = extract_target_from_splits(splits, "-pod").unwrap(); - index_vec.push(target_index); - } - let index_check = vec![6, 7]; - assert_eq!(index_vec, index_check); - } - - #[test] - fn extract_docker_id() { - let cgroup_paths = vec!["/sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod17fd3f7c_37e4_4009_8c38_e58b30691af3.slice/docker-13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861.scope".to_string(), - "/sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod17fd3f7c_37e4_4009_8c38_e58b30691af3.slice/docker-13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861.scope".to_string()]; - - let mut id_vec = Vec::::new(); - for cgroup_path in cgroup_paths { - let id = extract_container_id(cgroup_path).unwrap(); - id_vec.push(id); - } - let id_check = vec![ - "13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861".to_string(), - "13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861".to_string(), - ]; - assert_eq!(id_vec, id_check); + tokio::time::sleep(std::time::Duration::from_millis(100)).await; // small sleep } } diff --git a/core/src/components/identity/src/lib.rs b/core/src/components/identity/src/lib.rs index 5413414..ceaedc2 100644 --- a/core/src/components/identity/src/lib.rs +++ b/core/src/components/identity/src/lib.rs @@ -1,3 +1,3 @@ pub mod helpers; -pub mod structs; -pub mod enums; \ No newline at end of file +#[cfg(feature = "experimental")] +pub mod service_discovery; \ No newline at end of file diff --git a/core/src/components/identity/src/main.rs b/core/src/components/identity/src/main.rs index 56f81d6..cf517f7 100644 --- a/core/src/components/identity/src/main.rs +++ b/core/src/components/identity/src/main.rs @@ -8,13 +8,10 @@ * */ -mod enums; mod helpers; -mod structs; +mod service_discovery; -use crate::helpers::{ - display_events, display_tcp_registry_events, display_veth_events, get_veth_channels, -}; +use crate::helpers::{get_veth_channels, read_perf_buffer}; use aya::{ Ebpf, maps::{Map, perf::PerfEventArray}, @@ -44,7 +41,8 @@ use std::collections::HashMap; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { //init tracing subscriber - logger::init_default_logger(); + //logger::init_default_logger(); + let otlp_provider = logger::otlp_logger_init("identity_service-OTLP".to_string()); info!("Starting identity service..."); info!("fetching data"); @@ -86,9 +84,9 @@ async fn main() -> Result<(), anyhow::Error> { info!("Found interfaces: {:?}", interfaces); - //{ FIXME: paused for testing the other features - // populate_blocklist(&mut maps.2).await?; - //} + { + populate_blocklist().await?; + } { init_tc_classifier(bpf.clone(), interfaces, link_ids.clone()).await.context( @@ -101,11 +99,9 @@ async fn main() -> Result<(), anyhow::Error> { )?; } - event_listener(maps, link_ids.clone(), bpf.clone()) - .await - .map_err(|e| { - anyhow::anyhow!("Error inizializing event_listener. Reason: {}", e) - })?; + event_listener(maps).await.map_err(|e| { + anyhow::anyhow!("Error inizializing event_listener. Reason: {}", e) + })?; } Err(e) => { error!("Error while pinning bpf_maps: {}", e); @@ -115,6 +111,7 @@ async fn main() -> Result<(), anyhow::Error> { Err(e) => { error!("Error while loading bpf maps {}", e); let _ = signal::ctrl_c().await; + let _ = otlp_provider.shutdown(); } } @@ -200,8 +197,8 @@ async fn init_tcp_registry(bpf: Arc>) -> Result<(), anyhow::Error> { // async fn event_listener( bpf_maps: Vec, - link_ids: Arc>>, - bpf: Arc>, + //link_ids: Arc>>, + //bpf: Arc>, ) -> Result<(), anyhow::Error> { info!("Preparing perf_buffers and perf_arrays"); @@ -248,24 +245,37 @@ async fn event_listener( .expect("Cannot create tcp_registry buffer"); // init output buffers - let veth_buffers = vec![BytesMut::with_capacity(1024); 10]; + let veth_buffers = vec![BytesMut::with_capacity(1024); online_cpus().iter().len()]; let events_buffers = vec![BytesMut::with_capacity(1024); online_cpus().iter().len()]; let tcp_buffers = vec![BytesMut::with_capacity(1024); online_cpus().iter().len()]; // init veth link ids - let veth_link_ids = link_ids; + //let veth_link_ids = link_ids; // spawn async tasks let veth_events_displayer = tokio::spawn(async move { - display_veth_events(bpf.clone(), perf_veth_buffer, veth_buffers, veth_link_ids).await; + //display_veth_events(bpf.clone(), perf_veth_buffer, veth_buffers, veth_link_ids).await; + read_perf_buffer(perf_veth_buffer, veth_buffers, helpers::BufferType::VethLog).await; }); let net_events_displayer = tokio::spawn(async move { - display_events(perf_net_events_buffer, events_buffers).await; + //display_events(perf_net_events_buffer, events_buffers).await; + read_perf_buffer( + perf_net_events_buffer, + events_buffers, + helpers::BufferType::PacketLog, + ) + .await; }); let tcp_registry_events_displayer: tokio::task::JoinHandle<()> = tokio::spawn(async move { - display_tcp_registry_events(tcp_registry_buffer, tcp_buffers).await; + //display_tcp_registry_events(tcp_registry_buffer, tcp_buffers).await; + read_perf_buffer( + tcp_registry_buffer, + tcp_buffers, + helpers::BufferType::TcpPacketRegistry, + ) + .await; }); #[cfg(feature = "experimental")] diff --git a/core/src/components/identity/src/mod.rs b/core/src/components/identity/src/mod.rs index 5413414..ceaedc2 100644 --- a/core/src/components/identity/src/mod.rs +++ b/core/src/components/identity/src/mod.rs @@ -1,3 +1,3 @@ pub mod helpers; -pub mod structs; -pub mod enums; \ No newline at end of file +#[cfg(feature = "experimental")] +pub mod service_discovery; \ No newline at end of file diff --git a/core/src/components/identity/src/service_discovery.rs b/core/src/components/identity/src/service_discovery.rs new file mode 100644 index 0000000..bc43f3d --- /dev/null +++ b/core/src/components/identity/src/service_discovery.rs @@ -0,0 +1,297 @@ +#[cfg(feature = "experimental")] +use anyhow::Error; +#[cfg(feature = "experimental")] +use k8s_openapi::api::core::v1::Pod; +#[cfg(feature = "experimental")] +use kube::api::ObjectList; +#[cfg(feature = "experimental")] +use kube::{Api, Client}; +#[cfg(feature = "experimental")] +use std::fs; +#[cfg(feature = "experimental")] +use tokio::time; + +#[cfg(feature = "experimental")] +pub async fn scan_cgroup_paths(path: String) -> Result, Error> { + let mut cgroup_paths: Vec = Vec::new(); + let default_path = "/sys/fs/cgroup/kubepods.slice".to_string(); + + let target_path = if fs::metadata(&path).is_err() { + error!("Using default path: {}", &default_path); + default_path + } else { + path + }; + let entries = match fs::read_dir(&target_path) { + Ok(entries) => entries, + Err(e) => { + error!( + "Error reading cgroup directory {:?}: {}", + &target_path.clone(), + e + ); + return Ok(cgroup_paths); + } + }; + for entry in entries { + if let Ok(entry) = entry { + let path = entry.path(); + if path.is_dir() { + if let Some(path_str) = path.to_str() { + cgroup_paths.push(path_str.to_string()); + } + } + } + } + + Ok(cgroup_paths) +} + +#[cfg(feature = "experimental")] +struct ServiceIdentity { + uid: String, + container_id: String, +} + +#[cfg(feature = "experimental")] +pub async fn scan_cgroup_cronjob(time_delta: u64) -> Result<(), Error> { + let interval = std::time::Duration::from_secs(time_delta); + loop { + let scanned_paths = scan_cgroup_paths("/sys/fs/cgroup/kubelet.slice".to_string()) + .await + .expect("An error occured during the cgroup scan"); + //--> this should return : + // /sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice + // /sys/fs/cgroup/kubelet.slice/kubelet.service + let mut scanned_subpaths = Vec::::new(); + for path in scanned_paths { + //info!("Scanned cgroup path: {}", path); + // scan the subgroups + let subpaths = scan_cgroup_paths(path.to_string()).await; + match subpaths { + Ok(paths) => { + for subpath in paths { + scanned_subpaths.push(subpath); + } + // ---> this should return the cgroups files and also : + // kubelet-kubepods-burstable.slice + // kubelet-kubepods-besteffort.slice + + // this directories needs to be scanned again to get further information about the pods + // for example: + // kubelet-kubepods-besteffort-pod088f8704_24f0_4636_a8e2_13f75646f370.slice + // where pod088f8704_24f0_4636_a8e2_13f75646f370 is the pod UID + } + Err(e) => { + error!("An error occured during the cgroup subpath scan: {}", e); + continue; + } + } + } + + let mut scanned_subpaths_v2 = Vec::::new(); + // second cgroup scan level to get the pod UIDs + for scanned_subpath in &scanned_subpaths { + let subpaths_v2 = scan_cgroup_paths(scanned_subpath.to_string()).await; + match subpaths_v2 { + Ok(paths) => { + for sub2 in paths { + info!("Debugging sub2: {}", &sub2); //return e.g. /sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podb8701d38_3791_422d_ad15_890ad1a0844b.slice/docker-f2e265659293676231ecb38fafccc97b1a42b75be192c32a602bc8ea579dc866.scope + scanned_subpaths_v2.push(sub2); + // this contains the addressed like this + //kubelet-kubepods-besteffort-pod088f8704_24f0_4636_a8e2_13f75646f370.slice + } + } + Err(e) => { + error!("An error occured during the cgroup subpath v2 scan: {}", e); + continue; + } + } + } + + let mut uids = Vec::::new(); + let mut identites = Vec::::new(); + + //read the subpaths to extract the pod uid + for subpath in scanned_subpaths_v2 { + let uid = extract_pod_uid(subpath.clone()) + .expect("An error occured during the extraction of pod UIDs"); + let container_id = extract_container_id(subpath.clone()) + .expect("An error occured during the extraction of the docker container id"); + debug!("Debugging extracted UID: {:?}", &uid); + // create a linked list for each service + let service_identity = ServiceIdentity { uid, container_id }; + identites.push(service_identity); //push the linked list in a vector of ServiceIdentity structure. Each struct contains the uid and the container id + } + + // get pod information from UID and store the info in an HashMqp for O(1) access + let service_map = get_pod_info().await?; + + //info!("Debugging Identites vector: {:?}", identites); + for service in identites { + let name = service_cache(service_map.clone(), service.uid.clone()); + let uid = service.uid; + let id = service.container_id; + info!( + "[Identity]: name: {:?} uid: {:?} docker container id {:?} ", + name, uid, id + ); + } + + info!( + "Cronjob completed a cgroup scan cycle. Next scan will be in {} seconds", + time_delta + ); + time::sleep(interval).await; + } +} +#[cfg(feature = "experimental")] +fn service_cache(service_map: HashMap, uid: String) -> String { + service_map.get(&uid).cloned().unwrap_or_else(|| { + error!("Service not found for uid: {}", uid); + "unknown".to_string() + }) +} +#[cfg(feature = "experimental")] +fn extract_container_id(cgroup_path: String) -> Result { + let splits: Vec<&str> = cgroup_path.split("/").collect(); + + let index = extract_target_from_splits(splits.clone(), "docker-")?; + let docker_id_split = splits[index] + .trim_start_matches("docker-") + .trim_end_matches(".scope"); + Ok(docker_id_split.to_string()) +} + +// IDEA: add cgroup docker process mapping in ServiceIdentity structure +#[cfg(feature = "experimental")] +fn extract_pod_uid(cgroup_path: String) -> Result { + // example of cgroup path: + // /sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod93580201_87d5_44e6_9779_f6153ca17637.slice + // or + // /sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-burstable.slice/kubelet-kubepods-burstable-poddd3a1c6b_af40_41b1_8e1c_9e31fe8d96cb.slice + + // split the path by "/" + let splits: Vec<&str> = cgroup_path.split("/").collect(); + debug!("Debugging splits: {:?}", &splits); + + let index = extract_target_from_splits(splits.clone(), "-pod")?; + + let pod_split = splits[index] + .trim_start_matches("kubelet-kubepods-besteffort-") + .trim_start_matches("kubelet-kubepods-burstable-") + .trim_start_matches("kubepods-besteffort-") + .trim_start_matches("kubepods-burstable-"); + + let uid_ = pod_split + .trim_start_matches("pod") + .trim_end_matches(".slice"); //return uids with underscore (_) [ex.dd3a1c6b_af40_41b1_8e1c_9e31fe8d96cb] + + let uid = uid_.replace("_", "-"); + Ok(uid.to_string()) +} +#[cfg(feature = "experimental")] +fn extract_target_from_splits(splits: Vec<&str>, target: &str) -> Result { + for (index, split) in splits.iter().enumerate() { + // find the split that contains the word 'pod' + if split.contains(target) { + debug!("Target index; {}", index); + return Ok(index); + } + } + Err(Error::msg("'-pod' word not found in split")) +} + +/* unfortunately you cannot query the pods using the uids directly from ListParams */ +#[cfg(feature = "experimental")] +async fn query_all_pods() -> Result, Error> { + let client = Client::try_default() + .await + .expect("Cannot connect to kubernetes client"); + let pods: Api = Api::all(client); + let lp = kube::api::ListParams::default(); // default list params + let pod_list = pods + .list(&lp) + .await + .expect("An error occured during the pod list extraction"); + + Ok(pod_list) +} + +// fast pod caching system +#[cfg(feature = "experimental")] +async fn get_pod_info() -> Result, Error> { + let all_pods = query_all_pods().await?; + + let mut service_map = HashMap::::new(); + + for pod in all_pods { + if let (Some(name), Some(uid)) = (pod.metadata.name, pod.metadata.uid) { + service_map.insert(uid, name); + } + } // insert the pod name and uid from the KubeAPI + + Ok(service_map) +} + +#[cfg(feature = "experimental")] +mod tests { + use tracing_subscriber::fmt::format; + + use crate::helpers::{extract_container_id, extract_pod_uid, extract_target_from_splits}; + + #[test] + fn extract_uid_from_string() { + let cgroup_paths = vec!["/sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string(), + "/sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string()]; + + let mut uid_vec = Vec::::new(); + + for cgroup_path in cgroup_paths { + let uid = extract_pod_uid(cgroup_path) + .map_err(|e| format!("An error occured {}", e)) + .unwrap(); + uid_vec.push(uid); + } + + let check = vec![ + "231bd2d7-0f09-4781-a4e1-e4ea026342dd".to_string(), + "231bd2d7-0f09-4781-a4e1-e4ea026342dd".to_string(), + ]; + + assert_eq!(uid_vec, check); + } + + #[test] + fn test_extract_target_index() { + let cgroup_paths = vec!["/sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string(), + "/sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod231bd2d7_0f09_4781_a4e1_e4ea026342dd.slice".to_string()]; + + let mut index_vec = Vec::::new(); + for cgroup_path in cgroup_paths { + let splits: Vec<&str> = cgroup_path.split("/").collect(); + + let target_index = extract_target_from_splits(splits, "-pod").unwrap(); + index_vec.push(target_index); + } + let index_check = vec![6, 7]; + assert_eq!(index_vec, index_check); + } + + #[test] + fn extract_docker_id() { + let cgroup_paths = vec!["/sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod17fd3f7c_37e4_4009_8c38_e58b30691af3.slice/docker-13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861.scope".to_string(), + "/sys/fs/cgroup/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod17fd3f7c_37e4_4009_8c38_e58b30691af3.slice/docker-13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861.scope".to_string()]; + + let mut id_vec = Vec::::new(); + for cgroup_path in cgroup_paths { + let id = extract_container_id(cgroup_path).unwrap(); + id_vec.push(id); + } + let id_check = vec![ + "13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861".to_string(), + "13abd64c0ba349975a762476c9703b642d18077eabeb3aa1d941132048afc861".to_string(), + ]; + assert_eq!(id_vec, id_check); + } +} diff --git a/core/src/components/identity/src/structs.rs b/core/src/components/identity/src/structs.rs deleted file mode 100644 index 7e2aa2b..0000000 --- a/core/src/components/identity/src/structs.rs +++ /dev/null @@ -1,56 +0,0 @@ -use bytemuck_derive::Zeroable; - -/* - * Structure PacketLog - * This structure is used to store the packet information - */ -#[repr(C)] -#[derive(Clone, Copy, Zeroable)] -pub struct PacketLog { - pub proto: u8, - pub src_ip: u32, - pub src_port: u16, - pub dst_ip: u32, - pub dst_port: u16, - pub pid: u32, -} -unsafe impl aya::Pod for PacketLog {} - -/* - * Connection Array that contains the hash_id associated with an active connection - */ -//#[repr(C)] -//#[derive(Clone, Copy, Zeroable)] -//pub struct ConnArray { -// pub src_ip: u32, -// pub dst_ip: u32, -// pub src_port: u16, -// pub dst_port: u16, -// pub proto: u8, -//} - -//unsafe impl aya::Pod for ConnArray {} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct VethLog { - pub name: [u8; 16], - pub state: u64, - pub dev_addr: [u32; 8], - pub event_type: u8, - pub netns: u32, - pub pid: u32, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct TcpPacketRegistry { - pub proto: u8, - pub src_ip: u32, - pub dst_ip: u32, - pub src_port: u16, - pub dst_port: u16, - pub pid: u32, - pub command: [u8; 16], - pub cgroup_id: u64, -} diff --git a/core/src/testing/identity.yaml b/core/src/testing/identity.yaml index 38bf197..3239f3e 100644 --- a/core/src/testing/identity.yaml +++ b/core/src/testing/identity.yaml @@ -28,7 +28,6 @@ spec: echo "checking permissions" ls -ld /sys/fs/bpf - volumeMounts: - name: bpf mountPath: /sys/fs/bpf @@ -53,7 +52,7 @@ spec: - SYS_PTRACE containers: - name: identity - image: lorenzotettamanti/cortexflow-identity:0.1.5-refcount9 + image: lorenzotettamanti/cortexflow-identity:0.1.5-otlp17 command: ["/bin/bash", "-c"] args: - | @@ -70,6 +69,16 @@ spec: echo "Running application..." exec /usr/local/bin/cortexflow-identity-service || echo "Application exited with code $?" + env: + - name: OTEL_SERVICE_NAME + value: cortexflow-identity + - name: OTEL_EXPORTER_OTLP_ENDPOINT + value: http://localhost:4317 + - name: OTEL_EXPORTER_OTLP_PROTOCOL + value: grpc + - name: OTEL_RESOURCE_ATTRIBUTES + value: service.namespace=cortexflow,service.version=0.1.5 + resources: limits: cpu: "1" diff --git a/core/src/testing/otel_agent.yaml b/core/src/testing/otel_agent.yaml new file mode 100644 index 0000000..71b7e08 --- /dev/null +++ b/core/src/testing/otel_agent.yaml @@ -0,0 +1,210 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: otel-agent-conf + namespace: cortexflow + labels: + app: opentelemetry + component: otel-agent-conf +data: + otel-agent-config: | + receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + + exporters: + otlp: + endpoint: otel-collector.cortexflow.svc.cluster.local:4317 + tls: + insecure: true + logging: + loglevel: info + + service: + pipelines: + traces: + receivers: [otlp] + exporters: [otlp, logging] + logs: + receivers: [otlp] + exporters: [otlp, logging] + +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: otel-agent + namespace: cortexflow + labels: + app: opentelemetry + component: otel-agent +spec: + selector: + matchLabels: + app: opentelemetry + component: otel-agent + template: + metadata: + labels: + app: opentelemetry + component: otel-agent + spec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + containers: + - name: otel-agent + image: otel/opentelemetry-collector:0.95.0 + command: + - "/otelcol" + - "--config=/conf/otel-agent-config.yaml" + resources: + limits: + cpu: 500m + memory: 500Mi + requests: + cpu: 100m + memory: 100Mi + ports: + - containerPort: 4317 + hostPort: 4317 + protocol: TCP + - containerPort: 4318 + hostPort: 4318 + protocol: TCP + env: + - name: GOMEMLIMIT + value: 400MiB + volumeMounts: + - name: otel-agent-config-vol + mountPath: /conf + volumes: + - name: otel-agent-config-vol + configMap: + name: otel-agent-conf + items: + - key: otel-agent-config + path: otel-agent-config.yaml + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: otel-collector-conf + namespace: cortexflow + labels: + app: opentelemetry + component: otel-collector-conf +data: + otel-collector-config: | + receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + + processors: + memory_limiter: + limit_mib: 1500 + spike_limit_mib: 512 + check_interval: 5s + + exporters: + # otlp: + # endpoint: otel-collector.cortexflow.svc.cluster.local:4317 + # tls: + # insecure: true + logging: {} + + service: + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter] + exporters: [logging] + logs: + receivers: [otlp] + processors: [memory_limiter] + exporters: [logging] + +--- +apiVersion: v1 +kind: Service +metadata: + name: otel-collector + namespace: cortexflow + labels: + app: opentelemetry + component: otel-collector +spec: + selector: + app: opentelemetry + component: otel-collector + ports: + - name: otlp-grpc + port: 4317 + targetPort: 4317 + - name: otlp-http + port: 4318 + targetPort: 4318 + - name: metrics + port: 8888 + targetPort: 8888 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: otel-collector + namespace: cortexflow + labels: + app: opentelemetry + component: otel-collector +spec: + replicas: 1 + selector: + matchLabels: + app: opentelemetry + component: otel-collector + template: + metadata: + labels: + app: opentelemetry + component: otel-collector + spec: + containers: + - name: otel-collector + image: otel/opentelemetry-collector:0.95.0 + command: + - "/otelcol" + - "--config=/conf/otel-collector-config.yaml" + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 200m + memory: 400Mi + ports: + - containerPort: 4317 + - containerPort: 4318 + - containerPort: 8888 + env: + - name: GOMEMLIMIT + value: 1600MiB + volumeMounts: + - name: otel-collector-config-vol + mountPath: /conf + volumes: + - name: otel-collector-config-vol + configMap: + name: otel-collector-conf + items: + - key: otel-collector-config + path: otel-collector-config.yaml \ No newline at end of file